/* ============================================================================
   Компоненты. Всё, что встречается больше чем на одном экране.

   Правило именования — БЭМ-подобное, без вложенности глубже одного уровня:
     .block            сам компонент
     .block__element   его часть
     .block--modifier  вариант
   Причина строгости: в прошлой версии классы назывались .crow, .titem, .cwi,
   .fs-fill — по имени невозможно было понять ни к чему относится правило, ни
   можно ли его трогать. Здесь имя компонента ищется поиском по проекту.
   ============================================================================ */

/* ================================================================= иконки
   Иконки — <svg><use href="/static/icons.svg#name"> из общего спрайта. Ни
   эмодзи, ни символов вроде «✕» в разметке: эмодзи рисуется шрифтом системы,
   выглядит по-разному на Windows и macOS и озвучивается скринридером как слово.

   currentColor — иконка всегда цвета своего текста, отдельно её красить не надо. */
.icon {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--sm { width: 14px; height: 14px; }
.icon--lg { width: 20px; height: 20px; }
.icon--xl { width: 24px; height: 24px; }
/* Иконка внутри строки текста: выравнивание по базовой линии, а не по центру
   блока — иначе она «всплывает» над строчными буквами. */
.icon--inline { vertical-align: -0.18em; display: inline-block; }

/* ================================================================== кнопки
   Иерархия строгая, и она отвечает на вопрос «что здесь главное»:
     primary — одно главное действие на экран. Двух primary не бывает.
     default — обычные действия, их может быть сколько угодно.
     ghost   — второстепенное, не отнимающее внимания у primary.
     soft-*  — действие, окрашенное смыслом (отправить, удалить).
   Разрушительное действие НИКОГДА не primary: одинаковый вид у «Отправить» и
   «Удалить» — это вопрос времени до случайного нажатия. */
.btn {
  --btn-height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: var(--btn-height);
  padding: 0 var(--space-5);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition:
    background-color var(--motion-fast) var(--ease-out),
    border-color var(--motion-fast) var(--ease-out),
    color var(--motion-fast) var(--ease-out);
}
.btn:hover {
  background: var(--bg-hover);
  border-color: var(--line-strong);
  color: var(--fg);
  text-decoration: none;
}
.btn:active { background: var(--bg-active); }

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-on);
  font-weight: var(--weight-semi);
}
.btn--primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--accent-on);
}

.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--fg-muted);
}
.btn--ghost:hover { background: var(--bg-hover); color: var(--fg); }

/* Мягкие варианты: смысл цветом, но без веса залитой кнопки. */
.btn--soft-accent { background: var(--accent-soft); border-color: transparent; color: var(--accent-fg); }
.btn--soft-accent:hover { background: var(--accent-softer); border-color: var(--accent); color: var(--accent-fg); }

.btn--soft-ok { background: var(--ok-soft); border-color: transparent; color: var(--ok-fg); }
.btn--soft-ok:hover { background: var(--ok-soft); border-color: var(--ok); color: var(--ok-fg); }

.btn--soft-danger { background: var(--danger-soft); border-color: transparent; color: var(--danger-fg); }
.btn--soft-danger:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger-fg); }

.btn--soft-info { background: var(--info-soft); border-color: transparent; color: var(--info-fg); }
.btn--soft-info:hover { background: var(--info-soft); border-color: var(--info); color: var(--info-fg); }

.btn--sm { --btn-height: 30px; padding: 0 var(--space-4); font-size: var(--text-xs); }
.btn--lg { --btn-height: 42px; padding: 0 var(--space-6); font-size: var(--text-md); }

/* Кнопка-иконка обязана нести aria-label: без подписи она немая для
   скринридера. Квадратная, чтобы иконка стояла по центру. */
.btn--icon {
  padding: 0;
  width: var(--btn-height);
  min-width: var(--btn-height);
}
.btn--block { width: 100%; }
/* Действие в правой панели: подпись слева, иконка прижата к правому краю. */
.btn--between { justify-content: space-between; }

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}

/* Пальцем в кнопку 30px не попасть. На сенсорных экранах поднимаем все размеры
   до 44px — порога, ниже которого промахи становятся систематическими. */
