/* ============================================================
   СПРИНТ · оформление 12 сентября
   Подключается ПОСЛЕДНИМ, после app.css и frame.css.

   Палитра уже перекрашена через токены (sprint-tokens.css) — здесь
   только то, что токенами не выражается: антиква в заголовках,
   моноширинные подписи капсом, прямоугольные кнопки, чёрная верхняя
   панель и группы в боковом меню.

   Источник значений — _versions/v6-12sent/css/app.css.
   ============================================================ */

/* ---------- 1. Шрифты: локальные файлы, внешних запросов нет ----------
   Google Fonts запрещены юристом, поэтому подмножества скачаны один раз
   и лежат в ui/fonts/. Playfair — переменный, один файл на все веса. */

/* Unbounded — заголовки кабинета. Выбор Артёма 21.09.2026. */
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/unbounded-cyrillic-400.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/unbounded-latin-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/unbounded-cyrillic-500.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/unbounded-latin-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/unbounded-cyrillic-600.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/unbounded-latin-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/unbounded-cyrillic-700.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/unbounded-latin-700.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter — основная гротеска кабинета. Лежит локально: внешние шрифты
   запрещены юристом, файлы отдаёт наш же сервер. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/inter-cyrillic-400.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/inter-latin-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/inter-cyrillic-500.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/inter-latin-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/inter-cyrillic-600.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/inter-latin-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/inter-cyrillic-700.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/inter-latin-700.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/playfair-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/playfair-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- 2. Типографика ----------
   Правило 12 сентября: антиква только в заголовках, всё служебное —
   моноширинным капсом, тело — обычным шрифтом. */

.page-title,
.section__title,
#list .xopen__title,
h1, h2, h3 {
  font-family: var(--sp-display);
  font-weight: 500;
  letter-spacing: -.01em;
  color: var(--sp-ink);
}
.page-title { font-size: 40px; line-height: 1.12; }

/* Одно слово в заголовке золотом — акцент на экране ровно один */
.accent { color: var(--sp-accent); }

/* Надзаголовок над названием экрана: «КОММЕРЧЕСКИЕ:» */
.overline,
.page-head__over {
  font-family: var(--sp-sans);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--sp-dim);
}

/* Служебные подписи: шапка таблицы, лейблы полей, метки */
.label,
.field__label,
#list .xhead,
.count-line,
.bulk__text,
.collapse__note {
  font-family: var(--sp-sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  font-size: 12px;
}
.field__label { font-weight: 700; color: var(--sp-ink); }
#list .xhead { font-weight: 700; color: var(--sp-dim); }
.field__req { color: var(--sp-accent); }

/* Подпись под заголовком и пояснения — обычным шрифтом, без капса */
.page-head .hint,
.page-sub { font-family: var(--sp-sans); text-transform: none; letter-spacing: 0; }

/* Ники, даты, числа — моноширинным, как в образце */
#list .xpert__handle,
#list .xcell__v,
#list .score__num { font-family: var(--sp-mono); }

/* ---------- 3. Кнопки: прямоугольные, капсом, три ступени ----------
   Иерархия из правок Артёма: главное действие заливкой, второе рамкой,
   третье текстом. Заливка — синяя: золото под белым текстом не читается. */

.btn {
  border-radius: 0;
  font-family: var(--sp-sans);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
}
.btn--primary {
  background: var(--sp-navy);
  border: 1px solid var(--sp-navy);
  color: #FFFFFF;
}
.btn--primary:hover { background: var(--sp-navy-deep); border-color: var(--sp-navy-deep); color: #FFFFFF; }
/* Вторая ступень — рамка. */
.btn--secondary {
  background: transparent;
  border: 1px solid var(--sp-line-2);
  color: var(--sp-ink);
}
.btn--secondary:hover { background: var(--sp-sink); border-color: var(--sp-navy); color: var(--sp-navy); }

/* Третья — только текст. Рамки у неё быть не должно: с рамкой она
   неотличима от второй ступени, и трёхступенчатая иерархия схлопывается
   в двухступенчатую (поймано сценарием qa_mine). */
.btn--ghost {
  background: transparent;
  border: 1px solid transparent;
  color: var(--sp-mid);
}
.btn--ghost:hover { background: var(--sp-sink); border-color: transparent; color: var(--sp-navy); }
.btn:focus-visible { outline: 2px solid var(--sp-accent); outline-offset: 2px; }

/* Нажатие видно на любом управляющем элементе, а не только на .btn из app.css.
   Правка Артёма: «все кнопки на всех вкладках — эффекты при наведении и при
   нажатии». До этого :active жил только в app.css, а админка его не подключает,
   поэтому там нажатие было немым вовсе. */
.btn:active:not([disabled]):not(.is-disabled),
.nav-item:active, .fpill:active, .seg__item:active, .icon-btn:active,
.tab:active:not(.is-locked) { transform: translateY(1px); }

.btn--primary:active:not([disabled]):not(.is-disabled) {
  background: #0A1330; border-color: #0A1330; color: #FFFFFF;
}
.btn--secondary:active:not([disabled]):not(.is-disabled),
.btn--ghost:active:not([disabled]):not(.is-disabled) {
  background: #E6EAF2; border-color: var(--sp-navy); color: var(--sp-navy);
}
.btn--danger:active:not([disabled]):not(.is-disabled) { background: var(--sp-bad-soft); }
.nav-item:active { background: #E6EAF2; }
.fpill:active { background: var(--sp-sink); }

/* Текстовые действия в строках — синим, не золотом */
#list .xrow-act--inline .xrow-act__btn,
.toolbar__end .btn--ghost {
  border: 0;
  color: var(--sp-navy);
  background: transparent;
}
#list .xpert__top:hover .xrow-act--inline .xrow-act__btn { color: var(--sp-navy-deep); }

/* ---------- 4. Поля ---------- */
.input, .select, .textarea {
  border-radius: 0;
  border: 1px solid var(--sp-line-2);
  font-family: var(--sp-sans);
}
.input:focus, .select:focus, .textarea:focus {
  outline: 2px solid var(--sp-accent);
  outline-offset: 0;
  border-color: var(--sp-accent);
}

/* ---------- 5. Верхняя панель ---------- */
.app-header {
  position: sticky; top: 0; z-index: 45;
  display: flex; align-items: center; gap: 14px;
  height: 56px; padding: 0 24px;
  background: var(--sp-dark);
  color: #FFFFFF;
}
.app-header__brand {
  font-family: var(--sp-display);
  font-size: 22px; font-weight: 500; letter-spacing: -.01em;
  color: #FFFFFF; text-decoration: none;
}
.app-header__sub {
  font-family: var(--sp-sans);
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--sp-accent);
}
.app-header__actions { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.app-header__user {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--sp-sans); font-size: 12px; letter-spacing: .04em;
  color: rgba(255, 255, 255, .82);
}
.app-header__user .avatar {
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 0;
  background: rgba(255, 255, 255, .12); color: #FFFFFF;
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
}
.app-header .sb-burger { display: none; }

/* Рельса и содержимое встают под панель.

   Оболочка прижата ровно к высоте окна: раньше она брала 100vh И ещё 56px
   панели сверху, поэтому страница уезжала вниз на высоту панели и под
   содержимым открывалась пустота, в которую можно провалиться прокруткой.
   Прокрутка теперь живёт внутри области содержимого, а не у страницы. */
html, body { height: 100%; }
.app-shell {
  display: flex; flex-direction: column;
  height: 100vh; min-height: 0; overflow: hidden;
  /* app.css:342 держит align-items:start — в колонке это схлопывает шапку
     и тело по содержимому (шапка была 367px вместо 1440). */
  align-items: stretch;
  /* Оболочка обязана быть точкой отсчёта: у неё overflow:hidden, но
     непозиционированный предок не обрезает абсолютных потомков. Скрытые
     подписи для скринридера (.sr-only) лежат абсолютно и без этой строки
     считались от всей страницы — тянули её вниз на 406px пустоты. */
  position: relative;
}

/* И сама скрытая подпись не должна участвовать в раскладке: без clip-path
   она остаётся прямоугольником 1px, который влияет на высоту документа. */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%); border: 0;
}
.app-header { flex: 0 0 56px; }
.app-shell__body { display: flex; align-items: stretch; flex: 1; min-height: 0; }
.app-sidebar { position: static; height: auto; overflow-y: auto; }
/* Высоту области содержимого задаёт оболочка, а не она сама: на «Выдаче»
   локальное правило .app-main{height:100vh} добавляло к окну ещё 56px панели
   и давало 406px пустоты под страницей. */