@media (pointer: coarse) {
  .btn { --btn-height: 44px; }
  .btn--sm { --btn-height: 44px; }
}

/* Кнопка, выглядящая ссылкой. Для третьестепенного в плотных местах — «Изменить»
   в ленте. Остаётся <button>, потому что действие, а не переход. */
.linkbtn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--accent-fg);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.linkbtn:hover { color: var(--accent-hover); text-decoration: underline; }
.linkbtn--danger { color: var(--danger-fg); }
.linkbtn--danger:hover { color: var(--danger); }

/* Индикатор ожидания на кнопке. htmx сам вешает .htmx-request на время
   запроса — отдельного скрипта для «идёт сохранение» не нужно. */
.spinner {
  width: 13px;
  height: 13px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; opacity: 0.5; }
}
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { display: inline-flex; }

/* ============================================================ метки состояния
   Пилюля отвечает на вопрос «в каком состоянии объект», а не украшает.
   Цвет всегда дублируется словом: показывать состояние ТОЛЬКО цветом нельзя —
   восемь процентов мужчин не различат зелёный и красный. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 2px var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--bg-hover);
  color: var(--fg-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  white-space: nowrap;
}
.pill--accent { background: var(--accent-soft); color: var(--accent-fg); }
.pill--ok     { background: var(--ok-soft); color: var(--ok-fg); }
.pill--warn   { background: var(--warn-soft); color: var(--warn-fg); }
.pill--danger { background: var(--danger-soft); color: var(--danger-fg); }
.pill--info   { background: var(--info-soft); color: var(--info-fg); }
.pill--lg { padding: var(--space-2) var(--space-4); font-size: var(--text-sm); }

/* Точка состояния перед подписью — помогает отличить пилюли одного тона
   в длинном списке, не считывая цвет фона. */
.pill__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* Счётчик у заголовка: «Лиды 2168». Не пилюля — это число, а не состояние. */
.counter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-full);
  background: var(--bg-hover);
  color: var(--fg-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
}
.counter--danger { background: var(--danger); color: var(--danger-on); }
.counter--accent { background: var(--accent-soft); color: var(--accent-fg); }

/* Тир скоринга: буква в квадрате. Ширина фиксирована, чтобы буквы стояли
   столбцом в списке. */
.tier {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}
.tier--lg { width: 40px; height: 40px; font-size: var(--text-xl); border-radius: var(--radius-lg); }
.tier--a { background: var(--ok-soft); color: var(--ok-fg); }
.tier--b { background: var(--accent-soft); color: var(--accent-fg); }
.tier--c { background: var(--warn-soft); color: var(--warn-fg); }
.tier--d { background: var(--bg-hover); color: var(--fg-muted); }
.tier--none { background: var(--bg-hover); color: var(--fg-muted); }

/* Чип-ссылка: сайт компании. Выделен, потому что по нему кликают, в отличие
   от соседних фактов. */
.chip-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 2px var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-fg);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  border: 1px solid transparent;
  /* Чип не переносится на вторую строку: в узкой колонке подпись усекается
     многоточием (span.u-truncate внутри site_chip), перенос ломал высоту строк. */
  white-space: nowrap;
  max-width: 100%;
}
.chip-link:hover { border-color: var(--accent); color: var(--accent-fg); }
/* Сайта нет — тот же слот ведёт в поиск. Приглушён, чтобы не выдавать себя
   за настоящий сайт компании. */
.chip-link--unknown { background: var(--bg-hover); color: var(--fg-muted); font-weight: var(--weight-normal); }
.chip-link--unknown:hover { border-color: var(--line-strong); color: var(--fg-soft); }

/* ================================================================== карточка */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  padding: var(--space-6);
}
.card--flush { padding: 0; overflow: hidden; }
.card--sunken { background: var(--bg-sunken); }
.card--danger { border-color: color-mix(in srgb, var(--danger) 35%, var(--line)); }

.card__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}
.card--flush .card__head {
  margin-bottom: 0;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--line);
}
.card__title {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-lg);
  font-weight: var(--weight-semi);
}
/* Всё после заголовка уезжает вправо: действия карточки живут в её шапке. */
.card__tools { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }
.card__hint {
  color: var(--fg-muted);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}
.card__foot {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* Карточка правой колонки — мельче и без лишнего веса: это справка,
   а не рабочая поверхность. */
.side-card {
  background: var(--bg-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.side-card__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
}
.side-card__head .icon { color: var(--fg-muted); }
.side-card__tools { margin-left: auto; }
/* Смысловая часть внутри карточки: отделена чертой, а не пустотой — иначе
   «публичные контакты» читаются как продолжение списка реквизитов. */
.side-card__part {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--space-3);
}

/* =========================================================== ключ → значение
   Блок «О компании»: подпись слева, значение справа. Сетка, а не флекс с
   отступами: значения обязаны стоять одним столбцом, иначе список читается
   как набор разрозненных строк. */
.facts { display: grid; gap: var(--space-4); }
.facts__row {
  display: grid;
  grid-template-columns: minmax(80px, 96px) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: baseline;
}
.facts__key {
  color: var(--fg-muted);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
}
.facts__value {
  font-size: var(--text-sm);
  color: var(--fg);
  min-width: 0;
  overflow-wrap: break-word;
}
.facts__value--empty { color: var(--fg-muted); }

/* Ряд фактов в строку — для шапок, где значения короткие. */
.factline {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  color: var(--fg-muted);
  font-size: var(--text-sm);
}
.factline__item { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }

/* ==================================================================== поля
   Подпись всегда видима и всегда над полем. Плейсхолдер вместо подписи не
   годится: он исчезает при вводе, и человек, отвлёкшийся на середине формы,
   уже не знает, что заполняет. */
.field { display: grid; gap: var(--space-2); min-width: 0; }
.field__label {
  color: var(--fg-soft);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}
.field__hint { color: var(--fg-muted); font-size: var(--text-xs); }
.field__error {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--danger-fg);
  font-size: var(--text-xs);
}
.field__row { display: flex; gap: var(--space-3); align-items: center; }
.field__row > * { min-width: 0; }

.input,
.select,
.textarea {
  width: 100%;
  min-height: 36px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  color: var(--fg);
  font-size: var(--text-sm);
  transition:
    border-color var(--motion-fast) var(--ease-out),
    box-shadow var(--motion-fast) var(--ease-out);
}
.input::placeholder,
.textarea::placeholder { color: var(--fg-muted); }

/* Кольцо на активном поле мягче общего фокус-кольца: поле и так обведено
   рамкой, двойная обводка выглядит поломкой. */
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.input:disabled,
.select:disabled,
.textarea:disabled,
.input[readonly],
.textarea[readonly] {
  background: var(--bg-sunken);
  color: var(--fg-muted);
  cursor: not-allowed;
}
.input--invalid { border-color: var(--danger); }

.textarea {
  resize: vertical;
  line-height: var(--leading-normal);
  min-height: 96px;
}

/* Своя стрелка у select: системная различается в трёх браузерах и ломает
   выравнивание правого края в ряду фильтров. */
.select {
  appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2364748B' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
  background-size: 14px;
  cursor: pointer;
}

/* Поле поиска с иконкой внутри. Иконка декоративная — поле подписано
   плейсхолдером и aria-label. */
.search { position: relative; display: flex; align-items: center; }
.search__icon {
  position: absolute;
  left: var(--space-4);
  color: var(--fg-muted);
  pointer-events: none;
}
.search .input { padding-left: var(--space-9); }
/* Клавиша в подсказке: «Enter — отправить». Обычный inline-элемент, поэтому
   годится и внутри строки текста. */
.kbd {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 1px var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-sunken);
  color: var(--fg-soft);
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  line-height: 1.5;
  white-space: nowrap;
}

/* Та же клавиша, но прижатая к правому краю поля поиска. Отдельным классом,
   потому что абсолютное позиционирование внутри строки текста делает подсказку
   невидимой — она уезжает к краю ближайшего позиционированного предка. */
.search__kbd {
  position: absolute;
  right: var(--space-3);
  pointer-events: none;
}

/* Флажок и переключатель: системные слишком мелкие и не красятся. */
.checkbox {
  appearance: none;
  width: 16px;
  height: 16px;
  flex: none;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  cursor: pointer;
  transition:
    background-color var(--motion-fast) var(--ease-out),
    border-color var(--motion-fast) var(--ease-out);
}
.checkbox:hover { border-color: var(--accent); }
.checkbox:checked,
.checkbox:indeterminate {
  background-color: var(--accent);
  border-color: var(--accent);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12px;
}
.checkbox:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E");
}
.checkbox:indeterminate {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='M4 8h8'/%3E%3C/svg%3E");
}