.app-main { min-height: 0; overflow-y: auto; }
body .app-main { height: auto; }

/* ---------- 6. Боковое меню: группы с заголовками ---------- */
.app-sidebar {
  /* 252 вместо 232: после подъёма кегля «Поиск экспертов» и «Коммерческие»
     не помещались и резались многоточием. */
  width: 252px; flex: 0 0 252px;
  padding: 22px 0 28px;
  background: var(--sp-card);
  border-right: 1px solid var(--sp-line);
  align-items: stretch;
}
.app-sidebar__title {
  padding: 0 20px; margin: 0 0 6px;
  font-family: var(--sp-sans);
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--sp-dim);
}
/* Пункты тянутся на всю ширину рельсы. Правило align-items:center пришло из
   frame.css от рельсы 76px, где были одни иконки и центрирование было верным.
   На рельсе 232px с подписями оно ставило каждый пункт по своему центру —
   меню выглядело лесенкой (левый край −3, 16, 27, 35, 50). */
.app-sidebar__group {
  margin: 0 0 26px; gap: 0;
  display: flex; flex-direction: column; align-items: stretch;
}
/* Пункт занимает всю ширину рельсы, без собственных полей: иначе он
   висел со смещением 12px и не совпадал с заголовком группы. */
body .app-sidebar .nav-item {
  align-self: stretch; width: auto; margin: 0; box-sizing: border-box;
}
/* Заголовок группы выравниваем по тексту пункта, а не по краю рельсы:
   у пункта слева полоса 3px и отступ 20px, значит содержимое начинается
   на 23px — туда же ставим и заголовок. */
body .app-sidebar__title {
  align-self: stretch; padding-left: 23px; padding-right: 20px;
}
.app-sidebar .nav-item {
  width: auto; height: auto;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 20px;
  border: 0; border-left: 3px solid transparent; border-radius: 0;
  font-family: var(--sp-sans); font-size: 14px; font-weight: 400;
  color: var(--sp-mid);
  justify-content: flex-start;
}
.app-sidebar .nav-item:hover { background: var(--sp-sink); color: var(--sp-ink); box-shadow: none; }
.app-sidebar .nav-item.is-active {
  background: var(--sp-sink);
  border-left-color: var(--sp-accent);
  color: var(--sp-ink);
  font-weight: 600;
  box-shadow: none;
}
.app-sidebar .nav-item.is-active::before { display: none; }
.app-sidebar .nav-item__label { display: inline; flex: 1; min-width: 0; }
.app-sidebar .nav-item__ic { width: 16px; height: 16px; flex: 0 0 16px; color: var(--sp-dim); }
.app-sidebar .nav-item.is-active .nav-item__ic { color: var(--sp-accent); }
.app-sidebar .nav-item__count {
  display: inline; margin-left: auto;
  font-family: var(--sp-mono); font-size: 11px; color: var(--sp-dim);
}
.sb-foot { border-top: 1px solid var(--sp-line); }

/* ---------- 7. Блоки: угол прямой, тени нет ---------- */
.card, .section, .modal, .bulk, #list .xpert__open, .toast {
  border-radius: 0;
}
#list .xpert__score, .fpill, .tag, .score {
  border-radius: 0;
}
.fpill {
  font-family: var(--sp-sans); font-size: 12px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--sp-line-2); background: transparent; color: var(--sp-ink);
}
.fpill.is-active {
  background: var(--sp-navy); border-color: var(--sp-navy); color: #FFFFFF;
}
.fpill__n { color: inherit; opacity: .65; }

/* ---------- 8. Перебивка локальных стилей страниц ----------
   У каждого экрана свой <style> в конце <head>, он идёт ПОСЛЕ этого файла
   и при равной точности выигрывает. Добавляем `body` — один лишний вес,
   этого хватает, чтобы оформление брало верх без !important. */

/* Углы прямые везде, где локальный стиль ставил пилюлю */
body .fpill,
body #list .xpert__score,
body #list .xrow-act--inline .xrow-act__btn,
body #list .xpert__ava,
body .tag, body .score, body .btn, body .input, body .select, body .textarea {
  border-radius: 0;
}

/* Фильтры вердикта */
body .fpill {
  font-family: var(--sp-sans); font-weight: 700; font-size: 12px;
  letter-spacing: .08em; text-transform: uppercase;
  border: 1px solid var(--sp-line-2); background: transparent; color: var(--sp-ink);
}
body .fpill.is-active { background: var(--sp-navy); border-color: var(--sp-navy); color: #FFFFFF; }

/* Действие в строке — синим текстом. Золото под текстом даёт 1,9:1. */
body #list .xrow-act--inline .xrow-act__btn {
  color: var(--sp-navy); background: transparent; border-color: transparent;
}
body #list .xpert__top:hover .xrow-act--inline .xrow-act__btn {
  color: var(--sp-navy-deep); border-color: var(--sp-line-2);
}
body #list .xrow-act--inline .xrow-act__btn.is-disabled { color: var(--sp-dim); }

/* Отметка выбора — синяя: золотая галочка на золоте не видна */
body #list .xpert__pick input { border-radius: 0; border-color: var(--sp-line-2); }
body #list .xpert__pick input:checked { background: var(--sp-navy); border-color: var(--sp-navy); }
body #list .xpert__pick input:focus-visible { outline-color: var(--sp-accent); }

/* Инициалы эксперта — синим по светлому, а не золотом по золотому */
body #list .xpert__ava { background: var(--sp-sink); color: var(--sp-navy); }