.radio-row { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.radio-row label { display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer; font-size: var(--text-sm); }

/* ==================================================================== табы
   Два вида, и они не взаимозаменяемы:
     .tabs        — разделы страницы, подчёркивание снизу;
     .segmented   — выбор одного из немногих равноправных (канал связи),
                    вид переключателя.  */
.tabs {
  display: flex;
  gap: var(--space-2);
  border-bottom: 1px solid var(--line);
}
.tabs__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-2);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--fg-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: color var(--motion-fast) var(--ease-out);
}
.tabs__item:hover { color: var(--fg); }
.tabs__item[aria-selected="true"] {
  color: var(--accent-fg);
  border-bottom-color: var(--accent);
}

.segmented {
  display: flex;
  gap: var(--space-3);
}
.segmented__item {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 40px;
  padding: 0 var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition:
    border-color var(--motion-fast) var(--ease-out),
    background-color var(--motion-fast) var(--ease-out);
}
.segmented__item:hover { border-color: var(--line-strong); background: var(--bg-hover); }
.segmented__item[aria-selected="true"] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent-fg);
  font-weight: var(--weight-semi);
}
/* Канал недоступен: показываем, но не даём выбрать — исчезнувший таб
   заставляет гадать, был ли он вообще. */
.segmented__item[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* ================================================================== таблица
   Плотная сетка на много строк. Заголовок прилипает к верху области
   прокрутки: на 25 строках подписи столбцов уезжают с экрана первыми. */
.table-wrap { overflow-x: auto; }
.table {
  width: 100%;
  font-size: var(--text-sm);
}
.table th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--space-4) var(--space-5);
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--line);
  color: var(--fg-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  text-align: left;
  white-space: nowrap;
}
.table td {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}
.table tbody tr { transition: background-color var(--motion-fast) var(--ease-out); }
.table tbody tr:hover { background: var(--bg-hover); }
.table tbody tr:last-child td { border-bottom: none; }
.table__num { text-align: right; }
.table__tight { width: 1%; white-space: nowrap; }

/* Минимальные ширины колонок.

   Без них браузер ужимает столбец под доступное место — и «Максим Волгин»
   превращается в «Мак…», а при десятке колонок и в восемь пикселей. Ячейка
   с именем не должна сжиматься: лучше горизонтальная прокрутка у таблицы
   (она в .table-wrap и для того и заведена), чем нечитаемые имена.

   Ширины подобраны под самое длинное реальное значение: ФИО из трёх слов
   и название компании с формой собственности. Компания уступила место
   объединённой графе «ЛПР / Контакты»: её имя может усечься многоточием,
   а ФИО ЛПР — нет (см. [data-col="lpr"] ниже). */
.table__col-company { min-width: 240px; }
.table__col-person { min-width: 260px; }
.table__col-owner { min-width: 160px; }
.table__col-plan { min-width: 150px; }

/* Выбранная строка: заливка И полоса слева. Только заливкой обошлись бы, но
   при десятке отмеченных строк полоса даёт увидеть выбор, не вчитываясь. */
.table tbody tr[aria-selected="true"] {
  background: var(--accent-soft);
  box-shadow: inset 3px 0 0 var(--accent);
}
.table tbody tr[aria-selected="true"]:hover { background: var(--accent-softer); }

/* Закреплённая заметка в строке таблицы. Приглушена, но с иконкой: её задача —
   попасться на глаза до звонка, а не соперничать с названием компании. */
.table__note {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: 2px var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-fg);
  font-size: var(--text-xs);
  max-width: 100%;
}
.table__note > span,
.table__note { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Сортируемый заголовок — кнопка, а не div с обработчиком: так он доступен
   с клавиатуры и озвучивается как элемент управления. */
.table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.table__sort:hover { color: var(--fg); }
.table__sort .icon { opacity: 0.45; }
.table__sort[aria-sort]:not([aria-sort="none"]) .icon { opacity: 1; color: var(--accent); }

/* Панель массовых действий над таблицей. Занимает место всегда, даже когда
   ничего не выбрано: появляющаяся полоса сдвигала бы таблицу под курсором. */
.bulkbar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--line);
  font-size: var(--text-sm);
  min-height: 52px;
}
.bulkbar__count { font-weight: var(--weight-semi); }
.bulkbar__tools { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); }

/* ============================================================== KPI-плитка */
.kpi {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
}
.kpi__body { min-width: 0; display: grid; gap: var(--space-1); }
.kpi__label { color: var(--fg-muted); font-size: var(--text-xs); }
.kpi__value {
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
}
.kpi__note { color: var(--fg-muted); font-size: var(--text-xs); }
.kpi__delta { display: inline-flex; align-items: center; gap: var(--space-1); font-weight: var(--weight-medium); }
.kpi__delta--up { color: var(--ok-fg); }
.kpi__delta--down { color: var(--danger-fg); }
/* Значок в мягком квадрате — как на макете. Прижат вправо. */
.kpi__icon {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border-radius: var(--radius-lg);
  background: var(--bg-hover);
  color: var(--fg-muted);
}
.kpi__icon--accent { background: var(--accent-soft); color: var(--accent); }
.kpi__icon--ok { background: var(--ok-soft); color: var(--ok); }
.kpi__icon--warn { background: var(--warn-soft); color: var(--warn); }
.kpi__icon--info { background: var(--info-soft); color: var(--info); }

/* ================================================================= степпер
   Вертикальные вехи сделки. Соединительная линия рисуется псевдоэлементом от
   кружка, а не отдельным блоком: так она не разъезжается при разной высоте
   подписей. У последнего шага линии нет. */
.stepper { display: grid; gap: 0; }
.step {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  gap: var(--space-4);
  padding-bottom: var(--space-5);
  position: relative;
}
.step:last-child { padding-bottom: 0; }
.step::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 24px;
  bottom: 0;
  width: 2px;
  background: var(--line);
}
.step:last-child::before { display: none; }
.step__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--bg-hover);
  color: var(--fg-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  position: relative;
  z-index: 1;
}
.step__label {
  align-self: center;
  font-size: var(--text-sm);
  color: var(--fg-muted);
}
.step__note { display: block; font-size: var(--text-xs); color: var(--fg-muted); }

.step--done .step__mark { background: var(--ok-soft); color: var(--ok-fg); }
.step--done::before { background: var(--ok); opacity: 0.35; }
.step--done .step__label { color: var(--fg-soft); }
.step--current .step__mark { background: var(--accent); color: var(--accent-on); }
.step--current .step__label { color: var(--fg); font-weight: var(--weight-semi); }

/* ================================================================== аватар */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-fg);
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  text-transform: uppercase;
  letter-spacing: 0;
}
.avatar--sm { width: 24px; height: 24px; font-size: var(--text-2xs); }
.avatar--lg { width: 40px; height: 40px; font-size: var(--text-sm); }

/* Человек: аватар + имя + роль. */
.person { display: inline-flex; align-items: center; gap: var(--space-3); min-width: 0; }
.person__body { min-width: 0; display: grid; }
.person__name { font-size: var(--text-sm); font-weight: var(--weight-medium); }
.person__role { font-size: var(--text-xs); color: var(--fg-muted); }

/* ================================================================= выноска
   Блок, объясняющий что-то рядом с работой: подсказка модели, предупреждение,
   ошибка. Всегда с иконкой — по ней тон читается раньше, чем текст. */
.callout {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}
.callout__icon { flex: none; margin-top: 2px; color: var(--fg-muted); }
.callout__body { min-width: 0; display: grid; gap: var(--space-2); }
.callout__title { font-weight: var(--weight-semi); }
.callout--accent { background: var(--accent-soft); border-color: transparent; color: var(--accent-fg); }
.callout--accent .callout__icon { color: var(--accent); }
.callout--ok { background: var(--ok-soft); border-color: transparent; color: var(--ok-fg); }
.callout--ok .callout__icon { color: var(--ok); }
.callout--warn { background: var(--warn-soft); border-color: transparent; color: var(--warn-fg); }
.callout--warn .callout__icon { color: var(--warn); }
.callout--danger { background: var(--danger-soft); border-color: transparent; color: var(--danger-fg); }
.callout--danger .callout__icon { color: var(--danger); }