/* Подсветка отмеченной строки — нейтральная, чтобы не спорить с золотом */
body #list .xpert:has(.xpert__pick input:checked) > .xpert__top { background: var(--sp-sink); }
body #list .xpert:has(.xpert__pick input:checked) > .xpert__top:hover { background: #E9E9EC; }

/* Остатки скруглений. Часть правил в локальных стилях экранов записана
   через два класса (.toolbar .select--inline, .bulk .btn--primary) и по
   точности выше простого `body .btn` — поэтому добавляем .app-shell. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) :is(
  .btn, .select, .input, .textarea, .card, .section, .bulk,
  .modal, .toast, .fpill, .tag, .score, .abandoned, .xpert__ava
), body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) #list, body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) #list :is(.xpert__score, .xrow-act__btn) {
  border-radius: 0;
}

/* Аватарка в подвале рельсы — синим по светлому, квадратной */
body .sb-foot__ava, body .app-header__user .avatar {
  border-radius: 0; background: var(--sp-sink); color: var(--sp-navy);
  font-family: var(--sp-mono); font-weight: 700;
}
body .app-header__user .avatar { background: rgba(255, 255, 255, .14); color: #FFFFFF; }

/* Видимый фокус. Строка выдачи получила role="button" и tabindex, значит
   обязана показывать, где находится курсор клавиатуры. Обводка синяя:
   у золота на белом 1,9:1, для индикатора нужно минимум 3:1. */
body #list .xpert__top:focus-visible,
body .nav-item:focus-visible,
body .fpill:focus-visible,
body .app-header__brand:focus-visible {
  outline: 2px solid var(--sp-navy);
  outline-offset: -2px;
}

/* Счётчик активного пункта меню: золото на светлом даёт 2,02:1 — не текст.
   Золотом остаётся только полоса слева, она несёт то же значение. */
body .app-sidebar .nav-item.is-active .nav-item__count { color: var(--sp-dim); }

/* Ссылки и текстовые действия */
body a { color: var(--sp-navy); }
body .page-head .btn--newrun { color: var(--sp-navy); font-family: var(--sp-sans); }


/* ВАЖНО про область действия.
   Модалки, выдвижные панели и уведомления лежат ВНЕ .app-shell — они прямые
   дети <body>. Поэтому правила ниже перечисляют все слои, а не только оболочку:
   иначе внутри окна «Добавить лида» кнопка оставалась золотой с белым текстом
   (2,3:1), и это ловилось только обходом с кликами, а не осмотром страницы. */
/* ---------- 9. Золото никогда не красит буквы ----------
   Перекраска токенов сделала золотым всё, что раньше было синим акцентом,
   в том числе текст: подписи, метки, кикеры, числа. На белом это 1,9:1.
   Собрано по всем девяти экранам обходом DOM — вот полный список мест. */

body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) :is(
  .accent, .overline, .tag--gold, .fix__go, .fresh__label, .size-chip,
  .size-chip.is-on, .brief-step__kicker, .ftab, .ftab__n, .money-tile__v,
  .crm-pick__gap, .pv__kicker, .pv__metric, .sec__num, .auth-card__kicker,
  .auth-side__state, .verdict__title, .hist__back, .preset__mark, .ic-badge,
  .modal__over, .empty__mark, .brief-step__num
), body .auth-card .auth-card__kicker,
   body .auth-side .auth-side__state { color: var(--sp-gold-text); }

/* Цветные метки сохраняют свой смысловой цвет: золото поверх зелёной или
   красной подложки давало 3,4–3,9:1 и путало статус с акцентом. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .tag--muted { color: var(--sp-mid); background: var(--sp-sink); }
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .tag--positive { color: var(--sp-ok); background: var(--sp-ok-soft); }
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .tag--danger { color: var(--sp-bad); background: var(--sp-bad-soft); }
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .tag--warn { color: var(--sp-warn); background: var(--sp-warn-soft); }

/* Подпись внутри цветной метки брала общий серый --sp-dim и на красной
   подложке давала 4,01:1. Берём цвет самой метки. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) :is(.tag--danger, .tag--positive, .tag--warn, .tag--muted) :is(.st-k, .st-n) {
  color: inherit;
}

/* Выбранный срок публикаций: локальное правило красит подпись золотом
   (search.html — `input:checked + .fresh__label`), точность там выше. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .fresh__item input:checked + .fresh__label { color: var(--sp-gold-text); }
/* .size-chip.is-on здесь больше нет: включённый чип красится заливкой
   в разделе 12, и это правило его перебивало. */

/* Главное действие заливается синим на любом экране: часть экранов красила
   его золотом локально, и белый текст на золоте давал 2,3:1. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .btn--primary {
  background: var(--sp-navy); border-color: var(--sp-navy); color: #FFFFFF;
}
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) .btn--primary:hover {
  background: var(--sp-navy-deep); border-color: var(--sp-navy-deep); color: #FFFFFF;
}

/* Инициалы в кружках: золото по золоту не читалось вовсе */
body :is(.ava, .ava__img, .row-item__ava, .sb-foot__ava, .xpert__ava, .pcard__ava) {
  background: var(--sp-sink); color: var(--sp-navy);
}

/* Звёздочка обязательного поля — не золотом: это предупреждение */
body .field__req { color: var(--sp-bad); }

/* Вкладки и активные пункты: золото остаётся полосой, буквы — синие */
body :is(.tab.is-active, .ftab.is-active, .seg__item.is-active) { color: var(--sp-navy); }

/* Подпись «платформа» в чёрной панели — там золото на тёмном даёт 8,7:1 */
body .app-header__sub { color: var(--sp-accent); }

/* ---------- 10. Прямой угол на всём содержимом ----------
   Скругления живут в локальных стилях экранов (var(--sp-radius-*)), поэтому
   общего правила мало: перечисляем то, что обходом DOM нашлось скруглённым
   на девяти экранах. В оформлении 12 сентября прямоугольны все поверхности,
   кроме аватарки в чёрной панели. */
body :is(.app-shell, .modal, .modal-backdrop, .side-panel, .toast-stack, .toast) :is(
  .seg, .seg__label, .seg__item, .chip-toggle, .hint-chip, .fresh__label,
  .size-chip, .runs, .who, .letter, .hist, .form, .sticky-panel, .ftab,
  .board__col, .board__add, .col-act, .pcard, .pcard__task, .crm-pick,
  .modal__close, .tab, .metric, .panel-block, .row-item__ava, .lead,
  .kpi, .stat, .note, .filerow, .preset, .pv, .empty, .task,
  .profile-card, .mini, .kpdraft__list, .wizard, .step-card, .sticky-card
), body #brief-form, body .brief-main > form,
   body .auth-card, body .auth-side, body .auth-field__input {
  border-radius: 0;
}


/* Подпись под заголовком пустого состояния: раньше этот текст стоял ВМЕСТО
   иконки и читался как плашка неизвестного назначения (search.html). */