/* ============================================================== пустой экран
   Пустота обязана говорить, ЧТО сделать, а не только что ничего нет.
   «Ничего не найдено» без следующего шага — тупик. */
.empty {
  display: grid;
  gap: var(--space-4);
  justify-items: start;
  padding: var(--space-8) var(--space-6);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-sunken);
}
.empty--center { justify-items: center; text-align: center; }
.empty__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-lg);
  background: var(--bg-hover);
  color: var(--fg-muted);
}
.empty__title { font-size: var(--text-md); font-weight: var(--weight-semi); }
.empty__text { color: var(--fg-muted); font-size: var(--text-sm); max-width: 62ch; }

/* ================================================================= раскрытие
   Справочное, что нужно не каждый раз: каталог продуктов, история касаний.
   Свёрнуто по умолчанию, но подписано так, чтобы было ясно, что внутри. */
.disclose { border-top: 1px solid var(--line); }
.disclose:first-child { border-top: none; }
.disclose > summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) 0;
  cursor: pointer;
  list-style: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--fg-soft);
}
.disclose > summary::-webkit-details-marker { display: none; }
.disclose > summary:hover { color: var(--fg); }
.disclose__chevron { transition: transform var(--motion-fast) var(--ease-out); color: var(--fg-muted); }
.disclose[open] .disclose__chevron { transform: rotate(90deg); }
.disclose__hint { margin-left: auto; color: var(--fg-muted); font-size: var(--text-xs); font-weight: var(--weight-normal); }
.disclose__body { padding-bottom: var(--space-5); }

/* ==================================================================== лента
   События по лиду: реплики людей и записи автоматики. Записи автоматики
   приглушены — их много, и они фон для человеческих. */
.feed { display: grid; gap: var(--space-2); list-style: none; }
.feed__item {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--line);
}
.feed__item:first-child { border-top: none; }
.feed__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-md);
  background: var(--bg-hover);
  color: var(--fg-muted);
}
.feed__icon--accent { background: var(--accent-soft); color: var(--accent); }
.feed__icon--ok { background: var(--ok-soft); color: var(--ok); }
.feed__body { min-width: 0; display: grid; gap: var(--space-2); }
.feed__head { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.feed__text { font-size: var(--text-sm); line-height: var(--leading-snug); white-space: pre-wrap; }
.feed__meta { margin-left: auto; display: flex; align-items: baseline; gap: var(--space-3); color: var(--fg-muted); font-size: var(--text-xs); }
.feed__at { font-variant-numeric: tabular-nums; white-space: nowrap; }
.feed__item--system .feed__text { color: var(--fg-muted); }
.feed__item--pinned { background: var(--accent-soft); border-radius: var(--radius-md); padding-inline: var(--space-4); }
.feed__actions { display: flex; gap: var(--space-4); flex-wrap: wrap; }

/* ================================================================ листалка */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-5);
}
.pager__page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
}
.pager__page:hover { background: var(--bg-hover); color: var(--fg); }
.pager__page[aria-current="page"] {
  background: var(--accent);
  color: var(--accent-on);
}
.pager__gap { color: var(--fg-muted); padding: 0 var(--space-2); }
.pager__side { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-sm); color: var(--fg-muted); }

/* ================================================================ сообщения
   Всплывающее сообщение о результате. Появляется только когда результат
   неочевиден по самому экрану: удачное сохранение видно по данным, а вот
   неудачу нужно сказать словами.
   aria-live на контейнере — иначе скринридер не заметит появления. */
.toast-host {
  position: fixed;
  left: 50%;
  bottom: var(--space-7);
  transform: translateX(-50%);
  z-index: var(--z-toast);
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--slate-900);
  color: var(--slate-50);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: toast-in var(--motion-base) var(--ease-out);
}
.toast--danger { background: var(--danger-700, #B91C1C); }
.toast__action {
  color: var(--blue-200);
  font-weight: var(--weight-semi);
  cursor: pointer;
  text-decoration: underline;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* =================================================================== меню
   Выпадающее меню на <details>: браузер сам держит открытость и закрытие по
   Esc, своей реализации не нужно. */
.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; }
.menu > summary::-webkit-details-marker { display: none; }
.menu__list {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-2));
  z-index: var(--z-drawer);
  min-width: 200px;
  padding: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  box-shadow: var(--shadow-lg);
  display: grid;
  gap: 1px;
}
.menu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  color: var(--fg-soft);
  font-size: var(--text-sm);
  text-align: left;
  cursor: pointer;
}
.menu__item:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.menu__item--danger { color: var(--danger-fg); }
.menu__item--danger:hover { background: var(--danger-soft); color: var(--danger-fg); }
.menu__sep { height: 1px; background: var(--line); margin: var(--space-2) 0; }

/* ================================================================= полоса
   Горизонтальный индикатор доли. Используется в воронке и в разрезе по тирам. */
.bar {
  position: relative;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--bg-hover);
  overflow: hidden;
}
.bar__fill {
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--accent);
  min-width: 2px;
  transition: width var(--motion-slow) var(--ease-out);
}
.bar--tall { height: 28px; border-radius: var(--radius-md); }
.bar--tall .bar__fill { border-radius: var(--radius-md); }
.bar__value {
  position: absolute;
  left: var(--space-4);
  top: 0;
  height: 100%;
  display: flex;
  align-items: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
}
.bar__fill--ok { background: var(--ok); }
.bar__fill--warn { background: var(--warn); }
.bar__fill--danger { background: var(--danger); }
.bar__fill--muted { background: var(--slate-400); }

/* ============================================================ живое обновление
   Блоки, которые дособирает воркер (см. js/live.js), и лента лида: подмена по
   htmx должна быть видна, но не назойлива. htmx на время settle вешает
   .htmx-added на вставленный элемент — стартуем из лёгкого сдвига
   с прозрачностью и приезжаем на место. Остальным подменам консоли (сетка
   календаря, панели списка) въезд не нужен — они происходят по клику человека,
   и внимание уже там. */
#panel-company, #panel-progress, #panel-lpr, #panel-channels, #panel-message,
[id^="feed-"] {
  transition:
    opacity var(--motion-slow) var(--ease-out),
    transform var(--motion-slow) var(--ease-out);
}
#panel-company.htmx-added, #panel-progress.htmx-added, #panel-lpr.htmx-added,
#panel-channels.htmx-added, #panel-message.htmx-added,
[id^="feed-"].htmx-added {
  opacity: 0;
  transform: translateY(6px);
}

/* Подпись, которую фоновый опрос только что переписал: короткая вспышка
   акцентным фоном говорит «здесь обновилось», не отбирая взгляд надолго.
   Вешается из js/live.js только на реально сменившийся текст. */
@keyframes live-flash {
  0% { background-color: color-mix(in srgb, var(--accent) 24%, transparent); }
  100% { background-color: transparent; }
}
.live-flash { animation: live-flash 1.4s var(--ease-out); }

/* ============================================================= подтверждение
   Маленький модальный вопрос поверх другого окна (несохранённые изменения
   в планировании). Высота и ширина явные по той же причине, что у .picker:
   fit-content у <dialog> с флекс-детьми в Safari считается ненадёжно. */
.confirm {
  width: min(440px, 92vw);
  padding: var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  color: var(--fg);
  box-shadow: var(--shadow-xl);
}
.confirm::backdrop {
  background: rgb(15 23 42 / 0.35);
  backdrop-filter: blur(1px);
}
.confirm__title {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: var(--weight-semi);
}
.confirm__icon { color: var(--warn); }
.confirm__text {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--fg-muted);
}
.confirm__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

/* ------------------------------------------------------- список лидов: ячейки
   Кликабельный значок приоритета, ячейка заметки и пометки контактов —
   строке списка нужны компактные варианты, не расталкивающие таблицу. */
.pill--btn { border: 0; cursor: pointer; font: inherit; font-size: var(--text-xs); }
.pill--btn:hover { filter: brightness(1.12); }
.pill--ghost { background: transparent; border: 1px dashed var(--line-strong); color: var(--fg-muted); }

/* Заметка: текст слева, кнопка «+» справа, окошко ввода — третьим рядом на всю
   ширину. Окошко раскрывается в потоке (строка подрастает), а не поверх
   таблицы: у таблицы своя прокрутка, и слой резался бы её краем снизу. */