.empty__note {
  margin: 6px 0 0;
  font-family: var(--sp-sans); font-size: 11.5px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--sp-dim);
}


/* Расшифровка в процессе: тихо и явно, чтобы запись не выглядела проглоченной */
.quote.is-busy { color: var(--sp-dim); font-style: italic; }


/* ---------- 12. Состояния, которые видно только после клика ----------
   Найдено сквозным обходом с нажатием каждой кнопки: осмотр страницы
   в покое такие места не показывает. */

/* Подтверждение «Скопировано» на главной кнопке: класс .is-done красил текст
   в зелёный, а заливка у primary синяя — 1,35:1, надпись пропадала. */
body .btn--primary.is-done,
body .btn--primary.is-done:hover { background: var(--sp-ok); border-color: var(--sp-ok); color: #FFFFFF; }
body .btn--secondary.is-done, body .btn--ghost.is-done { color: var(--sp-ok); }

/* Включённый фильтр-чип: белый текст на золоте давал 2,3:1. Заливка синяя,
   как у остальных активных переключателей. */
/* Один язык выбора на экран. Срок публикаций помечается золотой рамкой на
   кремовой подложке, а размер аудитории красился синей заливкой — на одном
   экране получалось два разных «выбрано». Сводим к рамке: она и контраст
   держит (текст --sp-navy на кремовой подложке — 9,4:1), и не спорит
   с единственной кнопкой-заливкой экрана. */
body .app-shell :is(.chip-toggle, .size-chip, .seg__item).is-on,
body :is(.chip-toggle, .size-chip, .seg__item).is-on,
body .chip-toggle[aria-pressed="true"] {
  background: var(--sp-accent-soft);
  border-color: var(--sp-accent);
  color: var(--sp-navy);
  font-weight: 600;
}
/* «+ Колонка» — действие, а не выбор: остаётся заливкой */
body .board__add {
  background: var(--sp-navy); border-color: var(--sp-navy); color: #FFFFFF;
}

/* Наведение на «+ Колонка» осталось от светлой версии кнопки: app.css красит
   её текст золотом (--sp-accent) — на прежнем прозрачном фоне это читалось,
   на новой синей заливке даёт 4,49:1. Текст под курсором держим белым
   (10,3:1), сигнал наведения даёт светлая золотая рамка. */
body .board__add:hover,
body .board__add:focus-visible,
body .board__add:active {
  background: var(--sp-navy); color: #FFFFFF; border-color: var(--sp-accent);
}

/* На ТЁМНЫХ подложках золото должно быть светлым: тёмное --sp-gold-text
   рассчитано на белый фон и на чёрном даёт 3,0–3,9:1. Здесь обратная
   ситуация — светлое #CBA656 на тёмном даёт 8,7:1. */
body .app-shell :is(.theme-dark, .panel-dark, .pv, [data-theme="dark"]) :is(
  .accent, .overline, .pv__kicker, .pv__metric, .sec__num, .tag--gold
), body .app-header :is(.accent, .overline, .tag--gold),
   body :is(.theme-dark, .panel-dark, .pv) :is(.accent, .overline, .pv__kicker, .pv__metric, .sec__num) {
  color: var(--sp-accent);
}


/* Отмеченный переключатель: заливка синяя, а не золотая. Белая галочка
   на золоте даёт 2,3:1 при норме 3:1 для элементов управления — текстовый
   измеритель такое не ловит, нашлось осмотром скриншота входа. */
body input[type="checkbox"]:checked,
body input[type="radio"]:checked {
  background-color: var(--sp-navy);
  border-color: var(--sp-navy);
  accent-color: var(--sp-navy);
}


/* ---------- 13. Хвост, оставленный агентами владельцу композиции ----------
   Это общая рельса и общие токены: править их с одного экрана значит развести
   девять экранов по виду, поэтому агенты правильно передали сюда. */

/* Подпись и кнопка выхода в подвале рельсы — видимые и полноценные.
   Раньше кнопка была 0×0: выйти с десктопа было нечем. */
body .sb-foot { display: flex; align-items: center; gap: 10px; padding: 14px 20px 18px; }
body .sb-foot__user { display: flex; flex-direction: column; min-width: 0; }
body .sb-foot .btn--ghost, body .sb-foot__exit {
  display: inline-flex; align-items: center;
  margin-left: auto; min-height: 44px; padding: 0 10px;
  font-family: var(--sp-sans); font-size: 13px; letter-spacing: 0;
  text-transform: none; color: var(--sp-mid); background: transparent; border: 0;
}
body .sb-foot .btn--ghost:hover, body .sb-foot__exit:hover { color: var(--sp-bad); }

/* Зона нажатия пунктов меню — 44px. Было 41, у выхода 31: на телефоне палец
   промахивается. Высоту даём отступами, рисунок строки не меняется. */
body .app-sidebar .nav-item { min-height: 44px; }

@media (max-width: 900px) {
  body .app-header .sb-burger { width: 44px; height: 44px; }
  body .sb-foot { padding: 14px 16px 18px; }
}


/* Колонка вердикта была 138px, а метка «C · не тратить время» занимает 151 —
   она вылезала и обрезалась соседней ячейкой. Отдаём вердикту место из
   колонки действия, там запас есть.

   Медиазапрос обязателен: без него это правило с префиксом `body` перебивало
   мобильную раскладку самой выдачи, карточка кандидата оставалась десятичной
   таблицей, и на 375 px за краем экрана прятались чекбокс, оценка и кнопка
   «Добавить в CRM» (найдено оркестратором 21.09.2026). */
@media (min-width: 1438px) {
  body #list .xpert__top,
  body #list .xhead {
    grid-template-columns: 28px 49px minmax(180px, 1.5fr) 116px 116px 92px 110px 164px 138px 30px;
  }
}
body #list .xpert__score { max-width: 100%; }
body #list .score__label { white-space: nowrap; }

/* ---------- 11. Телефон ---------- */
@media (max-width: 900px) {
  /* Чёрной плашки нет и на телефоне, но сама полоса остаётся: в ней живёт
     бургер, а меню на этой ширине — выдвижной ящик. */
  body .app-header {
    padding: 0 14px; gap: 10px;
    background: var(--sp-card);
    color: var(--sp-ink);
    border-bottom: 1px solid var(--sp-line);
    border-right: none;
  }
  body .app-header__brand { color: var(--sp-ink); }
  body .app-header__sub { color: var(--sp-gold-text); }
  .app-header__sub, .app-header__user span:not(.avatar) { display: none; }
  .app-header .sb-burger {
    display: grid; place-items: center;
    /* 34px — палец мимо: зона нажатия держится 44px, как у остальных кнопок */
    width: 44px; height: 44px; margin: 0;
    background: transparent; border: 1px solid var(--sp-line-2);
    color: var(--sp-ink); font-size: 15px; cursor: pointer;
  }
  .app-shell__body { display: block; }
  /* Ящик начинается ПОД верхней панелью: при top:0 она накрывала первые 56px
     и съедала заголовок группы «Работа». */
  body .app-sidebar {
    /* position обязателен здесь: правило .app-sidebar{position:sticky} из
       раздела 5 идёт без медиазапроса и перебивало fixed из frame.css —
       ящик оставался в потоке и на телефоне отжимал содержимое вниз
       на всю свою высоту (≈700px пустоты над заголовком экрана). */
    position: fixed; left: 0; z-index: 40;
    top: 56px; height: calc(100vh - 56px); width: 252px;
    align-items: stretch;
  }
  /* Пункты тянутся на всю ширину: при сжатии по содержимому они вставали
     по центру и лесенкой — каждый со своим левым краем. */
  body .app-sidebar .nav-item {
    width: auto; align-self: stretch;
    justify-content: flex-start; padding: 9px 20px;
  }
  .page-title { font-size: 28px; }
}

/* ---------- 14. Кнопки: скин выше страничных стилей ----------
   proposal.html:121, admin.html:24 и search.html держат собственный `.btn`
   (скруглённый, гротеск, без капса). Страничный <style> грузится ПОСЛЕ
   ссылок и при равной силе побеждает — из-за этого КП, админка и поиск
   выглядели «другим дизайном». Префикс `body` возвращает единый язык. */
body .btn {
  border-radius: 0;
  /* Моноширинный капс на каждой кнопке читался тяжело и «технически».
     Гротеска обычным регистром — Артём, 21.09.2026. */
  font-family: var(--sp-sans);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
}
body .btn--primary {
  background: var(--sp-navy);
  border-color: var(--sp-navy);
  color: #FFFFFF;
}
body .btn--primary:hover:not([disabled]):not(.is-disabled) {
  background: var(--sp-navy-deep);
  border-color: var(--sp-navy-deep);
  color: #FFFFFF;
}
body .btn--secondary {
  background: transparent;
  border: 1px solid var(--sp-line-2);
  color: var(--sp-ink);
}
body .btn--ghost {
  background: transparent;
  border: 1px solid transparent;
  color: var(--sp-mid);
}
body .btn--ghost:hover:not([disabled]):not(.is-disabled) {
  background: var(--sp-sink);
  color: var(--sp-ink);
}

/* pipeline.html:397-399,444-445 перекрашивают кнопки внутри боковой панели
   и модалки: скругление 12px, гротеск и ЗОЛОТАЯ заливка под белым текстом
   (1,9:1). Два класса в селекторе сильнее `body .btn`, поэтому повторяем
   с тем же охватом. */
body :is(.side-panel, .modal) .btn {
  border-radius: 0;
  font-family: var(--sp-sans);
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
  font-weight: 600;
}
body :is(.side-panel, .modal) .btn--primary {
  background: var(--sp-navy);
  border-color: var(--sp-navy);
  color: #FFFFFF;
}
body :is(.side-panel, .modal) .btn--primary:hover:not([disabled]):not(.is-disabled) {
  background: var(--sp-navy-deep);
  border-color: var(--sp-navy-deep);
}

/* ---------- 15. Чёрной плашки сверху нет ----------
   Артём 21.09.2026: «убери эту чёрную плашку сверху, удали её».
   Разметку не трогаем — в шапке живут #burger и ссылка на марку, они нужны
   на телефоне. Вместо этого `display: contents` на теле оболочки поднимает
   меню и содержимое в саму сетку оболочки, и шапка встаёт белым блоком
   марки НАД меню, в его же колонке, а содержимое тянется на обе строки. */
@media (min-width: 901px) {
  body .app-shell {
    display: grid;
    /* Не `--sidebar-w`: app.css:134 переопределяет его на --sp-sidebar (258px),
       а сама рельса шириной 232 — колонка выходила на 26px шире полосы. */
    grid-template-columns: 252px minmax(0, 1fr);
    grid-template-rows: 56px minmax(0, 1fr);
    height: 100vh;
    overflow: hidden;
    position: relative;
  }
  body .app-shell__body { display: contents; }

  body .app-header {
    grid-column: 1; grid-row: 1;
    position: static;
    height: auto; min-height: 0;
    padding: 0 20px;
    background: var(--sp-card);
    color: var(--sp-ink);
    border-bottom: none;
    border-right: 1px solid var(--sp-line);
  }
  body .app-header__brand { color: var(--sp-ink); }
  body .app-header__sub { color: var(--sp-gold-text); }
  /* Имя пользователя уже стоит в подвале меню — в марке оно лишнее. */
  body .app-header__actions { display: none; }

  body .app-sidebar {
    grid-column: 1; grid-row: 2;
    position: static; height: auto; min-height: 0;
    overflow-y: auto;
    padding-top: var(--sp-space-4);
  }
  body .app-main {
    grid-column: 2; grid-row: 1 / span 2;
    min-height: 0; height: auto;
    overflow-y: auto;
  }
}

/* ---------- 16. Зоны нажатия на телефоне ----------
   Пять агентов независимо нашли одно и то же: на 375 px кнопки, чипы, пилюли
   и пункты меню имели 26–42 px по высоте при норме 44. Палец промахивается.
   Правило общее, потому что и причина общая — кегли заданы в разных местах,
   а требование одно. Скрытые поля и декоративные узлы не трогаем. */