.notecell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-2);
  align-items: start;
  min-width: 0;
  max-width: 260px;
}
.notecell__body { display: grid; gap: 2px; min-width: 0; }
.notecell__text {
  font-size: var(--text-xs);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.notecell__meta { font-size: var(--text-2xs); color: var(--fg-muted); }
/* Свой комментарий — кнопка в облике текста: нажатие открывает правку.
   Пунктир при наведении — единственная подсказка кликабельности, которую
   текст в две строки может себе позволить без визуального шума. */
.notecell__text--own {
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  color: inherit;
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}
.notecell__text--own:hover { text-decoration: underline dotted; color: var(--accent-fg); }
.notecell__add { border: 1px solid var(--line-strong); }
.notecell__panel {
  grid-column: 1 / -1;
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  min-width: 220px;
}
.notecell__panel[hidden] { display: none; }
.notecell__panel textarea { font-size: var(--text-xs); }
.notecell__panel-actions { display: flex; gap: var(--space-2); }

/* Объединённая графа «ЛПР / Контакты»: имя, контакты, кнопка поиска. */
.personcell { display: grid; gap: var(--space-1); min-width: 0; }
.personcell__name { display: block; font-weight: var(--weight-semi); }
.personcell__contacts { display: flex; align-items: flex-end; gap: var(--space-2); min-width: 0; }
.personcell__contacts .contactcell { flex: 1; min-width: 0; }
/* Кнопки поиска в ячейках — компактнее обычной btn--sm: это строка таблицы. */
.personcell__scan,
.sitecell__scan { --btn-height: 24px; color: var(--fg-muted); }
.personcell__scan[disabled],
.sitecell__scan[disabled] { cursor: progress; }
.personcell__note { font-size: var(--text-2xs); color: var(--fg-muted); }

/* Графа «Сайт»: чип и кнопка поиска в одну строку, итог запуска — строкой ниже.
   Обёртка чипа блочная: пометка «справочник» из site_chip встаёт под ссылку,
   inline-flex выталкивал её вбок поверх колонки «Этап». */
.sitecell { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); min-width: 0; }
.sitecell__chip { display: block; min-width: 0; max-width: 100%; }
.sitecell__note { flex-basis: 100%; font-size: var(--text-2xs); color: var(--fg-muted); }

.contactcell { display: grid; gap: 2px; font-size: var(--text-xs); }
.contactcell__row { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.contactcell__kind {
  flex: none;
  padding: 0 var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--text-2xs);
  background: var(--bg-hover);
  color: var(--fg-muted);
}
.contactcell__kind--private { background: var(--warn-soft); color: var(--warn-fg); }

/* Дата следующего касания — кнопка, открывающая окно календаря. */
.datebtn {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  color: var(--fg);
  cursor: pointer;
  text-decoration: underline dotted var(--line-strong);
  text-underline-offset: 3px;
}
.datebtn:hover { color: var(--accent-fg); }

/* Панель «Настроить таблицу»: список колонок с галочками и порядком. */
.colmenu { position: relative; }
.colmenu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: var(--z-widget);
  width: 280px;
  padding: var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  box-shadow: var(--shadow-xl);
  display: none;
}
.colmenu.is-open .colmenu__panel { display: block; }
.colmenu__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) 0;
  font-size: var(--text-xs);
}
.colmenu__item label { flex: 1; display: flex; align-items: center; gap: var(--space-3); cursor: pointer; }
.colmenu__move { display: flex; gap: 2px; }
.colmenu__actions {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

/* Объединённой графе нужен простор под ФИО и телефон целиком; длинная почта
   усечётся сама — адрес есть в mailto и в карточке. */
[data-col="lpr"] { min-width: 260px; }
.contactcell__row a { max-width: 195px; }
/* Графе комментария — под окошко ввода: без запаса оно вылезало бы на соседей. */
[data-col="comment"] { min-width: 230px; }
/* Сайту — под чип с доменом и кнопку поиска: без минимума колонка сжимается
   до нуля, и чип наезжает на «Этап». Домены длиннее усекаются в самом чипе. */
[data-col="site"] { min-width: 150px; }