@media (max-width: 760px) {
  body :is(.btn, .fpill, .ftab, .chip, .chip-toggle, .seg__label, .size-chip,
           .nav-item, .tab, .icon-btn, .row-item__act, .link-del, .tag__x,
           .col__act, .col-act, .board__add, .crm-acts .seg__label, .sb-foot__exit,
           .xrow-act__btn, .xrow-write, .modal__close, .wizard__item,
           .hist__back, .row-item__del, .filerow__del):not([hidden]) {
    min-height: 44px;
  }
  /* Кнопки-иконки должны быть и по ширине не меньше: 26×26 крестик чипа
     палец не ловит. */
  body :is(.icon-btn, .tag__x, .link-del, .col__act, .col-act, .modal__close):not([hidden]) {
    min-width: 44px;
  }
  /* Родная галочка мелкая по природе — увеличиваем саму зону, а не рисунок. */
  body .xpert__pick,
  body label:has(> input[type="checkbox"]) {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
}

/* ---------- 17. Пустые состояния: один вид на весь кабинет ----------
   Экраны задавали `.empty { text-align: left }`, а иконка и кнопка оставались
   по центру из ядра — состояние разваливалось пополам: заголовок у левого
   края, значок и действие посередине (Артём, 21.09.2026). Собираем в столбик
   по центру и ограничиваем ширину текста, иначе строка растягивается на всю
   карточку и читается тяжело. */
body :is(.empty, .state.empty) {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
body :is(.empty, .state.empty) .empty__mark { margin: 0 0 4px; }
body :is(.empty, .state.empty) .empty__title { margin: 0; }
body :is(.empty, .state.empty) .empty__text {
  margin: 0;
  max-width: 46ch;
}
body :is(.empty, .state.empty) .empty__actions {
  margin-top: 8px;
  justify-content: center;
}
body :is(.empty, .state.empty) .empty__note { margin: 0; }

/* ---------- 18. Колонка содержимого стоит по центру ----------
   Экраны ограничивают содержимое 1080 пикселями, но прижимали его к левому
   краю: слева ноль, справа 108 — выглядело как «текст уехал и справа пустота»
   (Артём, 21.09.2026). Колонка центрируется, поля становятся симметричными.
   Заодно даём воздух от меню: 40 пикселей на 1440 читались как «прижато». */
/* Боковые поля теперь даёт колонка, а не каждый блок сам: у шапок экранов
   было своё 40–56 пикселей поверх, и заголовок стоял правее содержимого. */
body .app-main > :is(.page-head, .toolbar, .crm-top, .count-line, .tabs,
                     .list-scroll) {
  /* `.list-scroll` добавлен 22.09.2026: его собственные 40 пикселей поля
     сдвигали таблицу выдачи на 346, когда шапка и фильтры стояли на 306.
     Поля даёт колонка, а не каждый блок сам — иначе края не сходятся.

     `.bulk` из этого списка ИСКЛЮЧЕНА: это не прозрачный блок, а залитая
     синим панель. Обнулив ей поля, я прижал надпись и кнопки вплотную к
     краю заливки (Артём, 22.09.2026: «текста обрезаются, кнопки в упор»).
     Её внутренние 20 пикселей — часть самой панели, а не поля страницы. */
  padding-left: 0;
  padding-right: 0;
}
/* Доска воронки прокручивается вбок — ширину ей не режем, но левый край
   ставим по той же колонке, что и заголовок. */
body .app-main > .board { padding-left: calc((100% - min(100%, var(--sp-content-max))) / 2); }

body .app-main > :is(.brief-layout, .kp-grid, .section, .page-head, .toolbar,
                     .list-scroll, .crm-top, .bulk, .count-line, .tabs) {
  /* Одна колонка на весь экран: шапка, панель и содержимое стоят по одной
     линии. Без max-width шапка схлопывалась по содержимому и центрировалась
     сама по себе — заголовок уезжал от таблицы. */
  max-width: var(--sp-content-max);
  margin-left: auto;
  margin-right: auto;
  width: 100%;
}
body .app-main { padding-left: 16px; padding-right: 16px; }

@media (max-width: 900px) {
  /* Поля уже, чем на большом экране, но НЕ ноль: с нулём буквы упираются в
     край стекла и читаются как обрезанные — видно на любом снимке 375.
     Раньше здесь стоял ноль ради ширины строки, и это была ошибка. */
  body .app-main { padding-left: 14px; padding-right: 14px; }
}

/* ---------- 19. Вместо теней — волосяной кант ----------
   Артём, 22.09.2026: «тени добавляют старости, хочется освежить». Мягкая тень
   под каждой карточкой — приём десятых годов; плоская поверхность с тонкой
   линией выглядит современнее и читается чище.

   Тень НЕ выключена в ноль, а заменена на кольцо в один пиксель без размытия
   и смещения. Так каждая из 33 карточек сохраняет чёткий край (иначе белое на
   почти белом теряет границы), но объёма на странице не остаётся.

   Почему через токен, а не поимённо: `--sp-shadow` стоит в 33 правилах шести
   экранов. Смена ЗНАЧЕНИЯ меняет их все разом. И, в отличие от `none`, кольцо
   остаётся допустимым первым слоем там, где к тени дописан второй
   (`var(--sp-shadow), inset 3px 0 0 …` у молчащего лида) — `none` первым слоем
   сделал бы такое правило недопустимым, и браузер выбросил бы его целиком
   вместе с красной полосой. */
:root {
  --sp-shadow: 0 0 0 1px var(--sp-line);
  /* Для плавающих слоёв тень остаётся — она объясняет, что модалка, шторка или
     тост оторваны от листа. Но тише прежней: одно мягкое пятно без второго,
     контактного слоя, который и давал ощущение объёмной плашки. */
  --shadow-overlay: 0 18px 50px -24px rgba(21, 23, 26, .28);
}

/* Слои, которые действительно лежат поверх страницы, берут тень явно: в core
   они были завязаны на тот же токен и вместе со всеми стали бы плоскими. */
body :is(.modal, .toast, .side-panel, .menu, .dropdown) {
  box-shadow: var(--shadow-overlay);
}

/* Наведение больше не приподнимает карточку — оно подсвечивает край. */
body .pcard:hover { box-shadow: 0 0 0 1px var(--sp-accent); }
/* Карточку тащат — вот тут отрыв от листа настоящий, тень уместна. */
body .pcard.is-dragging { box-shadow: var(--shadow-overlay); }

/* ---------- 20. Воронка: плитки и доска по той же колонке ----------
   Артём, 22.09.2026: «плашки сверху шире, а плашка воронки уже — отступы
   слева и справа на разных элементах разные». Замер подтвердил: шапка и
   панель стояли на 306/54, а плитки и доска — на 268/16. В разделе 18 их
   просто не было в списке. */
body .app-main > :is(.crm-stats, .board-wrap) {
  max-width: var(--sp-content-max);
  margin-left: auto;
  margin-right: auto;
  width: 100%;
}
/* Сами плитки и колонки доски лежали ещё на 44 пикселя внутрь: край коробки
   стоял по колонке, а первая колонка воронки — на 98, когда заголовок на 54.
   Поле снимаем: край даёт колонка, промежутки — зазор сетки. */
body :is(.crm-stats, .board) { padding-left: 0; padding-right: 0; }

/* ---------- 21. Бриф: пустая колонка справа больше не держит место ----------
   Сетка брифа — две колонки, 658 и 300. Боковая колонка скрыта, но место под
   неё сетка резервировала: 334 пикселя пустоты справа. Плюс своё поле в 44
   пикселя сдвигало текст правее заголовка — отсюда «что левее, а что правее».

   `auto` во второй колонке даёт скрытому блоку нулевую ширину, и содержимое
   встаёт ровно под заголовком. Появится боковая колонка — место возьмёт снова. */
body .app-main > .brief-layout {
  padding-left: 0;
  padding-right: 0;
  grid-template-columns: minmax(0, 1fr) auto;
}
/* `auto` даёт скрытой колонке ноль, но ВИДИМОЙ — ширину по содержимому: на
   шаге формы боковая колонка разъезжалась до 634 и душила саму форму.
   Ширину называем явно — ту же, что была в сетке до правки. */
body .brief-side { width: 300px; }
/* Строка ввода во всю ширину колонки нечитаема — держим её на длине абзаца.
   Край формы при этом остаётся под заголовком, а не съезжает к середине. */
body .brief-main { max-width: 820px; }
/* Пустое состояние — исключение: оно центрируется по всей колонке, иначе при
   узкой форме стоит заметно левее середины экрана. */
body .brief-main:has(> .empty) { max-width: none; }

/* ---------- 22. Поиск: своя обёртка живёт по общим правилам ----------
   На этом экране содержимое лежит не в `.app-main`, а в `.app-body` с
   собственным полем в 44 пикселя. Из-за этого карточки стояли на 312/60,
   когда шапка — на 306/54. Разница в шесть пикселей, но край на экране
   один, и он обязан быть общим. */
body .app-body { padding-left: 16px; padding-right: 16px; }
body .app-body > * {
  max-width: var(--sp-content-max);
  margin-left: auto;
  margin-right: auto;
  width: 100%;
}
@media (max-width: 900px) {
  body .app-body { padding-left: 0; padding-right: 0; }
}

/* ---------- 23. Портрет в аватарке ----------
   Аватарки были только инициалами. Если у записи есть НАШ файл портрета
   (чужой домен запрещён юристом — см. js/message.js), он закрывает кружок
   целиком. Инициалы остаются под ним: не загрузился файл — виден текст. */
body :is(.ava, .avatar, .xpert__ava, .pcard__ava, .row-item__ava, .sb-foot__ava) {
  position: relative;
  overflow: hidden;
}
body :is(.ava, .avatar, .xpert__ava, .pcard__ava, .row-item__ava, .sb-foot__ava) > img.ava__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ---------- 24. Липкая нижняя панель не накрывает содержимое ----------
   Панель выбора («выбрано N из M») висит над страницей, и последняя строка
   списка — строка счёта — уходила под неё наполовину. Высота панели вместе
   с полями ≈96 px; на эту высоту список и отступаем. */
body .app-main:has(.bulk) :is(.list-scroll, .board-wrap) { padding-bottom: 96px; }
/* Строка счёта лежит ВНУТРИ прокручиваемого списка и упиралась в его нижний
   край — выглядело как обрезка. Своего отступа ей хватает, лишний лишь
   добавлял пустой прокрутки; место под панель даёт padding-bottom списка. */

/* ---------- 25. Галочка в отметке — белая ----------
   Артём, 22.09.2026: «галочка чёрная на тёмно-синем, сливается».

   Причина: галочка красилась токеном `--text-on-navy`, а его переназначили на
   `--sp-accent-ink` (#14264E) — цвет текста поверх ЗОЛОТА. На золотой заливке
   он верен, но отметка заливается синим, и тёмное по тёмному пропадает.

   Чиним не подстановкой цвета в одном месте, а правилом: заливка отметки —
   синяя, знак внутри — белый. Золотую заливку из отметок убираем совсем:
   тёмный знак на золоте даёт 1,9:1, светлый — и того меньше. */
body .check input:checked {
  background: var(--sp-navy);
  border-color: var(--sp-navy);
}
body .check input[type="checkbox"]:checked::after { border-color: #FFFFFF; }
body .check input[type="radio"]:checked::after {
  background: #FFFFFF;
  /* Точка внутри была квадратной: её радиус брался из общего токена, а он
     по всему кабинету обнулён в ноль (углы прямые — решение 21.09.2026).
     Переключателю прямые углы не подходят: круглая рамка с квадратом внутри
     читается как брак. Радиус называем явно — и самой рамке, и точке. */
  border-radius: 50%;
}
body .check input[type="radio"] { border-radius: 50%; }

/* ---------- 26. Четвёртый этап воронки влезает в колонку ----------
   Столбцы были по 266: четыре вместе с зазорами дают 1 320 при колонке в
   1 080, и четвёртый обрезался ровно по краю — на экране это читается как
   поломка, хотя это боковая прокрутка. 258 + три зазора по 14 = 1 074. */
:root { --sp-board-column: 258px; }
/* Экран воронки задаёт ширину столбца литералом поверх токена — здесь же
   его и переопределяем, иначе токен ни на что не влияет. */
body .board__col {
  width: var(--sp-board-column);
  flex: 0 0 var(--sp-board-column);
}

/* ---------- 27. Предпросмотр КП говорит на языке готового документа ----------
   Артём, 22.09.2026: «в презентации уебищный старый дизайн». Сам документ
   переписан (server/kp_render.py), но кадр предпросмотра в кабинете рисуется
   СВОЕЙ разметкой и до сих пор держал тему «night»: антиква Georgia, чёрный
   фон. Получалось, что на экране одно, а в отправленном КП другое.

   Шаблоны из продукта удалены ещё 21.09.2026, поэтому тему не выбираем —
   приводим единственный оставшийся кадр к виду документа: тёмно-синий лист,
   гротеск, плотные заголовки, золото тонкой линией. */
body .pv[data-theme="night"] {
  --pv-body: "Inter", -apple-system, "Segoe UI", Arial, sans-serif;
  --pv-display: "Inter", -apple-system, "Segoe UI", Arial, sans-serif;
  --pv-bg: var(--sp-ink);
  --pv-ink: #FFFFFF;
  --pv-muted: rgba(255, 255, 255, .68);
  --pv-accent: var(--sp-accent);
  --pv-line: rgba(255, 255, 255, .18);
  --pv-title-size: 3em;
  --pv-title-track: -.035em;
}
body .pv[data-theme="night"] .pv__title { font-weight: 700; }
/* Подпись-метка: та же разрядка и тот же кегль, что на слайде документа. */
body .pv[data-theme="night"] .pv__kicker { letter-spacing: .18em; font-weight: 600; }
/* Линия под заголовком — тонкая метка, а не толстое подчёркивание. */
body .pv[data-theme="night"] .pv__rule { height: .14em; width: 4em; }

/* ---------- 28. Недоступные площадки выглядят недоступными ----------
   Здесь приглушались Instagram, TikTok и Pinterest: источника под них не было,
   и выбор обещал то, чего нет. 23.09.2026 подключён Apify — все пять площадок
   работают, приглушение снято, как и было условлено в самом правиле.

   Разница осталась в другом: у этих трёх нет поиска по нише, они разбирают
   профили по списку. Об этом говорит сама форма — полем «Профили» и подписью
   с ценой, а не приглушённой кнопкой. */

/* ---------- 29. Тосты на телефоне не закрывают шапку ----------
   На узком экране стопка тостов уезжала наверх, под высоту чёрной панели
   (`--header-h`). Панель мы сняли 21.09.2026, и отсчитывать стало не от чего:
   два тоста подряд накрывали заголовок экрана и подзаголовок — шапка
   переставала читаться (найдено проверкой 22.09.2026).

   Возвращаем их вниз, как на большом экране: внизу они ничего не закрывают,
   а место действия — кнопки — остаётся видимым. */
@media (max-width: 900px) {
  body .toast-stack {
    top: auto;
    bottom: var(--sp-space-3);
    left: var(--sp-space-3);
    right: var(--sp-space-3);
    width: auto;
  }
  /* Там, где внизу висит синяя панель выбора, поднимаемся над ней. */
  body .app-main:has(.bulk) ~ .toast-stack,
  body:has(.bulk) .toast-stack { bottom: 96px; }
}

/* ───────────────────────────────────────────────────────────── 30. Шапка
   колонки воронки: название не должно исчезать.

   Три кнопки колонки на телефоне растут до 44 px под палец (правило выше),
   и в строке шириной 258 px им остаётся 132 px плюс счётчик и сумма. Название
   этапа — единственный тянущийся элемент, поэтому оно сжималось до 5 px:
   на доске было видно «⊢» вместо «Новый». Замерено 22.09.2026 на 375.

   Лечим двумя ходами: название никогда не ужимается ниже своего текста и
   обрезается многоточием, а на узком экране уходит на свою строку целиком. */
body .board__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body .board__head .col-act { flex: 0 0 auto; }

@media (max-width: 900px) {
  body .board__head { flex-wrap: wrap; }
  /* Целая строка под название: кнопки и числа переезжают под него. */
  body .board__title { flex: 1 0 100%; }
}

/* Кадр готового КП (#res-cover, .pv--kp) живёт по палитре РЕФЕРЕНСА, а не по
   фирменному золоту кабинета. Правило выше красит .pv__kicker/.pv__metric
   общим акцентом и по специфичности перебивает переменную кадра — из-за
   этого предпросмотр показывал золотую метку на любом референсе, хотя лист
   собирался его собственным цветом (Артём, 23.09.2026: «дизайн никуда не
   годится»). Дописано в конец: общий слой только дополняем. */
body .app-shell .pv--kp .pv__kicker,
body .app-shell .pv--kp .pv__metric,
body .pv--kp .pv__kicker,
body .pv--kp .pv__metric { color: var(--pv-accent); }

/* ---------- 22. Аналитика воронки: та же колонка и воздух сверху ----------
   Артём, 23.09.2026: «плашки по аналитике сильно прижаты к кнопкам сверху, и
   отступы слева-справа у разных элементов разные». Замер на 1440: ряд кнопок
   стоял 306…1386, а плитки 312…1380 — то есть на 6 px внутрь с обеих сторон,
   и всего 4 px зазора под кнопками.

   Причина — собственные поля блока `#conv-view` (4px 44px 40px): он не лежал
   в общей колонке кабинета, а отбивался своими отступами от края main.
   Снимаем боковые поля, кладём блок в ту же колонку, что шапка и кнопки, и
   даём нормальный отступ сверху. */
body #conv-view {
  max-width: var(--sp-content-max);
  margin-left: auto;
  margin-right: auto;
  width: 100%;
  padding-left: 0;
  padding-right: 0;
  padding-top: 24px;
}

/* ---------- 23. Аватарка профиля: фото без белых краёв ----------
   Артём, 23.09.2026: «вокруг аватарки белые острые края, за фоткой белый
   квадрат, всё наслаивается». Причина: у кружка своя белая рамка и синяя
   заливка, а фото ложилось поверх прямоугольником — углы снимка торчали
   из-под круга, а незакрытая заливка читалась как второй квадрат.
   Фото обрезаем самим кружком и снимаем фон с рамкой, когда оно есть. */
body .avatar, body .sb-foot__ava { overflow: hidden; }
body .avatar:has(.ava__img), body .sb-foot__ava:has(.ava__img) {
  background: transparent;
  border-color: transparent;
  padding: 0;
}
body .ava__img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
}

/* ---------- 24. Правый край доски: без белой засветки ----------
   Артём, 23.09.2026: «когда скроллишь воронку направо, справа рядом с
   кнопкой „+ Колонка" подсвечивается белым — это убрать».
   Там стоял градиент в цвет бумаги шириной 56 px: задумывался как мягкое
   гашение обрезанной колонки, а читается как засветка поверх карточек.
   Колонка и так обрезается краем окна — подсказка не нужна. */
body .board-wrap::after { display: none; }

/* ---------- 25. Карточка лида: панель накрывает экран целиком ----------
   Артём, 23.09.2026: «открываешь карточку лида — сверху просто белая полоса
   пикселей на 30». Замер: панель и её затемнение начинались от `--header-h`
   (56 px), то есть шапка оставалась НЕзатемнённой светлой полосой во всю
   ширину над выехавшей панелью.

   Накрываем и шапку: панель — модальный слой, под ней не должно оставаться
   работающих элементов, а полоса сверху перестаёт быть полосой. */
body .side-panel { top: 0; }
body .side-panel__backdrop { inset: 0; }

/* ---------- 26. Скелеты снова мерцают ----------
   Артём, 23.09.2026: «скелет не мигает, он должен быть с анимацией».
   Анимация всё это время шла (sk-slide, 1.4 s) — невидимой её делала палитра:
   `--bg-sunken` и `--surface-hover` в этой теме равны #F0F0F2, и градиент
   переливался из цвета в тот же самый цвет. Замер подтвердил: все три опорные
   точки градиента — rgb(240,240,242).

   Даём блику собственный, чуть более светлый тон и не трогаем базовый цвет
   плашки: скелет должен оставаться спокойным, а не мигать лампочкой. */
body :is(.skeleton__line, .skeleton__block, .sk, .skeleton) {
  --sk-base: #E7E7EC;
  --sk-flash: #FAFAFC;
}
body :is(.skeleton__line, .skeleton__block) {
  background-image: linear-gradient(90deg, var(--sk-base) 0%, var(--sk-flash) 45%,
                                    var(--sk-base) 90%) !important;
  background-size: 200% 100% !important;
  animation: sk-slide 1.25s linear infinite !important;
}
/* Кому движение мешает — остаётся ровная плашка без пульсации. */
@media (prefers-reduced-motion: reduce) {
  body :is(.skeleton__line, .skeleton__block) {
    animation: none !important;
    background-image: none !important;
    background-color: var(--sk-base) !important;
  }
}

/* ---------- 27. Аватарка профиля: только своё фото и кнопка загрузки ----------
   Артём, 24.09.2026: «никакой аватарки другой не будет, только если человек сам
   прикрепил; при наведении — маленькая кнопка загрузить; белый квадрат — тоже
   пиздец полный».

   Пустая плашка больше не белый квадрат: спокойная заливка, плюс по центру,
   по наведению — подпись-подсказка. Фото занимает её целиком. */
body .sb-foot__ava.ava-upload {
  position: relative;
  cursor: pointer;
  background: var(--sp-sink);
  border: 1px dashed var(--sp-line-2);
  transition: border-color .15s ease, background .15s ease;
}
body .sb-foot__ava.ava-upload:hover,
body .sb-foot__ava.ava-upload:focus-visible {
  border-color: var(--sp-accent);
  background: var(--sp-accent-soft);
}
/* Плюс виден, только пока фото нет. */
body .ava-upload__hint {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1; font-weight: 600;
  color: var(--sp-mid); pointer-events: none;
}
body .sb-foot__ava:not(.is-empty) .ava-upload__hint { display: none; }
/* С фотографией рамка не нужна, а по наведению фото чуть гаснет — знак, что
   его можно сменить. */
body .sb-foot__ava.ava-upload:not(.is-empty) { border-style: solid; border-color: transparent; }
body .sb-foot__ava.ava-upload:not(.is-empty):hover .ava__img { opacity: .55; }
body .sb-foot__ava.ava-upload:not(.is-empty):hover::after {
  content: '＋'; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; color: var(--sp-navy);
}
body .sb-foot__ava.is-loading { opacity: .5; pointer-events: none; }
