* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  /* Системный шрифт и табличные цифры везде (ТЗ №66, задача 3): числа в столбцах и плитках не «пляшут». */
  font-family: var(--font-sans);
  background: var(--content-bg);
  color: var(--text-primary);
  font-size: var(--font-size-md);
  line-height: 1.45;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: var(--link); text-decoration: none; }
button { font-family: inherit; font-size: inherit; cursor: pointer; }
input, select, textarea { font-family: inherit; font-size: inherit; }

.shell { display: flex; min-height: 100vh; }

/* Сайдбар */
.sidebar {
  /* 288px, не 240px (ТЗ №31, задача 3.4) — при 240px «Баги и запросы
     функций» не помещалось в одну строку (23 символа + иконка 18px + отступы
     явно больше доступных 212px) и либо переносилось, либо обрезалось.
     Значение подобрано с запасом под самый длинный пункт меню, не под шкалу
     --space-* (та — для внутренних отступов, не для габаритов колонки). */
  width: 288px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  border-right: var(--border-width) solid var(--sidebar-border);
  padding: var(--space-10) var(--space-7);
  display: flex;
  flex-direction: column;
  gap: var(--space-9);
}
.sidebar-logo {
  display: flex;
  align-items: center;
  gap:var(--sp-3);
  padding:0 var(--sp-2) var(--sp-2);
  font-weight: 700;
  font-size:var(--fs-lead);
}
.sidebar-logo .mark {
  width: 28px; height: 28px;
  object-fit: contain;
  flex-shrink: 0;
}
/* Селектор проекта (ТЗ №31, задача 3.3) — визуально отделён от навигации
   снизу подписью и разделителем: это фильтр для всего приложения, а не
   пункт меню, и раньше выглядел как ещё один пункт списка. */
.sidebar-project {
  padding:0 var(--sp-2) var(--sp-3);
  margin-bottom:var(--sp-1);
  border-bottom: 1px solid var(--sidebar-divider);
}
.sidebar-project-label {
  font-size:var(--fs-caption); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--sidebar-text-muted);
  padding:0 var(--sp-2) var(--sp-2);
}
/* Метка экземпляра (ТЗ №42, задача 2) — роль/машина/порт/версия, всегда на
   виду, чтобы ноутбук Claude Code и боевой сервер нельзя было спутать. */
.instance-badge {
  display: flex; flex-direction: column; gap:var(--sp-1);
  padding:0 var(--sp-2) var(--sp-3);
  margin-bottom:var(--sp-1);
}
.instance-badge:empty { display: none; }
.instance-badge .pill { align-self: flex-start; }
.instance-badge-detail { font-size:var(--fs-caption); color: var(--sidebar-text-muted); }
.sidebar-nav { display: flex; flex-direction: column; gap:var(--sp-1); }
/* Группы меню (ТЗ №30, задача 3; ТЗ №31, задача 1.3). С ТЗ №71 (п. 2) заголовок группы — кнопка: нажатие сворачивает
   группу (стрелка поворачивается), закрытая группа прячет пункты, кроме текущего. Выглядит по-прежнему как подпись. */
.sidebar-group { display: flex; flex-direction: column; }
.sidebar-group-header {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: none; border: none; cursor: pointer; text-align: left;
  padding:var(--sp-2) var(--sp-3) var(--sp-1);
  font-size:var(--fs-caption); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--sidebar-text-muted);
  border-radius: var(--r-control);
}
.sidebar-group-header:hover { color: var(--sidebar-text); }
.sidebar-group-header:focus-visible { outline: 2px solid var(--sidebar-active-bg); outline-offset: 1px; }
.sidebar-group-arrow { transition: transform var(--t-base) var(--ease); }
.sidebar-group.closed .sidebar-group-arrow { transform: rotate(-90deg); }
.sidebar-group.closed .sidebar-group-items > .sidebar-link:not(.active) { display: none; }
/* Кнопки-значки меню: «Свернуть меню» и выбор отдела в свёрнутом меню (ТЗ №71, п. 2). */
.sidebar-icon-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; padding: 0; border-radius: var(--r-control);
  background: transparent; border: 1px solid var(--sidebar-divider); color: var(--sidebar-text); cursor: pointer;
}
.sidebar-icon-btn:hover { background: var(--sidebar-hover); }
.sidebar-icon-btn:focus-visible { outline: 2px solid var(--sidebar-active-bg); outline-offset: 1px; }
.sidebar-collapse-btn { margin-left: auto; }
.sidebar-project-compact { display: none; }
.sidebar-group-items { display: flex; flex-direction: column; gap:var(--sp-1); }
.sidebar-link {
  display: flex; align-items: center; gap:var(--sp-3);
  padding:var(--sp-2) var(--sp-3);
  border-radius: var(--r-control);
  color: var(--sidebar-text);
  font-weight: 500;
  fill: var(--sidebar-text-muted);
}
.sidebar-link svg { flex-shrink: 0; }
/* Счётчик у «Системы» (ТЗ №77, п. 6.1): сколько пунктов «Состояния» требуют внимания; только администратору. */
.sidebar-link { position: relative; }
.sidebar-badge {
  margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px; box-sizing: border-box; border-radius: var(--r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--warning-bg); color: var(--warning-text); border: var(--border-width) solid var(--warning-border);
  font-size: var(--fs-12); font-weight: 600; line-height: 1;
}
body.sidebar-collapsed .sidebar-badge { position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px; font-size: var(--fs-12); }
/* Поиск в шапке (ТЗ №47, задача 6) — кнопка в сайдбаре открывает то же окно,
   что и Ctrl+K (components/search_modal.js): не все знают горячую клавишу. */
.sidebar-search-btn {
  display: flex; align-items: center; gap:var(--sp-2);
  width: 100%; margin: var(--sp-2) 0; padding:var(--sp-2) var(--sp-3);
  border: 1px solid var(--sidebar-text-muted); border-radius: var(--radius-md);
  background: transparent; color: var(--sidebar-text-muted); font-size:var(--fs-caption); font-weight: 500;
  opacity: 0.75;
}
.sidebar-search-btn:hover { opacity: 1; }
.sidebar-search-btn span { flex: 1; text-align: left; }
.sidebar-search-btn kbd { font-family: inherit; font-size:var(--fs-caption); border: 1px solid currentColor; border-radius: var(--radius); padding: 0 var(--sp-1); }
/* Текст пункта — одна строка (ТЗ №31, задача 3.4): не переносится (см.
   ширину .sidebar выше) и не обрезается — text-overflow сюда специально не
   добавлен, обрезка запрещена явно тем же пунктом ТЗ. */
.sidebar-link span { white-space: nowrap; }
/* Три явно разных состояния (ТЗ №31, задача 3.1): обычный — без подложки;
   наведённый — слабая подложка; активный — сплошная белая, заметно сильнее
   наведённого, и он единственный на экране (класс .active ставится только
   на текущий пункт в renderSidebar). */
.sidebar-link.active {
  background: var(--sidebar-active-bg);
  color: var(--sidebar-active-text);
  fill: var(--sidebar-active-text);
}
.sidebar-link:not(.active):hover { background: var(--sidebar-hover); }
.sidebar-user {
  margin-top: auto;
  padding:var(--sp-3) var(--sp-3);
  border-top: 1px solid var(--sidebar-divider);
}
.sidebar-user:empty { display: none; border-top: none; padding: 0; }
.sidebar-user-name { font-weight: 600; color: var(--sidebar-active-text); font-size:var(--fs-body); }
.sidebar-user-role { color: var(--sidebar-text-muted); font-size:var(--fs-caption); margin-top:var(--sp-1); }

/* Свёрнутое меню (ТЗ №71, п. 2) — только на широком экране: узкая полоса со значками, название пункта — подсказкой
   (title) и для экранного диктора (текст спрятан, но читается). Текущий пункт подсвечен и здесь. */
@media (min-width: 721px) {
  body.sidebar-collapsed .sidebar { width: 64px; padding: var(--space-10) var(--sp-2); gap: var(--sp-4); align-items: center; }
  body.sidebar-collapsed .sidebar-logo { flex-direction: column; padding: 0; gap: var(--sp-2); }
  body.sidebar-collapsed .sidebar-logo #sidebar-company-name,
  body.sidebar-collapsed .sidebar-logo .mark,
  body.sidebar-collapsed .instance-badge-detail,
  body.sidebar-collapsed .sidebar-user,
  body.sidebar-collapsed .sidebar-group-header { display: none; }
  body.sidebar-collapsed .sidebar-collapse-btn { margin-left: 0; }
  body.sidebar-collapsed .instance-badge { padding: 0; align-items: center; }
  body.sidebar-collapsed .instance-badge .pill { max-width: 48px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  body.sidebar-collapsed #sidebar-project { padding: 0; border-bottom: none; margin: 0; }
  body.sidebar-collapsed #sidebar-project > :not(.sidebar-project-compact) { display: none; }
  body.sidebar-collapsed .sidebar-project-compact { display: flex; justify-content: center; }
  body.sidebar-collapsed .sidebar-project-compact .dept-picker-pop { left: 40px; top: 0; }
  body.sidebar-collapsed .sidebar-search-btn { width: 40px; justify-content: center; padding: var(--sp-2); }
  body.sidebar-collapsed .sidebar-search-btn span,
  body.sidebar-collapsed .sidebar-search-btn kbd { display: none; }
  body.sidebar-collapsed .sidebar-nav { width: 100%; }
  body.sidebar-collapsed .sidebar-group + .sidebar-group { border-top: 1px solid var(--sidebar-divider); padding-top: var(--sp-2); margin-top: var(--sp-1); }
  body.sidebar-collapsed .sidebar-link { justify-content: center; padding: var(--sp-2); }
  body.sidebar-collapsed .sidebar-link span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
@media (max-width: 720px) {
  .sidebar-collapse-btn { display: none; }
}

/* Контент */
.content {
  /* ТЗ №83, п. 1.1: содержимое не шире 1 200 px и по центру свободного места (свободное место справа от меню делят
     автоматические поля), поля 24 px; на телефоне — 16 px (ниже, @media 720). */
  flex: 1 1 auto; min-width: 0; width: 100%; max-width: calc(var(--page-max) + 2 * var(--page-pad)); margin-inline: auto;
  padding: var(--gap-blocks) var(--page-pad) var(--gap-sections);
}
.topbar {
  display: flex; align-items: flex-start; justify-content: space-between;
  margin-bottom: var(--gap-blocks); gap: var(--gap-in); flex-wrap: wrap;
}
.page-title { font-size: var(--fs-24); font-weight: 600; margin: 0; }
.page-subtitle { font-size: var(--font-size-base); color: var(--text-secondary); margin:var(--sp-1) 0 0; }
/* Сведение о странице под названием — неделя, период, оператор (данные, а не пояснение; пояснения теперь в «?», ТЗ №77, п. 6.1). */
.page-context { font-size: var(--font-size-base); color: var(--text-secondary); margin: var(--sp-1) 0 0; }

/* Блок «О звонке» в шапке карточки (ТЗ №44, задача 1): компактная сетка, на
   телефоне — в столбик. minmax(0, …) не даёт длинному значению растянуть
   страницу вбок (никакой горизонтальной прокрутки). */
/* Левая часть шапки карточки забирает всю свободную ширину — иначе она
   сжимается по содержимому, и сетка «О звонке» превращается в одну колонку. */
.call-head { flex: 1 1 560px; min-width: 0; }
.call-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--sp-3) var(--sp-6); margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); background: var(--tile-bg); border-radius: var(--radius-md);
  color: var(--text-primary);
}
.call-fact { min-width: 0; overflow-wrap: anywhere; }
.call-fact-label { font-size: var(--fs-caption); color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em; }
.call-fact-value { font-size: var(--fs-body); font-weight: 600; margin-top: 2px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); }
.call-fact-value .muted, .call-fact-value .btn { font-weight: 400; }
.call-fact-link { font-weight: 400; }
.call-fact-form { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
.call-fact-form .login-error { flex-basis: 100%; margin-top: 0; min-height: 0; }
@media (max-width: 640px) {
  .call-facts { grid-template-columns: minmax(0, 1fr); }
}

/* Фильтры-пилюли */
.filter-row { display: flex; align-items: center; gap:var(--sp-2); flex-wrap: wrap; margin-bottom:var(--sp-4); }
.filter-btn {
  display: inline-flex; align-items: center; gap:var(--sp-2);
  background: var(--btn-secondary-bg);
  border: 1px solid var(--btn-secondary-border);
  border-radius: var(--radius-pill);
  padding:var(--sp-2) var(--sp-4);
  font-weight: 500;
  color: var(--text-primary);
}
.filter-btn .label { color: var(--text-tertiary); font-weight: 400; margin-right:var(--sp-1); }
.filter-btn.active { background: var(--btn-primary-bg); color: var(--btn-primary-text); border-color: var(--btn-primary-bg); }
select.filter-select,
input.filter-select,
label.filter-select {
  border: 1px solid var(--btn-secondary-border);
  border-radius: var(--radius-pill);
  padding:var(--sp-2) var(--sp-3);
  background: var(--card-bg);
  color: var(--text-primary);
  font-weight: 500;
  font-family: inherit;
  font-size:var(--fs-body);
}
/* Чекбокс-фильтр «только с красными флагами» (ТЗ №47, задача 4) — та же
   пилюля, что у остальных фильтров, а не голый текст с квадратиком. */
label.filter-select { user-select: none; white-space: nowrap; }
input.filter-select::placeholder { color: var(--text-tertiary); font-weight: 400; }
/* Триггер для скрытого нативного <input type="date"> — выглядит как остальные пилюли-фильтры. */
.filter-date-wrap { position: relative; display: inline-flex; }
.filter-date-wrap input[type="date"] {
  position: absolute; inset: 0; opacity: 0; width: 100%; cursor: pointer;
}

/* Атрибут hidden должен скрывать и элементы с классом, задающим display
   (.btn — inline-flex, панель фильтров на телефоне — flex): без этого
   правило браузера по умолчанию проигрывает любому классу. */
[hidden] { display: none !important; }

/* Единая панель фильтров (ТЗ №49, задача 1). Главная строка (период, отдел,
   поиск, кнопка «Фильтры») — тот же .filter-row, что и раньше; здесь —
   всплывающая панель второстепенных фильтров и строка «таблеток». */
/* Панель прилипает к верху при прокрутке списка (ТЗ №49, задача 1.1): фон — чтобы строки списка
   не просвечивали под ней; z-index выше «липкой» шапки таблиц. «Таблетки» — отдельным блоком
   сразу под ней (components/filters.js переносит их при подключении). */
.filters-bar {
  position: sticky; top: 0; z-index: 30;
  background: var(--content-bg); padding: var(--sp-2) 0; margin-bottom: var(--sp-2);
}
.filters-bar + .filter-pills { margin: 0 0 var(--sp-4); }
.filter-pills:empty { display: none; }
@media (max-width: 720px) {
  /* Телефон (ТЗ №49, задача 1.2): главные фильтры — одна строка, лишнее прокручивается вбок внутри
     неё (страница вбок не ездит). Панель прилипает ниже кнопки меню — та закреплена сверху слева. */
  .filters-bar {
    top: 60px; flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    padding: var(--sp-1) var(--sp-1) var(--sp-2); margin: 0 calc(-1 * var(--sp-1)) var(--sp-2);
  }
  .filters-bar > *, .filters-bar .filters-saved { flex: none; }
  /* «Фильтры · N» — первым: в строке с прокруткой вбок кнопка в конце была бы за краем экрана. */
  .filters-bar #filters-open-btn { order: -2; }
  .filters-bar .period-picker { order: -1; }
  .filters-bar .filters-saved { flex-wrap: nowrap; }
  .filters-bar .filters-search { width: 230px; }
}
.filters-saved { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; }
/* Поиск: подсказка «Оператор, клиент или ID» видна целиком (ТЗ №54, задача 2). */
.filters-search { width: 26ch; max-width: 100%; }
/* «Фильтры · N ▾» / «Скрыть фильтры ▴» — переключатель раскрытой панели (ТЗ №54). */
.filters-toggle-arrow { margin-left: var(--sp-1); font-size: var(--fs-12); }
/* Раскрытая панель — на странице, под строкой фильтров (не окно и не поверх списка: список
   сдвигается вниз). Сеткой: 4 колонки на широком экране, 3 — на 1024, 1 — на телефоне. */
.filters-panel {
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius-md);
  padding: var(--sp-4); margin: 0 0 var(--sp-3);
}
.filters-panel[hidden] { display: none; }
.filters-panel-body { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-4); align-items: end; }
@media (max-width: 1200px) { .filters-panel-body { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.filters-field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.filters-field .filter-select { width: 100%; }
.filters-field-checkbox { display: flex; align-items: center; gap: var(--sp-2); cursor: pointer; user-select: none; min-height: 36px; }
.filters-range { display: flex; align-items: center; gap: var(--sp-2); }
.filters-range input { width: 100%; min-width: 0; }
.filters-panel-footer { display: flex; justify-content: flex-end; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); }
/* Панель раскрыта — «Сбросить всё» уже внизу панели, второй такой же в строке таблеток не нужен. */
.filters-panel:not([hidden]) + .filter-pills #filters-reset-all { display: none; }
.btn-icon { background: none; border: none; font-size: var(--fs-lead); line-height: 1; cursor: pointer; color: var(--text-tertiary); padding: var(--sp-1); min-width: 32px; min-height: 32px; }
.btn-link { background: none; border: 1px solid transparent; color: var(--link); padding: 0 var(--sp-2); }
.btn-link:hover:not(:disabled) { text-decoration: underline; }
/* Число-кнопка в таблицах KPI (ТЗ №61): нажатие показывает, из каких событий сложился балл. */
.kpi-num { background: none; border: 0; padding: 0; font: inherit; color: var(--link); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; }
.kpi-num:hover { text-decoration-style: solid; }

.filter-pills { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.filter-pill {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  background: var(--info-bg); color: var(--info-text);
  border-radius: var(--radius-pill); padding: 3px var(--sp-2) 3px var(--sp-3);
  font-size: var(--font-size-sm); font-weight: 600;
}
.filter-pill button { background: none; border: none; color: inherit; cursor: pointer; font-size: var(--fs-caption); padding: 0 var(--sp-1); }

@media (max-width: 720px) {
  /* Телефон (ТЗ №54, задача 2): панель тоже на странице, поля в одну колонку. */
  .filters-panel { padding: var(--sp-3); }
  .filters-panel-body { grid-template-columns: 1fr; }
}

/* Единый выбор периода (ТЗ №47, задача 1) */
.period-picker { position: relative; display: inline-flex; }
.period-kbd-help {
  position: absolute; top:var(--sp-2); right:var(--sp-2); width: 20px; height: 20px; border-radius: var(--r-pill);
  border: 1px solid var(--card-border); background: var(--tile-bg); color: var(--text-tertiary);
  font-size:var(--fs-caption); line-height: 18px; cursor: help; padding: 0;
}
.period-popover {
  position: absolute; z-index: 20; top: 40px; left: 0;
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius-md);
  box-shadow: var(--shadow); padding:var(--sp-4); min-width: 620px;
}
.period-popover-body { display: flex; gap:var(--sp-5); }
.period-quick { display: flex; flex-direction: column; gap:var(--sp-1); min-width: 160px; border-right: 1px solid var(--card-border); padding-right:var(--sp-4); }
.period-quick-item {
  text-align: left; border: none; background: none; border-radius: var(--radius-sm);
  padding:var(--sp-2) var(--sp-3); font-size:var(--fs-body); color: var(--text-primary); cursor: pointer;
}
.period-quick-item:hover { background: var(--tile-bg); }
.period-quick-item.active { background: var(--btn-primary-bg); color: var(--btn-primary-text); }
.period-calendar { flex: 1; min-width: 0; }
.period-calendar-nav { display: flex; align-items: center; }
.period-calendar-months { display: flex; gap:var(--sp-5); flex: 1; justify-content: center; }
.period-nav-btn {
  border: 1px solid var(--card-border); background: var(--card-bg); border-radius: var(--r-pill);
  width: 28px; height: 28px; line-height: 26px; text-align: center; cursor: pointer; color: var(--text-primary); flex: none;
}
.period-month { width: 224px; }
.period-month-title { text-align: center; font-weight: 600; margin-bottom:var(--sp-2); color: var(--text-primary); }
.period-weekdays, .period-days { display: grid; grid-template-columns: repeat(7, 1fr); }
.period-weekday { text-align: center; font-size:var(--fs-caption); color: var(--text-tertiary); padding:var(--sp-1) 0; }
.period-day {
  border: none; background: none; border-radius: var(--radius-sm); aspect-ratio: 1; font-size:var(--fs-body);
  color: var(--text-primary); cursor: pointer; margin: 1px;
}
.period-day-empty { cursor: default; }
.period-day:hover:not(:disabled) { background: var(--tile-bg); }
.period-day-today { font-weight: 700; box-shadow: inset 0 0 0 1px var(--brand-primary); }
.period-day-disabled { color: var(--card-border); cursor: not-allowed; }
.period-day-in-range { background: var(--info-bg); border-radius: 0; }
.period-day-start, .period-day-end { background: var(--btn-primary-bg); color: var(--btn-primary-text); }
.period-day:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.period-actions { display: flex; justify-content: flex-end; gap:var(--sp-2); margin-top:var(--sp-4); }
@media (max-width: 720px) {
  /* position: fixed относительно вьюпорта, а не кнопки: на узком экране кнопка может стоять где
     угодно в строке фильтров, и попап, растущий от неё вбок (position: absolute), почти всегда
     упёрся бы в правый край. От вьюпорта расстояние до краёв всегда одинаковое. */
  .period-popover { position: fixed; min-width: 0; left:var(--sp-3); right:var(--sp-3); top: 64px; max-height: 80vh; overflow-y: auto; }
  .period-popover-body { flex-direction: column; }
  .period-quick { flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--card-border); padding-right: 0; padding-bottom:var(--sp-2); }
  .period-calendar-months > .period-month:last-child { display: none; }
  .period-calendar-months { justify-content: center; }
  .period-month { width: 100%; max-width: 280px; }
}

/* Фильтр «Отдел» на страницах (ТЗ №71, п. 1а) — общий выбор «Компания · Отдел», несколько отделов по компаниям. */
.dept-picker { position: relative; display: inline-flex; }
.dept-picker-value { max-width: 28ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dept-picker-pop {
  position: absolute; z-index: 20; top: 40px; left: 0; min-width: 300px; max-width: 420px; max-height: 60vh; overflow-y: auto;
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius-md); box-shadow: var(--shadow);
  padding: var(--sp-3) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2);
}
.dept-picker-pop[hidden] { display: none; }
.dept-picker-org { border: none; margin: 0; padding: 0 0 0 var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-1); }
.dept-picker-org legend { padding: 0; margin-left: calc(-1 * var(--sp-3)); }
.dept-picker .check-row { display: flex; align-items: center; gap: var(--sp-2); min-height: 32px; cursor: pointer; }
.dept-picker-error { color: var(--error); font-size: var(--font-size-sm); }
.dept-picker-error:empty { display: none; }
.dept-picker-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }
@media (max-width: 720px) {
  /* Телефон: как у выбора периода — от краёв экрана, а не от кнопки в строке с прокруткой вбок. */
  .dept-picker-pop { position: fixed; left: var(--sp-3); right: var(--sp-3); top: 64px; min-width: 0; max-width: none; max-height: 80vh; }
  .dept-picker-value { max-width: 16ch; }
}

/* Фильтры «Команды» (ТЗ №71, п. 1): поиск, выборы, счётчик «показано 12 из 47», «Сбросить»; сортировка заголовками. */
.team-filters { margin-bottom: var(--sp-3); }
.team-filter-search { width: 26ch; max-width: 100%; }
.team-filter-count { color: var(--text-secondary); font-size: var(--font-size-sm); margin-left: auto; }
.th-sort { background: none; border: none; padding: 0; font: inherit; color: inherit; cursor: pointer; text-align: inherit; }
.th-sort:hover { color: var(--link); }
.th-sort:focus-visible { outline: 2px solid var(--focus-ring, var(--link)); outline-offset: 2px; border-radius: var(--radius-sm); }
.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (max-width: 720px) {
  .team-filters { flex-wrap: wrap; }
  .team-filter-search { width: 100%; }
  .team-filter-count { margin-left: 0; width: 100%; }
}

/* «Хлебные крошки» на вложенных экранах (ТЗ №49, задача 4) — components/breadcrumbs.js. */
.breadcrumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); list-style: none; margin: 0 0 var(--sp-2); padding: 0; font-size: var(--fs-caption); color: var(--text-secondary); }
.breadcrumbs li + li::before { content: "→"; margin-right: var(--sp-1); color: var(--text-tertiary); }
.breadcrumbs a { color: var(--link); text-decoration: none; }
.breadcrumbs a:hover { text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--text-primary); font-weight: 600; overflow-wrap: anywhere; }
@media (max-width: 720px) { .breadcrumbs a { display: inline-flex; align-items: center; min-height: 44px; } }

/* Карточки */
.card {
  background: var(--card-bg);
  border: var(--border-width) solid var(--card-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  padding: var(--gap-in);
  margin-bottom: var(--gap-blocks);
}
.card-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--gap-in); gap: var(--gap-in); flex-wrap: wrap;
}
.card-title { font-size: var(--font-size-lg); font-weight: 700; margin: 0; }
.card-toolbar { display: flex; gap: var(--space-4); flex-wrap: wrap; }

/* KPI-плитки */
.tile-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-6); }
.tile { background: var(--tile-bg); border-radius: var(--radius-md); padding: var(--space-7); }
.tile-head { display: flex; align-items: center; gap: var(--space-4); color: var(--text-secondary); font-weight: 600; font-size: var(--font-size-base); margin-bottom: var(--space-5); }
.tile-icon { width: 26px; height: 26px; border-radius: var(--r-pill); background: var(--card-bg); display: flex; align-items: center; justify-content: center; }
.tile-value { font-size: var(--fs-28); font-weight: 600; margin-bottom: var(--sp-2); }
.tile-progress { height: 6px; border-radius: var(--r-pill); background: var(--card-border); overflow: hidden; margin-bottom: var(--space-3); }
.tile-progress > div { height: 100%; background: var(--success); }
.tile-foot { display: flex; justify-content: space-between; font-size: var(--font-size-sm); color: var(--text-tertiary); }

/* Кнопки (ТЗ №49, задача 3) — один набор: .btn (второстепенная), .btn-primary (основная),
   .btn-danger (опасная, красная), .btn-link (кнопка-ссылка). Одна высота, шрифт, радиус и отступы
   у всех; на телефоне — не ниже 44 px (правило ниже, @media max-width: 720px). */
.btn, .btn-link {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--btn-height);
  border-radius: var(--radius);
  padding: 0 var(--sp-4);
  font: inherit; font-size: var(--fs-body); font-weight: 600; line-height: 1.2;
  cursor: pointer; text-decoration: none;
}
.btn {
  border: var(--border-width) solid var(--btn-secondary-border);
  background: var(--btn-secondary-bg);
  color: var(--text-primary);
}
.btn:hover:not(:disabled) { background: var(--tile-bg); }
.btn-primary { background: var(--btn-primary-bg); color: var(--btn-primary-text); border-color: var(--btn-primary-bg); }
.btn-primary:hover:not(:disabled) { background: var(--btn-primary-bg); filter: brightness(1.15); }
/* Опасное действие (ТЗ №49, задача 3): удалить, сбросить, исключить — красным, одним классом
   вместо ручных style="color:…;border-color:…" по страницам. Белый текст на --error-text —
   тот же контраст, что проверяет webapp/lib/contrast.test.js. */
.btn-danger { background: var(--error-text); color: var(--btn-primary-text); border-color: var(--error-text); }
.btn-danger:hover:not(:disabled) { background: var(--error-text); filter: brightness(1.1); }
.dialog-message { margin: var(--sp-2) 0 0; color: var(--text-secondary); white-space: pre-line; }
.btn:disabled, .btn-link:disabled { opacity: 0.5; cursor: default; }
/* «В работе» (components/busy.js): крутилка на месте начала надписи, повторно не нажать. */
.btn[aria-busy="true"], .btn-link[aria-busy="true"] { opacity: 0.7; cursor: progress; }
.btn[aria-busy="true"]::before, .btn-link[aria-busy="true"]::before {
  content: ""; width: 14px; height: 14px; flex: none; border-radius: var(--r-pill);
  border: 2px solid currentColor; border-right-color: transparent;
  animation: btn-spin var(--t-spin) linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Таблица */
table.data-table { width: 100%; border-collapse: collapse; font-size:var(--fs-body); }
/* Шапка таблицы остаётся на месте при прокрутке (ТЗ №49, задача 2): у таблиц в прокручиваемой
   обёртке (.table-scroll, .calls-table-wrap) — вверху обёртки, у остальных — вверху окна. */
.data-table th {
  text-align: left; font-weight: 600; color: var(--text-secondary);
  padding:var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--card-border);
  white-space: nowrap; user-select: none;
  position: sticky; top: 0; z-index: 2; background: var(--card-bg);
}
.data-table th[data-sort-key] { cursor: pointer; }
.data-table th[data-sort-key]:hover { color: var(--text-primary); }
/* Моноширинные (табличные) цифры — только там, где числа выстраиваются в
   столбец: строки таблиц (ТЗ №30, задача 4.6). Не применяется к крупным
   отдельным числам (.tile-value, .page-title) — те остаются обычными
   пропорциональными цифрами. */
.data-table td { padding:var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--card-border); vertical-align: middle; font-variant-numeric: tabular-nums; }
.data-table tbody tr { cursor: pointer; }
/* «Зебра» (ТЗ №49, задача 2) — чуть светлее серого «не оценивается», чтобы не спутать с ним. */
.data-table tbody tr:nth-child(even) { background: var(--row-alt-bg); }
.data-table tbody tr:hover { background: var(--tile-bg); }
.data-table tbody tr.row-empty, .data-table tbody tr.row-empty:hover { background: none; cursor: default; }
/* Звонок отдела без оценки (ТЗ №66, задача 2) — строка журнала без карточки: не кликается. */
.data-table tbody tr.row-not-evaluated { cursor: default; color: var(--text-secondary); }
.data-table tbody tr.row-needs-review { background: var(--row-review-bg); }
.data-table tbody tr.row-needs-review:hover { background: var(--row-review-hover); }
/* Исключённые из оценки (задача 2 ТЗ №9) — не прячутся, но приглушены,
   чтобы отличаться от обычных строк на глаз, не только по тексту колонки
   "Учёт". Нейтральный серый, не пересекается по цвету с row-needs-review
   (жёлтый) — обе подсветки не должны читаться как одно и то же. */
.data-table tbody tr.row-excluded { background: var(--row-muted-bg); color: var(--text-tertiary); }
.data-table tbody tr.row-excluded:hover { background: var(--row-muted-hover); }
.col-select { width: 34px; padding-right: 0 !important; }
/* Номер клиента (ТЗ №44) не переносится по строкам, а поле поиска — «оператор, клиент или ID» — не ужимается до обрезанной подсказки. */
td.col-client_number { white-space: nowrap; }
#f-operator { flex: 1 1 260px; min-width: 240px; max-width: 360px; }
.col-select input[type="checkbox"] { cursor: pointer; }
/* Строка списка как настоящая ссылка (ТЗ №15, задача 1) — растянутая
   ссылка внутри первой ячейки перекрывает всю строку через position:
   absolute относительно tr, поэтому работают средняя кнопка мыши и
   "Открыть в новой вкладке". Интерактивные элементы в других ячейках той
   же строки (чекбокс, кнопка "Исключить") должны быть выше по z-index —
   см. .row-select-checkbox/.candidate-exclude-btn. */
.data-table tbody tr[data-uuid] { position: relative; }
.row-link-cover { position: absolute; inset: 0; z-index: 0; }
/* position:relative (без явного z-index) достаточно: растянутая ссылка
   лежит в первой ячейке строки, эти элементы — в ячейках после неё, а
   позиционированные соседи без z-index рисуются в порядке DOM, то есть
   поверх неё. Так наведение (title-подсказки) и клики по чекбоксу/кнопке/
   пилюлям/точкам P1-P4 продолжают работать, а не перехватываются ссылкой. */
.row-select-checkbox, .candidate-exclude-btn, .pill, .dot, .candidate-hint { position: relative; }
.sort-arrow { font-size:var(--fs-caption); color: var(--text-tertiary); margin-left:var(--sp-1); }

/* Легенда подсветки строк (над таблицей "Звонки") */
.legend-needs-review { background: var(--row-review-bg); border: 1px solid var(--row-review-border); }
.legend-excluded { background: var(--row-muted-bg); border: 1px solid var(--card-border); }

/* Панель массового действия (задача 2 ТЗ №9) */
.bulk-toolbar { display: flex; align-items: center; gap:var(--sp-3); padding:var(--sp-3) 0; font-size:var(--fs-body); }
.bulk-toolbar #bulk-count { font-weight: 600; color: var(--text-secondary); margin-right:var(--sp-1); }
.bulk-toolbar select { width: auto; }
/* Решение AI (не человека) — контурная метка: полупрозрачная была ниже контраста AA (ТЗ №66, задача 6). */
.pill-ai-decision { background: transparent; box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 45%, transparent); }

/* Подсказка-кандидат на исключение (задача 4 ТЗ №9) — под пилюлей "Учёт",
   не вместо неё: подсказка ничего не решает сама. */
.candidate-hint { display: flex; align-items: center; gap:var(--sp-2); margin-top:var(--sp-1); font-size:var(--fs-caption); color: var(--warning); }
.candidate-exclude-btn {
  border: 1px solid var(--warning); background: var(--warning-bg); color: var(--warning);
  border-radius: var(--radius-sm); padding:var(--sp-1) var(--sp-2); font-size:var(--fs-caption); cursor: pointer;
}
.candidate-exclude-btn:hover { background: var(--warning); color: var(--on-warning); }
.candidate-exclude-btn:disabled { opacity: 0.5; cursor: default; }

/* Красный флаг в карточке звонка (ТЗ №35, задача 1.4) — самый тревожный
   цвет существующей шкалы, не новый. */
.red-flag-banner { border-color: var(--error); border-width: 2px; background: var(--error-bg); }
.red-flag-item { padding:var(--sp-2) 0; cursor: pointer; }
.red-flag-item + .red-flag-item { border-top: 1px solid var(--card-border); }

/* Пилюли статусов */
.pill { display: inline-flex; align-items: center; padding: 3px var(--space-5); border-radius: var(--radius-pill); font-weight: 600; font-size: var(--font-size-sm); }
.pill-blue { background: var(--info-bg); color: var(--info-text); }
.pill-green { background: var(--success-bg); color: var(--success-text); }
.pill-red { background: var(--error-bg); color: var(--error-text); }
.pill-amber { background: var(--warning-bg); color: var(--warning-text); }
.pill-amber-outline { background: var(--card-bg); color: var(--warning-text); border: 1px solid var(--warning); }
.pill-gray { background: var(--tile-bg); color: var(--text-secondary); }
.pill-xs { padding:var(--sp-1) var(--sp-2); font-size:var(--fs-caption); }
.review-pills { display: flex; gap:var(--sp-1); flex-wrap: wrap; }

.dot { display: inline-block; width: 9px; height: 9px; border-radius: var(--r-pill); box-sizing: border-box; flex-shrink: 0; }
.dot-green { background: var(--success); }
.dot-red { background: var(--error); }
.dot-gray { background: var(--dot-gray); }
/* Низкая уверенность модели (confidence, ТЗ №6) — контур того же цвета
   вместо заливки, без отдельной легенды (задача 6 ТЗ №9). */
.dot.dot-outline { background: transparent; }
.dot.dot-outline.dot-green { border: 2px solid var(--success); }
.dot.dot-outline.dot-red { border: 2px solid var(--error); }
.dot.dot-outline.dot-gray { border: 2px solid var(--dot-gray); }

/* Колонка P1–P4 (задача 6 ТЗ №9): четыре точки всегда в один ряд, ширина
   колонки фиксирована под них — раньше при недостатке места точки
   переносились на вторую строку, и высота строк таблицы прыгала. */
.principle-dots { display: inline-flex; align-items: center; gap:var(--sp-2); white-space: nowrap; }
th.col-principles, td.col-principles { width: 74px; min-width: 74px; white-space: nowrap; }

/* Пагинация */
.pagination { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-top:var(--sp-4); font-size:var(--fs-body); color: var(--text-secondary); }
/* Список обновляется (фильтры, сортировка) — прежние строки видны, но бледнее. */
#calls-list-card[aria-busy="true"] .calls-table-wrap, #calls-list-card[aria-busy="true"] .calls-cards { opacity: 0.6; transition: opacity var(--t-base) var(--ease); }

.empty-state { text-align: center; color: var(--text-tertiary); padding:var(--sp-6) var(--sp-3); }
/* Мало данных — приглушённый текст вместо полупрозрачной строки (та была ниже контраста AA, ТЗ №66, задача 6). */
.row-low-sample > td { color: var(--text-tertiary); }
.empty-state-text { margin: 0 0 var(--sp-3); }
.empty-state-text:last-child { margin-bottom: 0; }

/* Обновление без мигания (ТЗ №30, задача 4.3) — при повторной загрузке
   (смена фильтра) удерживаем ПРЕДЫДУЩЕЕ содержимое с пониженной
   прозрачностью вместо скелетона/пустой надписи "Загрузка…": скелетон,
   подменяющий содержимое, даёт скачок вёрстки. Применяется только когда
   уже есть что удерживать — на самой первой загрузке страницы дублировать
   нечего, там остаётся обычная надпись "Загрузка…". */
.is-loading { opacity: 0.5; transition: opacity var(--t-base) var(--ease); pointer-events: none; }

/* Страница звонка */
/* Прилипает к верху при прокрутке длинного транскрипта (ТЗ №47, задача 3): плеер и перемотка должны
   оставаться под рукой, не нужно листать наверх карточки. position: sticky, а не fixed — плеер уходит
   вместе со страницей при переходе на другой звонок, а не зависает поверх нового содержимого; top: 0
   годится, потому что шапка (.topbar) сама не прилипает. */
.player-card { padding:var(--sp-4) var(--sp-5); position: sticky; top: 0; z-index: 5; background: var(--content-bg); box-shadow: var(--shadow); }
.player-controls { display: flex; align-items: center; gap:var(--sp-4); }
.player-play {
  width: 40px; height: 40px; border-radius: var(--r-pill); background: var(--btn-primary-bg); color: var(--btn-primary-text);
  display: flex; align-items: center; justify-content: center; border: none; flex-shrink: 0;
}
.player-progress { flex: 1; height: 6px; background: var(--card-border); border-radius: var(--r-pill); position: relative; cursor: pointer; }
.player-progress > #progress-fill { height: 100%; background: var(--btn-primary-bg); border-radius: var(--r-pill); }
#progress-ticks { position: absolute; inset: 0; pointer-events: none; }
.progress-tick { position: absolute; top: -3px; width: 3px; height: 12px; border-radius:var(--radius); transform: translateX(-50%); pointer-events: auto; cursor: pointer; }
.tick-mark { background: var(--error); }
.tick-evidence { background: var(--info); }
.tick-issue { background: var(--warning); }

.mark-row { display: flex; align-items: center; gap:var(--sp-2); padding:var(--sp-2) 0; border-bottom: 1px solid var(--card-border); cursor: pointer; font-size:var(--fs-body); }
.mark-row:last-child { border-bottom: none; }
.mark-comment-text { flex: 1; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mark-delete-btn { border: none; background: none; color: var(--text-tertiary); padding:var(--sp-1) var(--sp-2); cursor: pointer; }
.mark-delete-btn:hover { color: var(--error); }
.player-time { font-variant-numeric: tabular-nums; color: var(--text-secondary); font-size:var(--fs-caption); width: 90px; text-align: right; }
.player-seek-btn { padding:var(--sp-2) var(--sp-3); font-size:var(--fs-caption); flex-shrink: 0; }
#speed-select { flex-shrink: 0; width: auto; }
#hotkey-help-btn { width: 32px; padding:var(--sp-2) 0; flex-shrink: 0; }

.player-controls-secondary { display: flex; align-items: center; gap:var(--sp-5); flex-wrap: wrap; margin-top:var(--sp-3); font-size:var(--fs-caption); color: var(--text-secondary); }
.player-slider-label { display: flex; align-items: center; gap:var(--sp-2); }
.client-calls-counter { margin: 0 0 var(--sp-3); font-size: var(--fs-lead); font-weight: 600; }
#client-calls .card { margin-top: var(--sp-4); }
.download-unavailable { display: inline-flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.player-card-no-recording .player-controls { opacity: .45; pointer-events: none; }
.recording-missing { margin-top: var(--sp-3); color: var(--text-secondary); font-size: var(--fs-body); }
.player-slider-label input[type="range"] { width: 110px; }

.resume-hint-bar {
  display: flex; align-items: center; gap:var(--sp-3); margin-top:var(--sp-3);
  padding:var(--sp-2) var(--sp-3); background: var(--tile-bg); border-radius: var(--radius-md); font-size:var(--fs-body);
}

.review-layout { display: grid; grid-template-columns: 1.4fr 1fr; gap:var(--sp-4); align-items: start; }
/* Два столбца — только на широком экране (ТЗ №83, п. 2.3: плееру и расшифровке нужно не меньше 440 px), ниже — один, оценка первой. */
@media (max-width: 1180px) { .review-layout { grid-template-columns: 1fr; } }

/* Вкладки переносятся на любой ширине (ТЗ №39, задача 5): у «Настроек» их
   шесть, и на среднем экране строка из них уезжала за край — вместе со всей
   страницей. Перенос был только на телефоне. */
.source-tabs { display: flex; gap:var(--sp-2); margin-bottom:var(--sp-3); flex-wrap: wrap; }
.source-tab { padding:var(--sp-2) var(--sp-3); border-radius: var(--radius-pill); border: 1px solid var(--btn-secondary-border); font-weight: 600; color: var(--text-secondary); }
.source-tab.active { background: var(--btn-primary-bg); color: var(--btn-primary-text); border-color: var(--btn-primary-bg); }

/* Кнопки в ячейке таблицы (ТЗ №39, задача 5). Раньше стояло
   white-space:nowrap прямо в разметке: на большом экране кнопки держались в
   строку, а на телефоне, где таблица превращается в карточки, эта же строка
   уезжала за край экрана вместе со страницей. Перенос решает оба случая: где
   есть место — одна строка, где нет — две. */
.cell-actions { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.source-tab:disabled { opacity: 0.35; cursor: default; }

.transcript-toolbar { display: flex; align-items: center; justify-content: space-between; gap:var(--sp-3); margin-bottom:var(--sp-2); font-size:var(--fs-caption); color: var(--text-tertiary); }
.follow-toggle { display: flex; align-items: center; gap:var(--sp-2); cursor: pointer; user-select: none; }

/* Высота выставляется динамически в JS (webapp/public/js/pages/call.js) —
   тянется до низа окна браузера, с отступом ~24px. min-height — страховка
   на случай, если JS ещё не отработал, и пол для маленьких экранов. */
.transcript { display: flex; flex-direction: column; gap:var(--sp-3); min-height: 400px; overflow-y: auto; padding-right:var(--sp-1); }
.transcript-line { padding:var(--sp-3) var(--sp-3); border-radius: var(--radius-md); background: var(--tile-bg); }
.transcript-line.speaker-operator { background: var(--speaker-operator-bg); }
.transcript-line.speaker-client { background: var(--speaker-client-bg); }
.transcript-line.highlight { outline: 2px solid var(--info); }
.transcript-speaker { font-size:var(--fs-caption); font-weight: 700; text-transform: uppercase; color: var(--text-tertiary); margin-bottom:var(--sp-1); }
.transcript-line.speaker-operator .transcript-speaker { color: var(--info-text); }
.transcript-time { font-variant-numeric: tabular-nums; color: var(--text-tertiary); font-size:var(--fs-caption); cursor: pointer; }
.transcript-line[data-start] { cursor: pointer; }

/* Уверенность распознавания и правка транскрипта (ТЗ №48, задача 2). Мягкая
   подсветка сомнительной строки — фон, не рамка: должна быть заметна, но не
   выглядеть как ошибка/предупреждение системы (это оценка, не диагноз). */
.transcript-line.transcript-questionable { background: var(--questionable-bg); }
.transcript-line.speaker-operator.transcript-questionable { background: var(--questionable-operator-bg); }
.transcript-confidence-bar, .transcript-human-banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-secondary); margin: var(--sp-2) 0; }
.transcript-edit-toolbar, #transcript-edit-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: var(--sp-2) 0; }
.transcript-edit-btn { margin-left: var(--sp-2); }
/* «почему?» у цветной строки (ТЗ №69, задача A5): уровень и причина по нажатию — на телефоне наведения нет. */
.confidence-why { margin-left: var(--sp-2); font-size: var(--fs-caption); }
.confidence-reason { font-size: var(--fs-caption); margin-top: var(--sp-1); }
.dict-replaced-badge { display: inline-block; margin-left: var(--sp-2); padding: 1px var(--sp-2); border-radius: var(--r-pill); background: var(--info-bg); color: var(--info); font-size: var(--fs-caption); cursor: help; }
.transcript-edit-textarea { width: 100%; min-height: 3.5em; font: inherit; padding: var(--sp-2); border-radius: var(--radius-md); border: var(--border-width) solid var(--card-border); resize: vertical; }
/* «Сохранить» / «Отмена» и подсказка под полем правки (24.09.2026). */
.transcript-edit-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); cursor: default; }
.transcript-edit-hint { font-size: var(--fs-caption); color: var(--text-secondary); }
@media (max-width: 720px) {
  /* Телефон: кнопки во всю ширину, одна под другой; подсказка — под ними. */
  .transcript-edit-actions { flex-direction: column; align-items: stretch; }
  .transcript-edit-actions .btn { width: 100%; }
}
.btn-small { padding: var(--space-2) var(--space-4); font-size: var(--fs-caption); gap: var(--space-2); }

.principle-row { display: flex; align-items: flex-start; gap:var(--sp-3); padding:var(--sp-3) 0; border-bottom: 1px solid var(--card-border); }
.principle-row:last-child { border-bottom: none; }
.principle-score { width: 22px; height: 22px; border-radius: var(--r-pill); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size:var(--fs-caption); flex-shrink: 0; }
.principle-score.score-1 { background: var(--success-bg); color: var(--success-text); }
.principle-score.score-0 { background: var(--error-bg); color: var(--error-text); }
.principle-score.score-unknown { background: var(--tile-bg); color: var(--text-tertiary); }
.principle-quote { color: var(--text-secondary); font-size:var(--fs-caption); margin-top:var(--sp-1); cursor: pointer; }
.principle-quote:hover { color: var(--link); }

.review-block { display: flex; gap:var(--sp-2); margin-top:var(--sp-3); }
.review-choice { flex: 1; padding:var(--sp-3) var(--sp-2); border-radius: var(--radius-md); border: 1px solid var(--btn-secondary-border); text-align: center; font-weight: 600; font-size:var(--fs-body); }
.review-choice.selected-accurate { background: var(--success-bg); border-color: var(--success); color: var(--success); }
.review-choice.selected-minor { background: var(--warning-bg); border-color: var(--warning); color: var(--warning); }
.review-choice.selected-major { background: var(--error-bg); border-color: var(--error); color: var(--error); }
.review-comment { width: 100%; margin-top:var(--sp-2); border: 1px solid var(--btn-secondary-border); border-radius: var(--radius-md); padding:var(--sp-2); font-family: inherit; resize: vertical; min-height: 56px; }


/* Модальные окна */
.modal-overlay {
  position: fixed; inset: 0; background: var(--overlay);
  display: flex; align-items: center; justify-content: center;
  z-index: 100; padding:var(--sp-5);
}
.modal-panel {
  background: var(--card-bg); border-radius: var(--radius-lg); padding:var(--sp-5);
  width: 100%; max-width: 640px; max-height: 88vh; overflow-y: auto;
  box-shadow: var(--shadow-modal);
}
.modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom:var(--sp-4); }

/* Поиск в шапке, Ctrl+K (ТЗ №47, задача 6) — components/search_modal.js. */
.search-modal-panel { padding:var(--sp-3); max-width: 560px; align-self: flex-start; margin-top: 10vh; }
.search-input {
  width: 100%; border: none; outline: none; font-size:var(--fs-lead);
  padding:var(--sp-3); border-bottom: 1px solid var(--card-border);
}
#search-results { max-height: 50vh; overflow-y: auto; margin-top:var(--sp-2); }
.search-result {
  display: flex; align-items: center; gap:var(--sp-3); width: 100%;
  padding:var(--sp-2) var(--sp-3); border-radius: var(--radius-md);
  text-align: left; background: none; border: none; font-size:var(--fs-body); color: var(--text-primary);
}
.search-result.active, .search-result:hover { background: var(--tile-bg); }
.search-result-main { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-see-all { display: block; padding:var(--sp-2) var(--sp-3); color: var(--link); font-weight: 500; }

/* Единые уведомления об успехе/ошибке (ТЗ №47, задача 6) — components/toast.js. */
.toast-stack {
  position: fixed; left: 50%; bottom:var(--sp-5); transform: translateX(-50%);
  display: flex; flex-direction: column; gap:var(--sp-2);
  z-index: 200; max-width: 90vw; align-items: center;
}
.toast {
  padding:var(--sp-3) var(--sp-4); border-radius: var(--radius-md); box-shadow:var(--shadow);
  color: var(--btn-primary-text); font-size:var(--fs-body); cursor: pointer;
}
/* Белый текст на ярком --success давал ~3:1 (ниже 4,5:1, ТЗ №49, задача 3) — фон темнее, тот же
   зелёный, что у текста на зелёных плашках. Пары проверяет webapp/lib/contrast.test.js. */
.toast-success { background: var(--success-text); }
.toast-error { background: var(--error-text); }
.toast { max-width: min(90vw, 560px); line-height: 1.4; }
.modal-close { border: none; background: none; font-size:var(--fs-title); line-height: 1; color: var(--text-tertiary); padding:var(--sp-1) var(--sp-2); }
.dropzone {
  border: 2px dashed var(--btn-secondary-border); border-radius: var(--radius-md);
  padding:var(--sp-6) var(--sp-4); text-align: center; color: var(--text-secondary);
  cursor: pointer; margin-bottom:var(--sp-4);
}
.dropzone.dragover { border-color: var(--btn-primary-bg); background: var(--tile-bg); }
.upload-item { border: 1px solid var(--card-border); border-radius: var(--radius-md); padding:var(--sp-3); margin-bottom:var(--sp-3); }
.upload-item-head { display: flex; justify-content: space-between; align-items: center; gap:var(--sp-2); margin-bottom:var(--sp-2); font-weight: 600; }
.upload-item-fields { display: grid; grid-template-columns: 1fr 1fr; gap:var(--sp-2); }
.upload-item-fields .full-width { grid-column: 1 / -1; }
.upload-item-status { font-size:var(--fs-caption); margin-top:var(--sp-2); }
.upload-item-status.ok { color: var(--success); }
.upload-item-status.error { color: var(--error); }
.upload-item-status.pending { color: var(--text-tertiary); }

/* Телефон (ТЗ №30, задача 4.5) — единственный способ, которым руководитель
   посмотрит утреннюю сводку, не "адаптив ради адаптива". Меню — выезжающая
   панель поверх контента, не всегда видимый сайдбар (на телефоне ему
   некуда деться, кроме как занять весь экран). Таблицы скроллятся по
   горизонтали внутри своей карточки, а не разъезжаются и не давят текст. */
.mobile-menu-btn {
  display: none;
  position: fixed; top: var(--space-5); left: var(--space-5); z-index: 60;
  width: 36px; height: 36px; align-items: center; justify-content: center;
  border-radius: var(--radius-md); border: var(--border-width) solid var(--btn-secondary-border);
  background: var(--card-bg); color: var(--text-primary);
}
.sidebar-overlay { display: none; }

/* Средняя ширина — планшет и половина большого экрана (ТЗ №39, задача 5).
   На 800 пикселях фильтры вставали столбиком по одному на строку (пилюли не
   давали себя сжать), а таблица красных флагов ужималась до переноса слов по
   слогам. Здесь пилюли получают предел ширины — в строку помещается
   несколько, — а карточка с таблицей прокручивается вбок, как на телефоне. */
@media (min-width: 721px) and (max-width: 1100px) {
  select.filter-select,
  input.filter-select,
  label.filter-select { max-width: 200px; }
  .filter-row { row-gap: var(--sp-2); }
  .card:has(table.data-table) { overflow-x: auto; }
}

@media (max-width: 720px) {
  .mobile-menu-btn { display: flex; }
  .shell { position: relative; }
  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; width: 288px;
    max-width: 84vw;
    /* На телефоне без сдвигов, только прозрачность (ТЗ №82): меню проявляется на месте; закрытое — не видно и недоступно клавиатуре. */
    opacity: 0; visibility: hidden;
    transition: opacity var(--t-base) var(--ease), visibility 0s var(--t-base);
    z-index: 55;
  }
  .sidebar.open { opacity: 1; visibility: visible; transition-delay: 0s; }
  .sidebar-overlay.open {
    display: block; position: fixed; inset: 0;
    background: var(--overlay); z-index: 50;
  }
  .content { padding: 56px var(--page-pad-phone, 16px) var(--gap-sections); }
  .topbar { flex-direction: column; align-items: stretch; }
  /* Карточка с таблицей скроллится сама по себе — колонки не сжимаются
     до нечитаемости, а строка остаётся широкой и скроллится вбок.
     (.review-layout уже одноколоночный при ширине уже 1180px, см. выше.) */
  .card:has(table.data-table) { overflow-x: auto; }
}

/* Окно входа (ТЗ №35, задача 3). Боковая панель и кнопка меню на экране входа
   скрыты (класс login-screen ставит app.js). Поля и кнопка — не ниже 44px,
   шрифт полей 16px: так iOS не увеличивает страницу при фокусе. */
body.login-screen .sidebar,
body.login-screen .sidebar-overlay,
body.login-screen .mobile-menu-btn { display: none; }
body.login-screen .content { padding: var(--space-11) var(--space-8); }
.login-wrap {
  min-height: calc(100vh - 48px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-11);
}
.login-brand { text-align: center; }
.login-logo { width: 260px; max-width: 100%; height: auto; display: block; margin: 0 auto var(--space-6); }
.login-tagline { color: var(--text-secondary); font-size: var(--font-size-xl); }
.login-card { width: 100%; max-width: 360px; margin-bottom: 0; }
.login-title { font-size: var(--font-size-lg); font-weight: 700; margin: 0 0 var(--space-8); }
.login-field { display: block; margin-bottom: var(--space-7); }
.login-label { display: block; font-size: var(--font-size-base); color: var(--text-secondary); margin-bottom: var(--space-2); }
input.filter-select.login-input {
  width: 100%; min-height: 44px; font-size:var(--fs-lead);
  border-radius: var(--radius-md); padding: var(--space-4) var(--space-6);
}
.login-submit { width: 100%; min-height: 44px; justify-content: center; font-size: var(--font-size-xl); }
.login-error { min-height: 20px; margin-top: var(--space-5); color: var(--error); font-size: var(--font-size-md); }
/* Метка экземпляра на странице входа (ТЗ №42, задача 2) — та же роль/машина/
   порт/версия, что и в шапке после входа, только здесь это главное, что
   должен заметить человек ДО того, как введёт пароль. */
.login-instance { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.login-instance-detail { font-size: var(--font-size-sm); color: var(--text-secondary); }
.login-dev-hint { text-align: center; }
/* Плашки-предупреждения и вспомогательные классы (ТЗ №35, задача 4) */
.muted { color: var(--text-secondary); font-size: var(--font-size-base); }
.alert {
  margin: var(--space-6) 0; padding: var(--space-5) var(--space-7);
  border-radius: var(--radius-md); font-size: var(--font-size-base); line-height: 1.45;
}
.alert-warning { background: var(--warning-bg); color: var(--warning-text); border: var(--border-width) solid var(--warning-border); }
/* Пауза AI (ТЗ №65) — красная плашка: нужно действие человека */
.alert-error { background: var(--error-bg); color: var(--error-text); border: var(--border-width) solid var(--error-text); }
.data-table td.num, .data-table th.num { text-align: right; }
/* Поля карточек настроек */
.settings-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-8); margin-bottom: var(--space-8); }
.settings-field { display: flex; flex-direction: column; gap: var(--space-2); }
.settings-label { font-size: var(--font-size-base); color: var(--text-secondary); }
.settings-hint { font-size: var(--font-size-sm); color: var(--text-tertiary); }
.settings-message { margin-left: var(--space-4); font-size: var(--font-size-base); }
/* Пользователи и окно смены пароля (ТЗ №36, задача 2) */
/* Выбор пароля при создании и сбросе (users.js#passwordChoiceHtml) */
/* min-width: 0 — у fieldset по умолчанию ширина «по содержимому», и строка с кнопкой вылезала за карточку на телефоне. */
.password-choice { border: none; padding: 0; margin: 0; gap: var(--sp-1); min-width: 0; }
.password-input-row { display: flex; gap: var(--sp-2); align-items: center; }
.password-input-row input { flex: 1; min-width: 0; }
.secret-card { border-color: var(--warning); }
.secret-code { font-size: var(--font-size-xl); padding: var(--space-2) var(--space-4); background: var(--tile-bg); border-radius: var(--radius-sm); user-select: all; letter-spacing: 0.04em; }
.check-row { display: flex; align-items: center; gap: var(--space-4); min-height: 32px; }
.row-muted td { color: var(--text-tertiary); }
.row-actions { white-space: nowrap; }
.row-actions .btn { margin-right: var(--space-2); }
/* Меню «⋯» в строке таблицы (ТЗ №69, G1.5): главная кнопка на виду, остальные — списком по нажатию. */
.row-actions { display: inline-flex; align-items: center; gap: var(--sp-1); flex-wrap: nowrap; }
.row-menu { position: relative; display: inline-block; }
.row-menu > summary { list-style: none; cursor: pointer; min-width: 32px; justify-content: center; font-weight: 700; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-list { z-index: 50; display: flex; flex-direction: column; min-width: 200px; padding: var(--sp-1); background: var(--card-bg); border: var(--border-width) solid var(--card-border); border-radius: var(--radius-md); box-shadow: var(--shadow-pop); }
.row-menu-list .btn { width: 100%; justify-content: flex-start; text-align: left; border-color: transparent; background: transparent; margin: 0; white-space: normal; }
.row-menu-list .btn:hover { background: var(--hover-bg, var(--tile-bg)); }
dialog.dialog { border: var(--border-width) solid var(--card-border); border-radius: var(--radius-lg); padding: var(--space-9); width: min(92vw, 380px); box-shadow: var(--shadow-modal); background: var(--card-bg); color: var(--text-primary); }
dialog.dialog::backdrop { background: var(--overlay); }
.dialog-actions { display: flex; gap: var(--space-4); margin-top: var(--space-6); }
/* Редактор карты аудита (ТЗ №36, задача 3) */
.principle-edit { border: var(--border-width) solid var(--card-border); border-radius: var(--radius-md); padding: var(--space-8); margin: 0 0 var(--space-8); }
.principle-edit legend { padding: 0 var(--space-3); }
textarea.filter-select.area { width: 100%; border-radius: var(--radius-md); font-weight: 400; line-height: 1.4; resize: vertical; }
.sidebar-project-note { margin-top: var(--space-3); font-size: var(--font-size-sm); color: var(--warning-text); line-height: 1.35; }
/* Карточка развития оператора (ТЗ №36, задача 4) */
.op-controls { display: flex; gap: var(--space-4); flex-wrap: wrap; align-items: center; }
.weakest-line { font-size: var(--font-size-2xl); margin: 0; }
.red-flag-card { border-color: var(--error); border-width: 2px; }
.charts-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-8); margin-bottom: var(--space-9); }
.chart-card { margin-bottom: 0; }
.chart-title { font-weight: 600; font-size: var(--font-size-base); margin-bottom: var(--space-3); }
.examples-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--space-9); }
.examples-grid h3 { margin: 0 0 var(--space-4); font-size: var(--font-size-md); }
.example-list { list-style: none; margin: 0; padding: 0; }
.example { padding: var(--space-4) 0; border-top: var(--border-width) solid var(--card-border); }
.example blockquote { margin: 0 0 var(--space-2); font-size: var(--font-size-md); }
.example-meta { font-size: var(--font-size-sm); color: var(--text-secondary); }
.state-dot { display: inline-block; width: 10px; height: 10px; border-radius: var(--r-pill); vertical-align: middle; margin-right: var(--space-2); }

/* Печать (A4): без меню, кнопок и фильтров; карточки не разрываются между страницами */
@page { size: A4; margin: 12mm; }
/* Длинные пояснения — свёрнуты под «Как подключить» / «Как это работает» (ТЗ №69, G1.4). */
.howto { margin: 0 0 var(--sp-2); font-size: var(--fs-caption); color: var(--text-secondary); }
.howto > summary { cursor: pointer; color: var(--link); width: fit-content; list-style: none; display: inline-flex; align-items: center; gap: 6px; }
.howto > summary::-webkit-details-marker { display: none; }
.howto > summary::before { content: "?"; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 50%; border: 1px solid currentColor; font-size: var(--fs-12); font-weight: 700; line-height: 1; }
.howto-body { margin-top: var(--sp-1); line-height: 1.5; }

/* Техническая деталь ошибки — под «подробнее» (ТЗ №69, G1.3). */
.error-details, .toast-details { margin: 0 0 var(--sp-3); font-size: var(--fs-caption); color: var(--text-secondary); }
.error-details summary, .toast-details summary { cursor: pointer; }
.error-details code, .toast-details code { display: block; white-space: pre-wrap; word-break: break-word; margin-top: var(--sp-1); }
.toast-details { margin: var(--sp-1) 0 0; color: inherit; opacity: 0.85; }

/* «Коучинг» (ТЗ №69, задача B): задания списком, у каждого — итог и график до/после. */
.coaching-body > .card { margin-bottom: var(--sp-3); }
.coaching-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.coaching-item { border: var(--border-width) solid var(--card-border); border-radius: var(--radius-md); padding: var(--sp-3); }
.coaching-head { display: flex; flex-wrap: wrap; gap: var(--sp-1); align-items: center; }
.coaching-text { margin: var(--sp-1) 0; white-space: pre-wrap; }
.coaching-chart { max-width: 360px; margin: var(--sp-2) 0; }

/* «Главное» — экран директора (ТЗ №69, задача D): три цифры плитками, списки проблем, звонков и действий. */
.director-toolbar { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.director-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.director-tile-value { font-size: var(--fs-28); font-weight: 600; line-height: 1.2; }
.director-tile-label { font-weight: 600; margin-top: var(--sp-1); }
.director-tile-sub { font-size: var(--fs-caption); margin-top: var(--sp-1); }
.director-few { font-size: var(--fs-body); font-weight: 600; color: var(--text-secondary); }
.director-delta.up { color: var(--success); }
.director-delta.down { color: var(--error); }
.director-list { margin: 0; padding-left: 1.4em; display: grid; gap: var(--sp-2); }
.director-item > div + div { margin-top: 2px; }
.director-link, .director-missed { font-weight: 600; }
.director-block { margin-bottom: var(--sp-3); }
.director-trust { display: grid; gap: var(--sp-1); font-size: var(--fs-caption); }
.dash-compliance { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.dash-compliance .kpi-delta { margin: 0; }

@media print {
  /* Подсказки «?» (ТЗ №67, задача 6) — только на экране: в PDF значки и всплывающий текст не нужны. */
  .hint-btn, .hint-pop { display: none !important; }
  .sidebar, .sidebar-overlay, .mobile-menu-btn, .no-print, #demo-banner, #owner-banner, .topbar .btn, #version-note select { display: none !important; }
  .shell { display: block; }
  .content { padding: 0; }
  body { font-size: 11pt; color: var(--print-text); }
  .card { break-inside: avoid; border-color: var(--print-border); box-shadow: none; }
  .charts-grid { grid-template-columns: repeat(2, 1fr); }
  .examples-grid { grid-template-columns: repeat(2, 1fr); }
  details { display: block; }
  details > summary { display: none; }
  a { color: inherit; text-decoration: none; }
  a[href]::after { content: none !important; }
  /* «Итоги пилота» (ТЗ №50, задача 3): без вкладок и шапки выбора; подвал — дата и период. */
  #page-tabs, .sidebar-project, .filters-bar { display: none !important; }
  .pilot-block { break-inside: avoid; page-break-inside: avoid; }
  .print-footer { display: block !important; margin-top: 8mm; font-size: 9pt; color: var(--print-muted); border-top: 1px solid var(--print-border); padding-top: 2mm; }
  /* ТЗ №67, задача 5: страница для директора в PDF. Разрыв страницы — только между блоками (блок целиком
     переносится на следующую страницу), заголовок блока не остаётся один внизу страницы; колонтитул с
     датой и периодом — на каждой странице (стиль #pilot-page-footer, его пишет pages/pilot.js) и в конце.
     Светлая всегда: тёмная тема действует только на экране (tokens.css, @media screen). */
  .pilot-body { display: block; }
  .pilot-block { box-shadow: none; margin-bottom: 5mm; break-before: auto; }
  .pilot-block .card-header, .pilot-subtitle { break-after: avoid; page-break-after: avoid; }
  .pilot-body .tile { border: 1px solid var(--print-border); }
  .pilot-meter, .pilot-meter > span { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .pilot-body .pilot-num-link, .pilot-body .pilot-num-link:hover { border-bottom: none; color: inherit; }
  .pilot-scroll { overflow: visible !important; }
  /* «Главное» (ТЗ №69): блок целиком на странице, ссылки — обычным текстом. */
  .director-block { break-inside: avoid; page-break-inside: avoid; box-shadow: none; }
  .director-tiles { grid-template-columns: repeat(2, 1fr); }
  .director-body .tile { border: 1px solid var(--print-border); }
  .director-link, .director-missed { color: inherit; }
  /* Графики и списки бывшего «Дашборда» под плитками (ТЗ №79, п. 4): карточка не рвётся между страницами. */
  #home-charts .card { break-inside: avoid; page-break-inside: avoid; box-shadow: none; }
}
.print-footer { display: none; }

/* «Итоги пилота» (ТЗ №50): крупные цифры строкой, под ними подписи и выборка. */
.pilot-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--sp-3) var(--sp-4); margin: var(--sp-2) 0 var(--sp-3); }
.pilot-stat-value { font-size: var(--fs-28); font-weight: 600; line-height: 1.2; }
.pilot-stat-label { color: var(--text-secondary); font-size: var(--fs-body); }
.pilot-num-link { color: var(--link); text-decoration: none; border-bottom: 1px dashed currentColor; }
.pilot-num-link:hover { border-bottom-style: solid; }
.pilot-subtitle { font-weight: 600; margin: var(--sp-3) 0 var(--sp-2); }
.pilot-list { margin: 0; padding-left: 1.2em; }
.pilot-list li { margin: 2px 0; }
.pilot-table { margin: 0 0 var(--sp-2); }
.pilot-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-3); }
.pilot-two { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-4); }
/* «Итоги пилота» для директора (ТЗ №67, задача 5): шапка с паузами AI, крупная цифра блока, сравнение
   с ручной прослушкой полосами, разделы «Что нашли» плитками. Только переменные темы; на 390 px всё
   переносится в одну колонку, широкие таблицы прокручиваются внутри своего блока. */
.pilot-body { display: grid; gap: var(--sp-4); }
.pilot-body .pilot-block { margin-bottom: 0; min-width: 0; }
.pilot-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-2) var(--sp-5); margin: 0; }
.pilot-facts dt { color: var(--text-secondary); font-size: var(--fs-caption); margin-bottom: var(--sp-1); }
.pilot-facts dd { margin: 0; font-size: var(--fs-lead); overflow-wrap: anywhere; }
.pilot-muted { color: var(--text-secondary); font-size: var(--fs-body); }
.pilot-hero { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-3); margin: 0 0 var(--sp-2); }
.pilot-hero-value { font-size: var(--fs-28); font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; }
.pilot-hero-label { font-size: var(--fs-lead); color: var(--text-secondary); overflow-wrap: anywhere; }
.pilot-stat.tile { padding: var(--sp-4); }
.pilot-stat-value { font-variant-numeric: tabular-nums; }
.pilot-compare { display: grid; gap: var(--sp-2); max-width: 560px; margin: var(--sp-2) 0 var(--sp-2); }
.pilot-compare-row { display: grid; grid-template-columns: 72px minmax(0, 1fr) 64px; gap: var(--sp-3); align-items: center; font-variant-numeric: tabular-nums; }
.pilot-compare-row b { text-align: right; }
.pilot-meter { display: block; height: 10px; border-radius: var(--r-pill); background: var(--tile-bg); border: var(--border-width) solid var(--card-border); overflow: hidden; }
.pilot-meter > span { display: block; height: 100%; min-width: 2px; background: var(--chart-line); }
.pilot-meter-manual > span { background: var(--text-tertiary); }
.pilot-meter-wide { max-width: 360px; margin: 0 0 var(--sp-2); }
.pilot-manual-form { margin: var(--sp-2) 0; }
.pilot-manual-row, .pilot-form-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin-top: var(--sp-2); }
.pilot-manual-row input { width: 140px; }
#pilot-next-text { width: 100%; font-family: inherit; }
.pilot-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-3); }
.pilot-part { background: var(--tile-bg); border-radius: var(--r-card); padding: var(--sp-3) var(--sp-4); min-width: 0; overflow-wrap: anywhere; }
.pilot-part .pilot-subtitle { margin-top: 0; }
.pilot-scroll { overflow-x: auto; max-width: 100%; }
.pilot-chart { max-width: 520px; margin-bottom: var(--sp-2); }
.pilot-changes li { margin: var(--sp-2) 0; }
.pilot-up { color: var(--success-text); font-weight: 600; }
.pilot-down { color: var(--error-text); font-weight: 600; }
@media (max-width: 720px) {
  .pilot-hero-value { font-size: var(--fs-28); }
  .pilot-compare-row { grid-template-columns: 64px minmax(0, 1fr) 56px; }
}
.status-value { font-size: var(--font-size-2xl); word-break: break-word; }


/* Выбор операторов в форме пользователя (ТЗ №37, задача 9.2): список с
   поиском, а не сплошной абзац со всеми номерами. */
.operator-choices {
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: var(--sp-2);
  margin-top: var(--sp-2);
}

/* Звонки карточками на узком экране (ТЗ №37, задача 12.5). На компьютере
   карточек нет, на телефоне — нет таблицы: в ней девять столбцов и 1420 px,
   она прокручивалась вбок. Обе разметки рисуются всегда, выбор — здесь. */
.calls-cards { display: none; }
.call-card {
  display: block;
  padding: var(--sp-3);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  margin-bottom: var(--sp-2);
  text-decoration: none;
  color: inherit;
  background: var(--card-bg);
}
.call-card-excluded { opacity: 0.65; }
.call-card-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-body); }
.call-card-head strong { font-size: var(--fs-lead); }
.call-card-operator { font-weight: 600; margin-top: var(--sp-1); }
.call-card-client { color: var(--text-secondary); font-size: var(--fs-body); margin-top: 2px; }
.call-card-tags { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.call-card-summary { margin-top: var(--sp-2); font-size: var(--fs-caption); color: var(--text-secondary); }
/* Поиск «в тексте разговора» (ТЗ №79, п. 15): режим поля, строка о долгом поиске, находка — время реплики и фрагмент с подсветкой. */
.filters-search-mode { width: auto; max-width: 11rem; }
.calls-search-note { margin: var(--sp-2) 0; font-size: var(--fs-caption); }
.text-hit { position: relative; display: block; margin-top: var(--sp-1); font-size: var(--fs-caption); color: var(--text-secondary); text-decoration: none; overflow-wrap: anywhere; }
.text-hit:hover, .text-hit:focus-visible { text-decoration: underline; }
.text-hit mark { background: var(--warning-bg); color: var(--warning-text); border-radius: 2px; padding: 0 1px; }
.text-hit-time { font-variant-numeric: tabular-nums; color: var(--text-primary); font-weight: 600; }
.call-card-hit { margin-top: var(--sp-2); }
/* Таблица звонков широкая (до 14 столбцов) и не сжимается в карточки на
   большом экране. Прокрутка — внутри неё самой, а не всей страницей
   (ТЗ №39, задача 5): иначе вся страница ездит вбок, и шапка с фильтрами
   уезжает вместе с ней. */
/* Высота ограничена (ТЗ №49, задача 2): длинный список прокручивается внутри обёртки, и шапка
   таблицы (position: sticky) остаётся видна — иначе после 20-й строки не понять, где какой столбец. */
.calls-table-wrap, .table-scroll { overflow: auto; max-height: 75vh; }

@media (max-width: 767px) {
  .calls-table-wrap { display: none; }
  .calls-cards { display: block; }
}

/* ===== Телефон (ТЗ №36, задача 8): до 720 px ===== */
@media (max-width: 720px) {
  /* Самая мелкая ступень шрифта — 14 px (на компьютере 12). */
  :root { --fs-caption: 14px; }
  /* Всё, на что нажимают, — не ниже 44 px; поля 16 px, чтобы iOS не увеличивал страницу при фокусе. */
  .content button,
  .content .btn,
  .content select,
  .content textarea,
  .content summary,
  .content input:not([type="checkbox"]):not([type="radio"]),
  /* Окна (components/dialog.js) и меню пользователя живут вне .content — правило то же. */
  dialog button, dialog select, dialog input:not([type="checkbox"]):not([type="radio"]),
  .sidebar .btn, .sidebar select, .filter-pill button, .btn-icon { min-height: 44px; }
  .btn-icon, .filter-pill button { min-width: 44px; }
  dialog input:not([type="checkbox"]):not([type="radio"]), dialog select { font-size: var(--fs-lead); }
  .content input[type="file"] { padding: var(--sp-2) 0; }
  .content select, .content textarea,
  .content input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]) { font-size: var(--fs-lead); }
  .content input[type="checkbox"], .content input[type="radio"] { width: 24px; height: 24px; }
  .mobile-menu-btn { width: 44px; height: 44px; }
  .sidebar-link { min-height: 44px; }
  .source-tabs { flex-wrap: wrap; }
  .content select, .content input:not([type="checkbox"]):not([type="radio"]) { max-width: 100%; }
  .player-controls { flex-wrap: wrap; }
  .player-time { width: auto; }
  .filters-row, .filter-row, .card-toolbar { gap: var(--sp-2); }
  /* Демо-плашка сверху не должна закрывать кнопку меню. */
  body:has(#demo-banner, #owner-banner) .mobile-menu-btn { top: 44px; }
  body:has(#demo-banner, #owner-banner) .content { padding-top: 96px; }
  .content { padding-bottom: var(--sp-6); }

  /* Таблицы до шести столбцов — карточками (подписи ставит components/mobile_tables.js). */
  table.data-table.stack, table.data-table.stack tbody, table.data-table.stack tr, table.data-table.stack td { display: block; width: 100%; }
  table.data-table.stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.data-table.stack tr { border: var(--border-width) solid var(--card-border); border-radius: var(--radius); margin-bottom: var(--sp-3); padding: var(--sp-2) var(--sp-3); }
  table.data-table.stack td { border: none; padding: var(--sp-1) 0; text-align: left; white-space: normal; min-width: 0; overflow-wrap: anywhere; }
  table.data-table.stack td::before { content: attr(data-label); display: block; font-size: var(--fs-caption); font-weight: 600; color: var(--text-secondary); }
  table.data-table.stack td.num, table.data-table.stack th.num { text-align: left; }
  .card:has(table.data-table.stack) { overflow-x: visible; }
}


/* Короткий вердикт наверху карточки звонка (ТЗ №36, 10.2) */
.verdict-card { padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-3); }
.verdict-alarm { border-color: var(--error); border-width: 2px; }
.verdict-head { display: flex; align-items: baseline; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.verdict-score { font-size: var(--fs-heading); font-weight: 700; display: flex; align-items: baseline; gap: var(--sp-2); }
.verdict-score-note { font-size: var(--fs-caption); font-weight: 400; color: var(--text-secondary); }
.verdict-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-1) var(--sp-4); }
.verdict-row { display: flex; gap: var(--sp-2); align-items: baseline; padding: var(--sp-1) 0; }
.verdict-mark { flex: 0 0 auto; font-weight: 700; width: 1.2em; text-align: center; }
.v-yes { color: var(--success-text); }
.v-no { color: var(--error-text); }
.v-unknown { color: var(--text-secondary); }
.verdict-why { display: block; font-size: var(--fs-caption); color: var(--text-secondary); }


/* Клавиатура (ТЗ №36, задача 10.5): видимый фокус на всём, что можно выбрать с клавиатуры.
   :focus-visible — рамка появляется при навигации клавишами, но не при клике мышью. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  /* Кольцо фокуса 2 px цвета акцента (ТЗ №66, задача 3) — только при работе с клавиатуры. Без смены скругления:
     раньше фокус менял border-radius, и элемент «прыгал». */
  outline: var(--focus-ring-width) solid var(--accent);
  outline-offset: 2px;
}
.sidebar :where(a, button):focus-visible { outline-color: var(--accent); }
/* Строка таблицы, по которой можно перейти к звонку, должна получать фокус — см. rowLinkCover. */
tr:focus-visible { outline: var(--focus-ring-width) solid var(--accent); outline-offset: -2px; }
/* «Пропустить к содержимому» — первая цель Tab, видна только при фокусе. */
.skip-link {
  position: absolute; left: var(--sp-3); top: -100px; z-index: 100;
  background: var(--card-bg); color: var(--text-primary); padding: var(--sp-3) var(--sp-4);
  border: var(--border-width) solid var(--card-border); border-radius: var(--radius);
  display: inline-flex; align-items: center; min-height: 44px;
}
.skip-link:focus { top: var(--sp-3); }

/* Состояние загрузки — каркас страницы, а не пустой экран (ТЗ №36, 10.4). */
.skeleton { display: grid; gap: var(--sp-3); }
.skeleton-row { height: 72px; border-radius: var(--radius); background: linear-gradient(90deg, var(--tile-bg) 25%, var(--skeleton-shine) 37%, var(--tile-bg) 63%); background-size: 400% 100%; animation: skeleton var(--t-shimmer) ease infinite; }
@keyframes skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* Переключатель языка в меню пользователя (ТЗ №36, задача 11) */
.sidebar-lang { display: block; font-size: var(--fs-caption); color: var(--sidebar-text-muted); margin-top: var(--sp-2); }
.sidebar-lang select { width: 100%; margin-top: var(--sp-1); }


/* Слепая оценка (ТЗ №36, задача 12) */
.blind-principle { border: var(--border-width) solid var(--card-border); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2); }
.blind-principle legend { font-weight: 600; padding: 0 var(--sp-1); }
.blind-transcript { margin-bottom: var(--sp-3); }
.transcript-pre { white-space: pre-wrap; font-family: inherit; font-size: var(--fs-body); max-height: 320px; overflow: auto; background: var(--tile-bg); padding: var(--sp-3); border-radius: var(--radius); }
.progress-row { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.progress-label { width: 2.5em; font-weight: 600; }
.progress-track { flex: 1; height: 10px; background: var(--tile-bg); border-radius: var(--radius-pill); overflow: hidden; }
.progress-fill { display: block; height: 100%; background: var(--success); }
.progress-value { width: 5em; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-secondary); }

/* Тип звонка в карточке (ТЗ №52): одна строка над вердиктом. */
.call-type-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); }

/* ---------- Карточка звонка v2 (ТЗ №52, задача 4) ---------- */
.card-head-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); font-size: var(--fs-body); }
.card-head-part { font-weight: 600; }
.card-head-sep { color: var(--text-tertiary); }
/* Верх карточки звонка (ТЗ №69, G2.7): главное слева, одна главная кнопка справа; на телефоне кнопка — во всю ширину
   под текстом. Суть — одна строка (полный текст — в подсказке и в «Кратком содержании» ниже). */
.call-top { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.call-top-body { flex: 1 1 auto; min-width: 0; }
.call-top .card-head-line { margin: 0 0 var(--sp-2); }
.call-top .score-zone { font-size: var(--fs-lead); }
.call-top-summary { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.call-top-action { flex: 0 0 auto; }
.call-top-btn { min-height: 44px; padding: 0 var(--sp-5); font-size: var(--fs-lead); }
@media (max-width: 720px) {
  .call-top { flex-direction: column; align-items: stretch; gap: var(--sp-3); }
  .call-top-btn { width: 100%; justify-content: center; }
}
.score-zone { display: inline-block; padding: 2px var(--sp-2); border-radius: var(--radius-pill); font-weight: 700; }
.score-zone-good { background: var(--success-bg); color: var(--success-text); }
.score-zone-medium { background: var(--warning-bg); color: var(--warning-text); }
.score-zone-bad { background: var(--error-bg); color: var(--error-text); }
.score-zone-none { color: var(--text-tertiary); }
.score-zone-text-good { color: var(--success-text); font-weight: 700; }
.score-zone-text-medium { color: var(--warning-text); font-weight: 700; }
.score-zone-text-bad { color: var(--error-text); font-weight: 700; }
.zone-legend { display: flex; flex-wrap: wrap; gap: var(--sp-3); font-size: var(--fs-caption); color: var(--text-tertiary); margin-top: var(--sp-2); }
.zone-dot { display: inline-block; width: 10px; height: 10px; border-radius: var(--r-pill); margin-right: var(--sp-1); vertical-align: middle; }
.zone-dot.score-zone-good { background: var(--success); }
.zone-dot.score-zone-medium { background: var(--warning); }
.zone-dot.score-zone-bad { background: var(--error); }
.score-ring-wrap { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.score-ring-wrap .zone-legend { flex-direction: column; gap: 2px; margin-top: 0; }
.last-agreement { margin: 0 0 var(--sp-3); }
.card-v2-tabs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.card-v2-tab { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-pill); border: 1px solid var(--btn-secondary-border); background: transparent; font-weight: 600; color: var(--text-secondary); cursor: pointer; }
.card-v2-tab.active { background: var(--btn-primary-bg); color: var(--btn-primary-text); border-color: var(--btn-primary-bg); }
.tab-count { display: inline-block; min-width: 1.5em; padding: 0 6px; border-radius: var(--radius-pill); background: var(--tile-bg); color: var(--text-primary); font-size: var(--fs-caption); text-align: center; }
.card-v2-tab.active .tab-count { background: var(--on-accent-soft); color: var(--btn-primary-text); }
.tab-count-zero { color: var(--text-tertiary); }
.card-v2-list { margin: 0; padding-left: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
.card-v2-subtitle { font-weight: 700; margin: var(--sp-3) 0 var(--sp-2); }
.card-v2-time { font-size: var(--fs-caption); }
.lead-why summary { cursor: pointer; list-style: none; }
.lead-why[open] { flex-basis: 100%; }
.lead-why-body { margin-top: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--card-border); border-radius: var(--radius); font-size: var(--fs-caption); }
.lead-why-body ul { margin: var(--sp-1) 0 var(--sp-2); }
.lead-settings-level { margin: var(--sp-2) 0; }
.operator-override { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); font-size: var(--fs-body); }
.manager-note { margin: 0 0 var(--sp-3); }

/* ---------- Дашборд v2 (ТЗ №53) ---------- */
.kpi-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.kpi-tile { display: block; padding: var(--sp-4); border: 1px solid var(--card-border); border-radius: var(--radius); background: var(--card-bg); color: var(--text-primary); text-decoration: none; }
.kpi-tile:hover { border-color: var(--text-tertiary); }
.kpi-title { font-size: var(--fs-caption); color: var(--text-secondary); font-weight: 600; }
.kpi-value { font-size: var(--fs-28); font-weight: 600; margin: var(--sp-1) 0; }
.kpi-alarm { color: var(--error-text); }
.kpi-delta { font-size: var(--fs-lead); font-weight: 700; }
.kpi-delta-good { color: var(--success-text); }
.kpi-delta-bad { color: var(--error-text); }
.kpi-delta-flat { color: var(--text-secondary); }
.kpi-sample, .dash-sample { font-size: var(--fs-caption); color: var(--text-tertiary); margin: var(--sp-1) 0 0; }
.dash-card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.seg-switch { display: inline-flex; flex-wrap: wrap; gap: var(--sp-1); }
.seg-btn { padding: var(--sp-1) var(--sp-3); border-radius: var(--radius-pill); border: 1px solid var(--btn-secondary-border); background: transparent; color: var(--text-secondary); font-weight: 600; cursor: pointer; }
.seg-btn.active { background: var(--btn-primary-bg); color: var(--btn-primary-text); border-color: var(--btn-primary-bg); }
.dash-chart { width: 100%; height: 220px; display: block; }
.chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-axis { fill: var(--chart-text); font-size: var(--fs-12); }
.chart-line { fill: none; stroke: var(--chart-line); stroke-width: 2; vector-effect: non-scaling-stroke; }
.chart-line-prev { fill: none; stroke: var(--chart-prev); stroke-width: 2; stroke-dasharray: 6 4; vector-effect: non-scaling-stroke; }
.chart-dot { fill: var(--chart-line); }
.chart-hit { fill: transparent; cursor: pointer; }
.chart-marker { stroke: var(--chart-marker); stroke-width: 1; stroke-dasharray: 3 3; }
.chart-marker-label { fill: var(--chart-marker); font-size: var(--fs-12); }
.chart-table { margin-top: var(--sp-2); font-size: var(--fs-caption); }
.chart-table summary { cursor: pointer; color: var(--text-tertiary); }
.crit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--sp-3); }
.crit-card { border: 1px solid var(--card-border); border-radius: var(--radius); }
.crit-weakest { border: 2px solid var(--error); }
.crit-toggle { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1); width: 100%; padding: var(--sp-3); background: transparent; border: 0; color: var(--text-primary); text-align: left; cursor: pointer; font: inherit; }
.crit-name { font-weight: 600; }
.crit-value { font-size: var(--fs-title); }
.crit-foot, .crit-changed { font-size: var(--fs-caption); color: var(--text-tertiary); }
.crit-changed { color: var(--warning-text); }
.crit-details { padding: 0 var(--sp-3) var(--sp-3); font-size: var(--fs-body); }
.spark { display: block; max-width: 100%; }
.spark-empty { font-size: var(--fs-caption); color: var(--text-tertiary); }
.dash-up { color: var(--success-text); font-weight: 600; }
.dash-down { color: var(--error-text); font-weight: 600; }
.dash-two-col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-4); }
.dash-two-col > .card { margin-bottom: 0; }
.dash-bars { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.dash-bar-toggle { display: grid; grid-template-columns: minmax(90px, 1fr) 2fr auto; align-items: center; gap: var(--sp-2); width: 100%; background: transparent; border: 0; padding: var(--sp-1) 0; color: var(--text-primary); text-align: left; cursor: pointer; font: inherit; }
.dash-bar-label { overflow-wrap: anywhere; }
.dash-bar-track { height: 10px; border-radius: var(--radius-pill); background: var(--tile-bg); border: 1px solid var(--card-border); overflow: hidden; }
.dash-bar-fill { display: block; height: 100%; background: var(--chart-bar); }
.dash-bar-value { font-size: var(--fs-caption); color: var(--text-secondary); white-space: nowrap; }
.dash-bar-details { padding: var(--sp-2) 0 var(--sp-2) var(--sp-3); border-left: 2px solid var(--card-border); margin: var(--sp-1) 0 var(--sp-2); font-size: var(--fs-body); }
.dash-grown { margin: 0 0 var(--sp-3); }
.donut-wrap { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); }
.donut-part.lead-1 { stroke: var(--lead-1); }
.donut-part.lead-2 { stroke: var(--lead-2); }
.donut-part.lead-3 { stroke: var(--lead-3); }
.donut-center { fill: var(--text-primary); font-size: var(--fs-16); font-weight: 600; }
.donut-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.donut-dot { display: inline-block; width: 10px; height: 10px; border-radius: var(--r-pill); margin-right: var(--sp-1); }
.donut-dot.lead-1 { background: var(--lead-1); }
.donut-dot.lead-2 { background: var(--lead-2); }
.donut-dot.lead-3 { background: var(--lead-3); }
@media (max-width: 1100px) { .kpi-row { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 720px) {
  .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dash-two-col { grid-template-columns: 1fr; }
  .dash-bar-toggle { grid-template-columns: 1fr auto; }
  .dash-bar-track { grid-column: 1 / -1; order: 3; }
}
/* Переключатель темы (ТЗ №53, задача 6) — в меню, над именем пользователя. */
.theme-switch { display: inline-flex; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.theme-btn { width: 32px; height: 32px; border-radius: var(--radius-pill); border: 1px solid var(--sidebar-divider); background: transparent; color: var(--sidebar-text); cursor: pointer; font-size: var(--fs-lead); line-height: 1; }
.theme-btn.active { background: var(--sidebar-active-bg); color: var(--sidebar-active-text); }
/* «Как в системе» — появляется после первого выбора темы (ТЗ №84, п. 7.6) */
.theme-reset { align-self: center; margin-left: var(--sp-1); padding: 0; border: 0; background: transparent; color: var(--sidebar-text); font-size: var(--fs-caption); cursor: pointer; text-decoration: underline; }

/* «Показать пароль» — страница входа и окно «Сменить пароль» (ТЗ №55, задача 1). Область нажатия 44×44 (телефон). */
.password-wrap { position: relative; display: block; }
.password-wrap .password-input { width: 100%; padding-right: 48px; }
.password-toggle { position: absolute; top: 50%; right: 0; transform: translateY(-50%); width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: var(--radius); background: transparent; color: var(--text-secondary); cursor: pointer; }
.password-toggle:hover { color: var(--text-primary); }
.login-tagline[hidden] { display: none; }

/* «Не удалось загрузить страницу» вместо белого экрана (ТЗ №55, задача 2). */
.boot-failed { max-width: 520px; margin: var(--sp-6) auto; padding: var(--sp-5); border: 1px solid var(--card-border); border-radius: var(--radius); background: var(--card-bg); text-align: center; }
.boot-failed-text { margin: 0 0 var(--sp-4); font-size: var(--fs-lead); color: var(--text-primary); }

/* Анимации короткие (100–200 мс, не дольше 300) и ПОЛНОСТЬЮ отключаются, если в системе выбрано «уменьшить движение» (ТЗ №66, задача 3; ТЗ №81, п. 3: «отключает
   всё» — теперь и крутилка «в работе», и мерцание каркаса, и полоса загрузки; занятая кнопка остаётся видна по приглушённому виду и неподвижному значку). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 1ms !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; transition-delay: 0s !important; scroll-behavior: auto !important; }
  /* Остаётся только смена цвета у состояний (ТЗ №82, п. 3): точка «в порядке / проблема» меняет цвет плавно. */
  .status-dot::before { transition-duration: var(--t-base) !important; }
}

/* ---------- Свой выпадающий список (ТЗ №66, задача 4) — js/ui/select.js ----------
   Системный <select> остаётся в разметке (значение, change, адрес, сохранение выбора — как раньше), но не виден:
   поверх — своё поле и свой список. */
.ui-select { position: relative; display: inline-flex; min-width: 0; max-width: 100%; vertical-align: middle; }
.ui-select-block, .filters-field .ui-select { display: flex; width: 100%; }
.ui-select-native { position: absolute !important; left: 0; bottom: 0; width: 1px !important; height: 1px !important; min-height: 0 !important; margin: 0 !important; padding: 0 !important; border: 0 !important; opacity: 0; pointer-events: none; clip-path: inset(50%); }
.ui-select-trigger {
  display: inline-flex; align-items: center; gap: var(--sp-2); width: 100%; min-width: 0;
  min-height: var(--btn-height); padding: 0 var(--sp-2) 0 var(--sp-3);
  border: var(--border-width) solid var(--control-border); border-radius: var(--r-control);
  background: var(--control-bg); color: var(--text-primary);
  font: inherit; font-size: var(--fs-body); font-weight: 500; line-height: 1.2; text-align: left; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.ui-select-trigger:hover:not(:disabled) { border-color: var(--control-border-hover); }
.ui-select-trigger:disabled { opacity: 0.5; cursor: default; }
.ui-select.is-open .ui-select-trigger { border-color: var(--accent); }
.ui-select-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-select-chevron { flex: none; color: var(--text-tertiary); transition: transform var(--t-base) var(--ease); }
.ui-select.is-open .ui-select-chevron { transform: rotate(180deg); }
.ui-select-pop {
  position: fixed; z-index: 300; display: flex; flex-direction: column; overflow: hidden;
  padding: var(--sp-1); background: var(--card-bg); color: var(--text-primary);
  border: var(--border-width) solid var(--card-border); border-radius: var(--r-card); box-shadow: var(--shadow-pop);
  animation: ui-select-in var(--t-base) var(--ease);
}
.ui-select-pop.is-up { animation-name: ui-select-in-up; }
@keyframes ui-select-in { from { opacity: 0; transform: translateY(calc(-1 * var(--move))); } to { opacity: 1; transform: none; } }
@keyframes ui-select-in-up { from { opacity: 0; transform: translateY(var(--move)); } to { opacity: 1; transform: none; } }
.ui-select-search { display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-2); margin: 0 0 var(--sp-1); border-bottom: var(--border-width) solid var(--card-border); color: var(--text-tertiary); }
.ui-select-search-input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text-primary); font: inherit; font-size: var(--fs-body); padding: var(--sp-2) 0; }
.ui-select-search-input::placeholder { color: var(--text-tertiary); }
.ui-select-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; flex: 1; min-height: 0; overscroll-behavior: contain; }
.ui-select-option {
  display: flex; align-items: center; gap: var(--sp-2); min-height: 34px; padding: 0 var(--sp-2);
  border-radius: var(--r-control); color: var(--text-primary); font-size: var(--fs-body); cursor: pointer; user-select: none;
}
.ui-select-option.is-active { background: var(--bg-hover); }
.ui-select-option[aria-selected="true"] { font-weight: 600; }
.ui-select-option[aria-disabled="true"] { opacity: 0.5; cursor: default; }
.ui-select-option-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-select-check { flex: none; color: var(--accent); }
/* «Все компании» / «Все» — отделены от конкретных вариантов тонкой линией. */
.ui-select-option-sep { position: relative; margin-bottom: 9px; }
.ui-select-option-sep::after { content: ""; position: absolute; left: var(--sp-2); right: var(--sp-2); bottom: -5px; height: 1px; background: var(--card-border); }
.ui-select-empty { padding: var(--sp-2) var(--sp-3); color: var(--text-tertiary); font-size: var(--fs-body); }
/* Цветная точка компании (стабильный цвет по id — orgColorIndex в select.js). */
.ui-select-dot { flex: none; width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--text-tertiary); }
.ui-select-dot-all { background: transparent; box-shadow: inset 0 0 0 1.5px var(--text-tertiary); }
.ui-select-dot.org-color-1 { background: var(--org-1); }
.ui-select-dot.org-color-2 { background: var(--org-2); }
.ui-select-dot.org-color-3 { background: var(--org-3); }
.ui-select-dot.org-color-4 { background: var(--org-4); }
.ui-select-dot.org-color-5 { background: var(--org-5); }
.ui-select-dot.org-color-6 { background: var(--org-6); }
@media (min-width: 721px) and (max-width: 1100px) {
  .filter-row .ui-select, .filters-bar .ui-select { max-width: 200px; }
}
@media (max-width: 720px) {
  /* Телефон: поле не ниже 44 px, пункты тоже — палец, а не мышь (ТЗ №36); поиск 16 px — iOS не увеличивает. */
  .ui-select-trigger { min-height: 44px; font-size: var(--fs-lead); }
  .ui-select-option { min-height: 44px; font-size: var(--fs-lead); }
  .ui-select-search-input { font-size: var(--fs-lead); }
}

/* ================= ТЗ №66, задача 5: таблицы, ячейки, карточки, кнопки, боковая панель =================
   «Мягкий современный» вид: всё — переменными темы (css/tokens.css), обе темы, телефон 390 px. Правила ниже
   уточняют прежние (ниже по файлу — значит главнее); классы и разметка страниц не меняются. */

/* --- Таблицы: строка ~48 px, тонкие разделители вместо сетки, мягкий фон при наведении, шапка закреплена,
       мелкая и приглушённая; числа — табличные, по правому краю. --- */
table.data-table { border-collapse: separate; border-spacing: 0; }
.data-table th {
  height: 36px; padding: var(--sp-2) var(--sp-3);
  font-size: var(--fs-12); font-weight: 600; letter-spacing: 0.01em; color: var(--text-tertiary);
  border-bottom: var(--border-width) solid var(--card-border); background: var(--card-bg);
}
.data-table th[data-sort-key]:hover { color: var(--text-secondary); }
.data-table th[aria-sort] { color: var(--text-secondary); }
.sort-arrow { color: var(--accent); }
.data-table td { height: 48px; padding: var(--sp-2) var(--sp-3); border-bottom: var(--border-width) solid var(--card-border); }
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr { transition: background-color var(--t-fast) var(--ease); }
.data-table tbody tr:hover { background: var(--bg-hover); }
/* «Транскрипт не проверен человеком» — мягкий фон и тонкая жёлтая полоса слева, а не яркая заливка строки. */
.data-table tbody tr.row-needs-review > td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.data-table td.col-user_talk_time, .data-table th.col-user_talk_time { text-align: right; }
.data-table td.col-start_stamp { white-space: nowrap; color: var(--text-secondary); }
.data-table td.col-client_number { color: var(--text-secondary); }

/* --- Метки-«таблетки»: мягкий фон и текст из семантических цветов; значок — от цвета текста. --- */
.pill { gap: 4px; padding: 2px var(--sp-2); border-radius: var(--r-pill); font-size: var(--fs-12); font-weight: 600; line-height: 1.5; }
/* В ячейке таблицы метка — одной строкой; в тексте и карточках на телефоне — переносится (длинный тип флага). */
.data-table .pill { white-space: nowrap; }
table.data-table.stack .pill { white-space: normal; }
.pill-xs { padding: 1px var(--sp-2); font-size: var(--fs-12); }
.pill-gray { background: var(--neutral-bg); color: var(--neutral-text); }
.pill-icon { flex: none; }

/* --- Балл: «таблетка» цвета зоны и тонкая полоска заполнения. --- */
.score-pill { display: inline-flex; align-items: center; padding: 2px var(--sp-2); border-radius: var(--r-pill); font-size: var(--fs-13); line-height: 1.4; }
.score-pill.score-zone-text-good { background: var(--success-bg); }
.score-pill.score-zone-text-medium { background: var(--warning-bg); }
.score-pill.score-zone-text-bad { background: var(--error-bg); }
.score-cell { display: inline-flex; flex-direction: column; align-items: stretch; gap: 4px; min-width: 52px; vertical-align: middle; }
.score-bar { display: block; height: 3px; border-radius: var(--r-pill); background: var(--neutral-bg); overflow: hidden; }
.score-bar-fill { display: block; height: 100%; border-radius: inherit; }
.score-bar-good { background: var(--success); }
.score-bar-medium { background: var(--warning); }
.score-bar-bad { background: var(--error); }
td.col-score_percent { white-space: nowrap; }
td.col-score_percent .score-cell + .flag-badge { margin-left: var(--sp-2); vertical-align: top; }

/* --- Красный флаг: маленький значок с числом, типы — в подсказке. --- */
.flag-badge {
  display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; border-radius: var(--r-pill);
  background: var(--error-bg); color: var(--error-text); font-size: var(--fs-12); font-weight: 700; line-height: 1.4;
  cursor: help; vertical-align: middle; position: relative;
}

/* --- Оператор: кружок с инициалами (цвет по имени) и имя. --- */
.op-cell { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; max-width: 100%; }
.op-cell-name { min-width: 0; }
.avatar {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border-radius: var(--r-pill); font-size: var(--fs-12); font-weight: 600; letter-spacing: 0.02em; line-height: 1; user-select: none;
}
.avatar::before { content: attr(data-initials); }
.avatar-1 { background: var(--av-1-bg); color: var(--av-1-fg); }
.avatar-2 { background: var(--av-2-bg); color: var(--av-2-fg); }
.avatar-3 { background: var(--av-3-bg); color: var(--av-3-fg); }
.avatar-4 { background: var(--av-4-bg); color: var(--av-4-fg); }
.avatar-5 { background: var(--av-5-bg); color: var(--av-5-fg); }
.avatar-6 { background: var(--av-6-bg); color: var(--av-6-fg); }
.avatar-7 { background: var(--av-7-bg); color: var(--av-7-fg); }
.avatar-8 { background: var(--av-8-bg); color: var(--av-8-fg); }

/* --- Пустое состояние: значок, одна строка и подсказка — вместо голого «0». --- */
.empty-state { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: var(--sp-6) var(--sp-3); color: var(--text-secondary); text-align: center; }
.empty-state-icon { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--r-pill); background: var(--neutral-bg); color: var(--text-tertiary); }
.empty-state-title { margin: 0; font-size: var(--fs-lead); font-weight: 600; color: var(--text-primary); }
.empty-state-text { margin: 0; max-width: 48ch; }
.empty-state .btn { margin-top: var(--sp-2); }
/* Ошибка внутри уже существующей карточки (showError …, { compact: true }). */
.error-state { padding: var(--sp-3) 0; }
/* Внутри вкладки, графика, ячейки таблицы (ТЗ №69, G2.10): тот же вид, меньше места. */
.empty-state-sm { padding: var(--sp-3) var(--sp-2); gap: var(--sp-1); }
.empty-state-sm .empty-state-icon { width: 28px; height: 28px; }
.empty-state-sm .empty-state-icon svg { width: 16px; height: 16px; }

/* --- Загрузка: скелетоны строк таблицы, а не пустота или крутилка на весь экран. --- */
.skeleton-row { height: 44px; border-radius: var(--r-control); }
.skeleton-table { gap: 0; }
.skeleton-table .skeleton-row { height: 16px; margin: 16px 0; border-radius: var(--r-pill); }
.skeleton-table .skeleton-row:nth-child(3n + 2) { width: 86%; }
.skeleton-table .skeleton-row:nth-child(3n) { width: 72%; }

/* --- Карточки и плитки: скругление 10, обводка 1 px и лёгкая тень; кликабельная — темнеет рамка (без подъёма, ТЗ №82, п. 4). --- */
.tile { background: var(--tile-bg); border: var(--border-width) solid var(--card-border); border-radius: var(--r-card); }
.tile-head { font-size: var(--fs-13); font-weight: 500; color: var(--text-tertiary); }
.tile-value { font-size: var(--fs-28); font-weight: 600; letter-spacing: -0.01em; }
.kpi-tile { border-radius: var(--r-card); box-shadow: var(--shadow-card); transition: border-color var(--t-fast) var(--ease); }
.kpi-tile:hover { border-color: var(--control-border-hover); }
.kpi-title { font-size: var(--fs-12); font-weight: 500; color: var(--text-tertiary); }
.kpi-value { font-size: var(--fs-28); font-weight: 600; letter-spacing: -0.01em; }
.kpi-delta { font-size: var(--fs-12); font-weight: 600; }

/* --- Подсказка «?» к плитке и показателю (ТЗ №67, задача 6) — js/ui/hint.js. Маленький приглушённый кружок рядом
       с заголовком; на телефоне область нажатия 44 px — невидимым ::after, сам значок не растёт. Подсказка — одна на
       всё приложение, карточкой с тенью, под значком (или над ним, если снизу нет места). --- */
button.hint-btn {
  /* z-index 3 — выше закреплённой шапки таблицы (2): область нажатия у «?» над таблицей не уходит под неё. */
  position: relative; z-index: 3; display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 16px; height: 16px; min-width: 0; min-height: 0; margin: 0 0 0 6px; padding: 0;
  border: var(--border-width) solid var(--control-border); border-radius: var(--r-pill);
  background: transparent; color: var(--text-tertiary);
  font: inherit; font-size: var(--fs-12); font-weight: 600; line-height: 1; letter-spacing: 0; text-transform: none;
  vertical-align: middle; cursor: help;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
/* Область нажатия: ::after отсчитывается от внутреннего края рамки — отсюда «− ширина рамки». */
button.hint-btn::after { content: ""; position: absolute; inset: calc(-4px - var(--border-width)); }
button.hint-btn:hover, button.hint-btn[aria-expanded="true"] { color: var(--text-primary); border-color: var(--control-border-hover); background: var(--bg-hover); }
button.hint-btn[aria-expanded="true"] { color: var(--accent); border-color: var(--accent); }
/* Заголовок со значком — строкой: «?» по первой строке текста и не переносится на отдельную строку один. */
.tile-head:has(> button.hint-btn), .kpi-title:has(> button.hint-btn), .card-title:has(> button.hint-btn) { display: flex; align-items: baseline; gap: 6px; }
.tile-head > button.hint-btn, .kpi-title > button.hint-btn, .card-title > button.hint-btn { margin-left: 0; }
/* «?» рядом с названием страницы или блока (ТЗ №77, п. 6): пояснение — по нажатию, а не абзацем на странице. */
.page-title-row { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.page-title-row > button.hint-btn { margin-left: 8px; }
h3 > button.hint-btn, .settings-label > button.hint-btn { margin-left: 6px; }
.hint-pop {
  position: fixed; z-index: 400; left: 0; top: 0; box-sizing: border-box; width: max-content;
  padding: var(--sp-2) var(--sp-3); border: var(--border-width) solid var(--card-border); border-radius: var(--r-card);
  background: var(--card-bg); color: var(--text-primary); box-shadow: var(--shadow-pop);
  font-size: var(--fs-13); font-weight: 400; line-height: 1.45; text-align: left; white-space: normal; overflow-wrap: anywhere;
  animation: hint-in var(--t-fast) var(--ease);
}
.hint-pop[hidden] { display: none; }
.hint-pop::before {
  content: ""; position: absolute; left: var(--hint-arrow-x, 50%); top: -5px; width: 8px; height: 8px; margin-left: -4px;
  background: var(--card-bg); border-left: var(--border-width) solid var(--card-border); border-top: var(--border-width) solid var(--card-border);
  transform: rotate(45deg);
}
.hint-pop.is-up::before { top: auto; bottom: -5px; border: 0; border-right: var(--border-width) solid var(--card-border); border-bottom: var(--border-width) solid var(--card-border); }
@keyframes hint-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 720px), (pointer: coarse) {
  button.hint-btn { width: 18px; height: 18px; }
  button.hint-btn::after { inset: calc(-13px - var(--border-width)); } /* 18 + 2 × 13 = 44 px */
}

.call-card { border-radius: var(--r-card); box-shadow: var(--shadow-card); transition: border-color var(--t-fast) var(--ease); }
.call-card[data-uuid]:hover { border-color: var(--control-border-hover); }
.crit-card { border-radius: var(--r-card); transition: border-color var(--t-fast) var(--ease); }
.crit-card:hover { border-color: var(--control-border-hover); }
.card-title { font-size: var(--fs-16); font-weight: 600; }
.page-title { font-size: var(--fs-24); font-weight: 600; letter-spacing: -0.01em; }

/* --- Кнопки: основная, второстепенная, «тихая». --- */
.btn, .btn-link { border-radius: var(--r-control); font-weight: 500; transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.btn { border-color: var(--control-border); background: var(--control-bg); }
.btn:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--control-border-hover); }
.btn-primary { font-weight: 600; background: var(--btn-primary-bg); border-color: var(--btn-primary-bg); color: var(--btn-primary-text); }
.btn-primary:hover:not(:disabled) { background: var(--btn-primary-bg); border-color: var(--btn-primary-bg); filter: brightness(1.12); }
.btn-danger { font-weight: 600; }
.btn-quiet { background: transparent; border-color: transparent; color: var(--text-secondary); }
.btn-quiet:hover:not(:disabled) { background: var(--bg-hover); border-color: transparent; color: var(--text-primary); }

/* --- Поля: мягкая рамка и кольцо фокуса. --- */
select.filter-select, input.filter-select, label.filter-select, textarea.filter-select, .filter-btn {
  border-radius: var(--r-control); border-color: var(--control-border); background: var(--control-bg);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
select.filter-select:hover, input.filter-select:hover, label.filter-select:hover, textarea.filter-select:hover, .filter-btn:hover { border-color: var(--control-border-hover); }
input.filter-select:focus-visible, textarea.filter-select:focus-visible, .ui-select-search-input:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 var(--focus-ring-width) var(--bg-selected); }
.ui-select-search-input:focus-visible { box-shadow: none; }
.filter-btn { font-weight: 500; }
.review-comment, .transcript-edit-textarea { border-radius: var(--r-control); border-color: var(--control-border); background: var(--control-bg); color: var(--text-primary); }

/* --- Переключатели вкладок: «таблетка» выбранной вкладки на мягкой подложке. --- */
.source-tabs, .card-v2-tabs, .seg-switch {
  display: flex; flex-wrap: wrap; gap: var(--sp-1); width: fit-content; max-width: 100%;
  padding: var(--sp-1); background: var(--neutral-bg); border-radius: var(--r-card);
}
.source-tab, .card-v2-tab, .seg-btn {
  border: 0; background: transparent; color: var(--text-secondary); font-weight: 500;
  padding: 6px var(--sp-3); border-radius: var(--r-pill); cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.source-tab:hover:not(:disabled), .card-v2-tab:hover, .seg-btn:hover { color: var(--text-primary); }
.source-tab.active, .card-v2-tab.active, .seg-btn.active {
  background: var(--card-bg); color: var(--text-primary); border-color: transparent;
  box-shadow: 0 0 0 var(--border-width) var(--card-border), var(--shadow-card);
}
.card-v2-tab.active .tab-count { background: var(--neutral-bg); color: var(--text-primary); }

/* --- Группы вкладок (ТЗ №79, п. 4: «Качество», «Настройки»; webapp/public/js/pages/tabbed.js). Сверху — группы таблеткой, под ними —
       вкладки выбранной группы текстом с чертой под выбранной. Обе строки переносятся: на телефоне (390 px) вбок ничего не ездит. --- */
.page-tabs .group-tabs { margin-bottom: var(--sp-2); }
.group-tab {
  border: 0; background: transparent; color: var(--text-secondary); font-weight: 500;
  padding: 6px var(--sp-3); border-radius: var(--r-pill); cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.group-tab:hover { color: var(--text-primary); }
.group-tab.active { background: var(--card-bg); color: var(--text-primary); box-shadow: 0 0 0 var(--border-width) var(--card-border), var(--shadow-card); }
.page-tabs .sub-tabs {
  width: auto; gap: 0 var(--sp-4); padding: 0; background: transparent; border-radius: 0;
  border-bottom: var(--border-width) solid var(--card-border);
}
.page-tabs .sub-tabs .source-tab { padding: var(--sp-2) 0; border-radius: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.page-tabs .sub-tabs .source-tab.active { background: transparent; box-shadow: none; color: var(--text-primary); font-weight: 600; border-bottom-color: var(--btn-primary-bg); }

/* --- Боковая панель: выбранный пункт — мягкий фон со скруглением (во всех темах одинаково); заголовки разделов
       мельче и приглушённее. --- */
.sidebar-group-header, .sidebar-project-label {
  font-size: var(--fs-12); font-weight: 500; letter-spacing: 0.02em; text-transform: none; color: var(--sidebar-text-muted);
}
.sidebar-group-header { padding: var(--sp-3) var(--sp-3) var(--sp-1); }
.sidebar-link { font-weight: 500; color: var(--sidebar-text); transition: background-color var(--t-fast) var(--ease); }
.sidebar-link svg { color: var(--sidebar-text-muted); stroke: currentColor; }
.sidebar-link.active { background: var(--sidebar-active-bg); color: var(--sidebar-active-text); font-weight: 600; }
.sidebar-link.active svg { color: var(--sidebar-active-text); }
.sidebar-link:not(.active):hover { background: var(--sidebar-hover); }
.sidebar-search-btn { border-color: var(--sidebar-divider); border-radius: var(--r-control); opacity: 1; }
.sidebar-search-btn:hover { background: var(--sidebar-hover); }

/* --- Карточка звонка: реплики оператора и клиента различаются (мягкий фон и выравнивание, как в переписке). --- */
.transcript-line { border-radius: var(--r-card); }
.transcript-line.speaker-operator { margin-right: 12%; }
.transcript-line.speaker-client { margin-left: 12%; }
@media (max-width: 720px) {
  .transcript-line.speaker-operator { margin-right: 6%; }
  .transcript-line.speaker-client { margin-left: 6%; }
}
/* Стоп-сигнал (красный флаг) в карточке звонка и отчётах — тонкая рамка и полоса слева вместо рамки 2 px:
   заметно, но без яркого пятна (ТЗ №66, задача 5). */
.verdict-alarm, .red-flag-banner, .red-flag-card { border-width: var(--border-width); border-color: var(--error); box-shadow: inset 3px 0 0 var(--error), var(--shadow-card); }
.crit-weakest { border-width: var(--border-width); border-color: var(--error); box-shadow: inset 3px 0 0 var(--error); }

/* ---------- Карточка звонка: запись и транскрипт вместе (ТЗ №67, задача 4) ---------- */
/* Цитата-доказательство, для которой нашлась реплика, — ссылка: клик прокручивает к реплике и перематывает запись. */
.quote-linked { cursor: pointer; }
.principle-quote.quote-linked, .clickable-quote.quote-linked { color: var(--link); }
.principle-quote.quote-linked:hover, .clickable-quote.quote-linked:hover { text-decoration: underline; text-underline-offset: 2px; }
/* Не нашлась ни по времени, ни по тексту — просто текст, без ссылки. */
.quote-unlinked, .quote-unlinked:hover { cursor: default; text-decoration: none; }
.principle-quote.quote-unlinked { color: var(--text-secondary); }
button.clickable-quote.quote-unlinked:disabled { opacity: 1; color: var(--text-secondary); }
/* Реплика, к которой перешли по цитате, — короткая подсветка кольцом акцента. */
.transcript-line.quote-target { box-shadow: 0 0 0 var(--focus-ring-width) var(--accent); transition: box-shadow var(--t-base) var(--ease); }
/* Реплика, которая звучит сейчас, — мягкий фон выбранного (обе темы). */
.transcript-line.highlight { outline: none; box-shadow: inset 3px 0 0 var(--accent); background: var(--bg-selected); }

@media (max-width: 720px) {
  /* Телефон: плеер закреплён снизу экрана, транскрипт прокручивается вместе со страницей и не уходит под плеер. */
  .player-card {
    position: fixed; top: auto; bottom: 0; left: 0; right: 0; z-index: 45; margin: 0;
    border-radius: var(--r-card) var(--r-card) 0 0; border-bottom: 0;
    padding: var(--sp-2) var(--sp-3) calc(var(--sp-2) + env(safe-area-inset-bottom, 0px));
    box-shadow: var(--shadow-modal); background: var(--card-bg);
  }
  /* Две строки: воспроизведение, ±5 с, полоса, время; ниже — скорость и «Скачать аудио». Громкость и усиление —
     у телефона свои кнопки, подсказка по клавишам на телефоне не нужна; подсказка «продолжить с …» остаётся. */
  .player-card { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
  .player-card .player-controls { display: contents; }
  .player-card .player-progress { flex: 1 1 60px; }
  .player-card #hotkey-help-btn, .player-card .player-slider-label { display: none; }
  .player-card .player-controls-secondary { margin: 0; gap: var(--sp-2); }
  .player-card #resume-hint, .player-card .recording-missing { flex-basis: 100%; }
  .player-card #resume-hint:empty { display: none; }
  .player-card-no-recording .player-controls > * { opacity: .45; }
  .content:has(.player-card) { padding-bottom: 160px; }
  .transcript { min-height: 0; max-height: none; overflow-y: visible; }
}

/* ---------- Первое впечатление (ТЗ №67, задача 8): вход, «не найдена», «нет доступа», загрузка ----------
   Всё — переменными tokens.css (обе темы), скругления/тени/кольцо фокуса — как в ТЗ №66. */

/* Экран входа: карточка по центру на мягком фоне с лёгким акцентным свечением сверху. */
body.login-screen {
  background: radial-gradient(900px 420px at 50% -160px, var(--bg-selected), transparent 70%), var(--screen-bg);
}
body.login-screen .content { padding: var(--sp-6) var(--sp-4); }
.login-wrap { min-height: calc(100vh - 2 * var(--sp-6)); gap: var(--sp-5); }
.login-brand { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); }
.login-logo { width: 220px; margin: 0 auto; border-radius: var(--r-card); }
.login-tagline { font-size: var(--fs-16); color: var(--text-secondary); }
.card.login-card {
  max-width: 380px; padding: var(--sp-6); margin: 0;
  border-radius: var(--r-card); box-shadow: var(--shadow-pop);
}
.login-title { font-size: var(--fs-20); font-weight: 700; letter-spacing: -0.01em; margin: 0 0 var(--sp-1); }
.login-hint { margin: 0 0 var(--sp-5); color: var(--text-secondary); font-size: var(--fs-14); text-wrap: pretty; }
.login-field { margin-bottom: var(--sp-4); }
.login-label { font-size: var(--fs-13); font-weight: 500; margin-bottom: var(--sp-2); }
/* Поле входа не сжимается до 200 px на средней ширине (правило для фильтров выше) — оно на всю карточку. */
input.filter-select.login-input {
  max-width: none; min-height: 44px; padding: 0 var(--sp-3);
  border-radius: var(--r-control); font-size: var(--fs-16); font-weight: 400;
}
.password-wrap input.filter-select.login-input { padding-right: 48px; }
.login-submit { margin-top: var(--sp-2); min-height: 44px; font-size: var(--fs-16); }
/* Ошибка входа — мягкая плашка; пока ошибки нет, место под неё не занято (раньше под кнопкой пустовало 32 px). */
.login-error { min-height: 0; margin-top: 0; color: var(--error-text); font-size: var(--fs-14); }
.login-error:not(:empty) { margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-radius: var(--r-control); background: var(--error-bg); }
.login-dev-hint { max-width: 380px; font-size: var(--fs-13); display: grid; gap: var(--sp-1); }
.login-dev-hint code { font-family: var(--font-mono); background: var(--neutral-bg); color: var(--neutral-text); padding: 1px var(--sp-1); border-radius: var(--r-control); overflow-wrap: anywhere; }
@media (max-width: 720px) {
  body.login-screen .content { padding: var(--sp-5) var(--sp-4); }
  .login-wrap { min-height: calc(100vh - 2 * var(--sp-5)); }
  .card.login-card { padding: var(--sp-5); }
  .login-logo { width: 200px; }
}

/* «Страница не найдена» и «Нет доступа» — карточка по центру основной области (components/status_page.js). */
.status-page { display: flex; align-items: center; justify-content: center; min-height: calc(100vh - 200px); padding: var(--sp-5) 0; }
.status-card {
  width: 100%; max-width: 480px; text-align: center;
  background: var(--card-bg); border: var(--border-width) solid var(--card-border); border-radius: var(--r-card);
  box-shadow: var(--shadow-lift); padding: var(--sp-6) var(--sp-5);
}
.status-icon {
  display: inline-flex; align-items: center; justify-content: center; width: 56px; height: 56px;
  margin-bottom: var(--sp-4); border-radius: var(--r-pill); background: var(--bg-selected); color: var(--accent);
}
.status-icon-noAccess { background: var(--warning-bg); color: var(--warning-text); }
.status-code { margin: 0 0 var(--sp-1); font-size: var(--fs-12); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-tertiary); }
.status-title { margin: 0 0 var(--sp-2); font-size: var(--fs-20); font-weight: 700; letter-spacing: -0.01em; color: var(--text-primary); }
.status-text { margin: 0 auto var(--sp-5); max-width: 42ch; color: var(--text-secondary); font-size: var(--fs-14); text-wrap: balance; }
.status-detail { margin: calc(-1 * var(--sp-3)) 0 var(--sp-5); }
.status-detail code { display: inline-block; max-width: 100%; font-family: var(--font-mono); font-size: var(--fs-13); background: var(--neutral-bg); color: var(--neutral-text); padding: 2px var(--sp-2); border-radius: var(--r-control); overflow-wrap: anywhere; }
.status-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); }
.status-actions .btn[hidden] { display: none; }
@media (max-width: 720px) {
  .status-page { min-height: 0; padding: var(--sp-4) 0; }
  .status-card { padding: var(--sp-5) var(--sp-4); }
  .status-actions .btn { flex: 1 1 100%; }
}

/* Загрузка приложения: каркас из index.html, пока не отрисовалась первая страница (без белого экрана). */
.boot-skeleton { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
.boot-sk {
  display: block; border-radius: var(--r-control);
  background: linear-gradient(90deg, var(--neutral-bg) 25%, var(--skeleton-shine) 37%, var(--neutral-bg) 63%);
  background-size: 400% 100%; animation: skeleton var(--t-shimmer) ease infinite;
}
.boot-sk-title { height: 28px; width: 240px; max-width: 70%; }
.boot-sk-subtitle { height: 14px; width: 420px; max-width: 90%; margin-top: calc(-1 * var(--sp-2)); border-radius: var(--r-pill); }
.boot-sk-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-4); }
.boot-sk-tile { height: 104px; border-radius: var(--r-card); }
.boot-sk-card { height: 360px; border-radius: var(--r-card); }
.boot-skeleton-nav { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-3) var(--sp-3) 0; }
.boot-skeleton-nav .boot-sk { height: 14px; border-radius: var(--r-pill); background: var(--sidebar-hover); animation: none; }
.boot-skeleton-nav .boot-sk-group { width: 40%; height: 10px; margin-top: var(--sp-2); }
.boot-skeleton-nav .boot-sk-link { width: 75%; }
.boot-skeleton-nav .boot-sk-link:nth-child(3n) { width: 60%; }

/* Сотрудники «Моих Звонков» (ТЗ №69, G2.8): поиск, группа, сортировка, «только не сопоставленные». */
.mz-emp-toolbar { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin: var(--sp-2) 0; }
.mz-emp-toolbar .list-search { flex: 1 1 220px; min-width: 0; }
.mz-emp-search { min-width: 0; }
.mz-emp-unmatched-label { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-caption); cursor: pointer; }
.mz-emp-count { margin: 0 0 var(--sp-2); font-size: var(--fs-caption); }
.mz-emp-map-cell { white-space: nowrap; }
.mz-emp-map-cell .mz-map { max-width: 100%; }
@media (max-width: 720px) {
  .mz-emp-toolbar > * { flex: 1 1 100%; }
  .mz-emp-unmatched-label { min-height: 44px; }
  .mz-emp-map-cell { white-space: normal; }
  .mz-emp-map-cell .mz-map, .mz-emp-map-cell .mz-create { width: 100%; margin-top: var(--sp-1); }
}
/* «Ждут проверки» (ТЗ №70): нажатый быстрый набор подсвечен; строка прогресса проверяющего — под фильтрами */
.verify-preset[aria-pressed="true"] { background: var(--info-bg); color: var(--info-text); border-color: var(--info-text); }
.verify-progress { margin: 0 0 var(--sp-4); padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--info-bg); color: var(--info-text); font-size: var(--fs-body); }
/* Проверка оценки человеком в карточке звонка (ТЗ №70): блок над оценкой AI и форма «Проверить оценку» */
.verify-block { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--card-border); }
.verify-block .btn { align-self: flex-start; }
.verify-summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.verify-changes { margin: 0; padding-left: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-1); }
.verify-history summary { cursor: pointer; color: var(--text-secondary); }
.verify-form { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-3); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--card-border); }
.verify-crit { border: 1px solid var(--card-border); border-radius: var(--radius-md); padding: var(--sp-2) var(--sp-3); margin: 0; min-width: 0; }
.verify-crit.is-changed { border-color: var(--warning-border); background: var(--warning-bg); }
.verify-crit legend { padding: 0 var(--sp-1); }
.verify-crit-ai { font-size: var(--fs-body); margin-bottom: var(--sp-2); overflow-wrap: anywhere; }
.verify-crit-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--sp-2); align-items: end; }
.verify-field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.verify-field .filter-select, .verify-comment { width: 100%; min-width: 0; }
.verify-comment { grid-column: 1 / -1; }
.verify-flags { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.verify-flag { overflow-wrap: anywhere; }
.verify-errors { color: var(--error); font-size: var(--fs-body); }
.verify-errors:empty { display: none; }
.verify-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.verify-head { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
/* «Точность AI» (ТЗ №70): фильтры вида, оператора и карты; плитки; таблица 4×4 «AI → человек»; доли по цвету строк */
.accuracy-toolbar { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-end; margin-bottom: var(--sp-4); }
.accuracy-field { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.accuracy-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-3); margin-bottom: var(--sp-3); }
.accuracy-tile { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.accuracy-tile-value { font-size: var(--fs-lead); font-weight: 700; overflow-wrap: anywhere; }
.accuracy-tile-label { color: var(--text-secondary); }
.accuracy-tile-sub { font-size: var(--fs-caption); overflow-wrap: anywhere; }
.accuracy-h3 { font-size: var(--fs-body); font-weight: 700; margin: var(--sp-4) 0 var(--sp-2); }
.accuracy-crit { border: 1px solid var(--card-border); border-radius: var(--radius-md); padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2); }
.accuracy-crit summary { cursor: pointer; overflow-wrap: anywhere; }
.accuracy-matrix td.is-match { background: var(--success-bg); }
.accuracy-dyn-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--sp-3); }
.accuracy-level { display: inline-block; width: 10px; height: 10px; border-radius: 50%; vertical-align: middle; }
.accuracy-level-high { background: var(--success); }
.accuracy-level-medium { background: var(--questionable-bg); border: 1px solid var(--warning); }
.accuracy-level-low { background: var(--warning); }
/* Отдел продаж в карточке звонка (ТЗ №72): итог звонка и «Для CRM» */
.sales-block { display: flex; flex-direction: column; gap: var(--sp-3); }
.sales-outcome { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.sales-crm-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.sales-crm-list { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-1) var(--sp-3); margin: var(--sp-2) 0 0; }
.sales-crm-list dt { color: var(--text-secondary); }
.sales-crm-list dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 720px) { .sales-crm-list { grid-template-columns: 1fr; } .sales-crm-list dd { margin-bottom: var(--sp-2); } }

/* Готовая сводка (ТЗ №73, задача 4): когда посчитано и «Обновить» — над цифрами, не молча. */
.ready-note { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--card-border); border-radius: var(--radius-md); background: var(--tile-bg); color: var(--text-secondary); font-size: var(--fs-caption); }
@media print { .ready-note { display: none; } }

/* «Показывать по: 20 · 50 · 100 · 500 · 1000» (ТЗ №74, п. 1) */
.table-pager { gap: var(--sp-2) var(--sp-3); }
.table-pager .pager-count { margin-right: auto; }
.page-size { display: inline-flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.page-size-label { margin-right: var(--sp-1); }
.page-size-btn { min-width: 40px; min-height: 32px; padding: 0 var(--sp-2); border: 1px solid var(--control-border); border-radius: var(--radius-md); background: var(--card-bg); color: var(--text-secondary); font: inherit; cursor: pointer; }
.page-size-btn:hover { border-color: var(--control-border-hover); }
.page-size-btn[aria-pressed="true"] { background: var(--tile-bg); color: var(--text-primary); border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); font-weight: 600; }
.page-size-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 720px) { .page-size-btn { min-height: 40px; min-width: 44px; } }

/* «Главное» (ТЗ №74, п. 8): плитки ровными рядами — 3 + 3 на широком экране, 2 + 2 + 2 на планшете, по одной на телефоне */
@media (max-width: 900px) { .director-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .director-tiles { grid-template-columns: minmax(0, 1fr); } }
@media print { .director-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Пауза AI (ТЗ №74, п. 4): красная полоса сверху страниц; пометка «неполные» — жёлтая плашка у цифр периода */
.ai-pause-bar { position: sticky; top: 0; z-index: 20; margin: 0 0 var(--sp-3); padding: var(--sp-2) var(--sp-4); border-radius: var(--radius-md); border: 1px solid var(--error-text); background: var(--error-bg); color: var(--error-text); font-size: var(--fs-body); }
.ai-pause-bar { display: flex; align-items: flex-start; gap: var(--sp-3); }
.ai-pause-bar .ai-pause-text { flex: 1; min-width: 0; }
.ai-pause-bar .ai-pause-close { flex: none; width: 28px; height: 28px; margin: -2px -6px -2px 0; border: 0; border-radius: var(--radius-md); background: transparent; color: inherit; font-size: var(--fs-24); line-height: 1; cursor: pointer; }
.ai-pause-bar .ai-pause-close:hover { background: color-mix(in srgb, currentColor 14%, transparent); }
.ai-pause-bar .ai-pause-close:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; }
.ai-pause-bar a.ai-pause-fix { margin-left: var(--sp-2); color: inherit; font-weight: 600; text-decoration: underline; }
.pause-incomplete { margin: 0 0 var(--sp-3); }
.pause-incomplete-note { font-size: var(--fs-caption); color: var(--text-secondary); }
@media print { .ai-pause-bar { position: static; } }

/* Проверка оценки: форма на экране (ТЗ №74, п. 6). Карточка — сверху правой колонки. Широкий экран: открытая форма
   закреплена при прокрутке (правая колонка растянута на всю высоту строки, чтобы форме было где ехать): слушаешь и читаешь
   расшифровку, форма рядом; --player-h — высота закреплённого плеера, форма стоит под ним. Узкий экран и телефон — во весь
   экран поверх страницы (с кнопкой «Слушать» внутри: плеер под ней не виден). */
.verify-dock { margin-bottom: var(--sp-4); }
.verify-dock .verify-block, .verify-dock .verify-form { margin-bottom: 0; padding-bottom: 0; border-bottom: 0; }
.verify-form-head { display: flex; align-items: center; gap: var(--sp-2); justify-content: flex-end; }
.verify-listen-btn, .verify-close-btn { display: none; }
.verify-keys-hint { padding: var(--sp-2) var(--sp-3); border-radius: var(--radius-md); background: var(--tile-bg); font-size: var(--fs-body); }
.verify-keys-hint ul { margin: var(--sp-1) 0 0; padding-left: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-1); }
.verify-keys-hint[hidden] { display: none; }
.verify-crit:focus-within { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
@media (min-width: 1181px) {
  .review-layout > div:last-child { align-self: stretch; }
  .verify-dock.is-open { position: sticky; top: calc(var(--player-h, 0px) + var(--sp-3)); max-height: calc(100vh - var(--player-h, 0px) - 2 * var(--sp-3)); overflow-y: auto; z-index: 4; box-shadow: var(--shadow); }
}
@media (max-width: 1180px) {
  .verify-dock.is-open { position: fixed; inset: 0; z-index: 60; margin: 0; border-radius: 0; overflow-y: auto; background: var(--content-bg); padding: var(--sp-4); }
  .verify-dock.is-open .verify-listen-btn, .verify-dock.is-open .verify-close-btn { display: inline-flex; }
  .verify-dock.is-open .verify-form-head { position: sticky; top: calc(-1 * var(--sp-4)); z-index: 1; padding: var(--sp-2) 0; margin: 0 0 var(--sp-2); background: var(--content-bg); }
  .verify-dock.is-open .verify-listen-btn { margin-right: auto; min-height: 44px; }
  .verify-dock.is-open .verify-actions { position: sticky; bottom: calc(-1 * var(--sp-4)); padding: var(--sp-2) 0; background: var(--content-bg); }
  .verify-dock.is-open .verify-actions .btn { min-height: 44px; }
  body.verify-overlay-open { overflow: hidden; }
}

/* «Звонки»: «Суть» — одна строка, забирает оставшуюся ширину и не растягивает таблицу (ТЗ №74, п. 7). Отступы и одна строка в ячейке — css/system.css (ТЗ №83, п. 1.4). */
.calls-table-wrap table.data-table { width: 100%; }
th.col-summary, td.col-summary { width: 100%; max-width: 0; min-width: 120px; }
td.col-summary { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
td.col-summary .cell-summary { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-secondary); }

/* Разбор ошибок AI (ТЗ №75, п. 6) */
.acc-error-bar { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.principle-row.is-error-focus { outline: 2px solid var(--warning-border); outline-offset: 2px; background: var(--warning-bg); border-radius: var(--radius-sm); }
.accuracy-crit-table th[data-sort-key] { cursor: pointer; white-space: nowrap; }
.accuracy-snap-mark { margin-left: var(--sp-1); }
.accuracy-errors { margin-top: var(--sp-4); }

/* Правила критерия в форме проверки (ТЗ №76, п. 2) */
.verify-rules { margin: var(--sp-1) 0 var(--sp-2); font-size: var(--fs-caption); }
.verify-rules > summary { cursor: pointer; color: var(--link); }
.verify-rules ul { margin: var(--sp-1) 0; padding-left: var(--sp-4); }
.verify-rules-toggle { margin-bottom: var(--sp-2); }
.verify-rules .feature-quote { cursor: pointer; }

/* Сотрудники «Моих Звонков» без оператора (ТЗ №76, п. 3) */
.mz-unmatched { text-decoration: none; }
a.mz-unmatched:hover { text-decoration: underline; }
.mz-emp-unmapped.is-target { outline: 2px solid var(--warning-border); background: var(--warning-bg); }
.mz-unmatched-banner { margin-bottom: var(--sp-3); }

/* «Настройка: готово N из 11» (ТЗ №79, п. 6) — components/setup_list.js: компактный список с галочками на «Состоянии»; у каждого пункта название с
   подписью-числом, одна строка «зачем» и кнопка. На телефоне кнопка уходит под текст (не уезжает вбок). */
.setup-list { list-style: none; margin: 0; padding: 0; }
.setup-item { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: var(--border-width) solid var(--card-border); }
.setup-item:last-child { border-bottom: none; }
.setup-check { width: 22px; height: 22px; box-sizing: border-box; border-radius: var(--r-pill); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: var(--fs-caption); border: var(--border-width) solid var(--control-border); color: var(--text-tertiary); }
.setup-item.is-done .setup-check { background: var(--success-bg); border-color: transparent; color: var(--success-text); }
.setup-title { font-weight: 600; overflow-wrap: anywhere; }
.setup-fact { font-weight: 400; color: var(--text-secondary); margin-left: var(--sp-2); }
.setup-why { font-size: var(--fs-caption); color: var(--text-secondary); overflow-wrap: anywhere; }
.setup-action { justify-self: end; }
/* «Как настроить» у пункта без вкладки: кнопка, но подсказка открывается тем же обработчиком, что и у «?» (ui/hint.js). */
button.hint-btn.setup-howto { width: auto; height: auto; min-height: var(--btn-height); margin: 0; padding: 0 var(--sp-4); border-radius: var(--radius); border-color: var(--btn-secondary-border); background: var(--btn-secondary-bg); color: var(--text-primary); font-size: var(--fs-caption); font-weight: 600; cursor: pointer; }
button.hint-btn.setup-howto:hover, button.hint-btn.setup-howto[aria-expanded="true"] { background: var(--tile-bg); color: var(--text-primary); border-color: var(--btn-secondary-border); }
button.hint-btn.setup-howto::after { display: none; }
@media (max-width: 720px) {
  .setup-item { grid-template-columns: 22px minmax(0, 1fr); }
  .setup-action { grid-column: 2; justify-self: start; }
  .content button.hint-btn.setup-howto { min-height: 44px; }
}
/* Строка «Настройка: N из 11» на «Главном» у администратора (ТЗ №79, п. 6) — одна строка ссылкой над плитками; всё настроено — строки нет. */
#director-setup { margin: 0 0 var(--sp-3); font-size: var(--fs-caption); }
/* «Повторить» у итога без текста модели (ТЗ №79, п. 7.2) — кнопка и цена в одной строке над цифрами итога. */
.wd-retry { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-3); }
/* «Показать отменённые» над таблицей ручных записей KPI (ТЗ №79, п. 7.5). */
.kpi-manual-toolbar { margin: 0 0 var(--sp-2); }
/* Фраза «AI не работал N дней из M за период» (ТЗ №79, п. 7.6): в шапке блоков периода — с отступом сверху. */
#pilot-pause-note { margin: var(--sp-3) 0 0; }

/* «Вышло обновление — обновите страницу» (ТЗ №79, п. 24): одна компактная строка над приложением, спокойных цветов, как полоса паузы AI. */
.update-bar { position: sticky; top: 0; z-index: 40; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-4); background: var(--info-bg); color: var(--info-text); border-bottom: 1px solid var(--info-text); font-size: var(--fs-body); }
@media print { .update-bar { display: none; } }

/* ---------- Одинаковое поведение везде (ТЗ №79, п. 25) ---------- */
/* Загрузка дольше 0,5 с: тонкая полоса над страницей (components/loading.js); быстрые ответы её не показывают. Не двигает вёрстку и не мешает нажимать. */
.loading-bar { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 1000; overflow: hidden; pointer-events: none; background: transparent; }
.loading-bar[hidden] { display: none; }
.loading-bar > span { position: absolute; top: 0; bottom: 0; width: 35%; background: var(--accent); border-radius: var(--r-pill); animation: loading-bar-run var(--t-bar-run) ease-in-out infinite; }
@keyframes loading-bar-run { 0% { left: -35%; } 100% { left: 100%; } }
#content[data-slow-loading] { opacity: 0.7; transition: opacity var(--t-base) var(--ease); }
/* Таблицы: строки за пределами выбранного «Показывать по…» спрятаны; заголовок со своей сортировкой — такой же, как у «Звонков». */
.data-table tr[hidden] { display: none !important; }
.data-table th[data-enh-sort] { cursor: pointer; white-space: nowrap; }
.data-table th[data-enh-sort]:hover { color: var(--text-primary); }
.data-table th[data-enh-sort]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Формы: обязательное поле помечено звёздочкой, ошибка стоит у поля. */
.req-mark { color: var(--error-text); margin-left: 2px; font-weight: 600; }
.field-error { display: block; margin-top: var(--sp-1); color: var(--error-text); font-size: var(--fs-14); }
.field-error[hidden] { display: none; }
[aria-invalid="true"] { border-color: var(--error-text) !important; }

/* «Итоги → Отчёт директору» (ТЗ №79, п. 12): семь блоков, одна страница A4. На экране — карточки; в печати — без меню, шапки, кнопок и «?», блок целиком на странице,
   таблицы по ширине листа (поля листа задаёт общий @page выше: A4, 12 мм), светлая тема всегда. */
.dr-sheet { display: grid; gap: var(--sp-3); }
.dr-block { margin: 0; }
.dr-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.dr-stat-value { font-size: var(--fs-28); font-weight: 600; line-height: 1.2; }
.dr-stat-label { font-weight: 600; margin-top: var(--sp-1); color: var(--text-secondary); }
.dr-score-value { font-size: var(--fs-36); font-weight: 600; line-height: 1.2; }
.dr-score-sub { margin-top: var(--sp-1); color: var(--text-secondary); }
.dr-link { font-weight: inherit; }
.dr-line { margin-top: var(--sp-2); font-size: var(--fs-caption); }
.dr-block .table-scroll + .table-scroll { margin-top: var(--sp-3); }
.dr-table td { vertical-align: top; }
.dr-table td.num { white-space: nowrap; }
.dr-table .dr-note { color: var(--text-secondary); }
.dr-delta.up { color: var(--success); }
.dr-delta.down { color: var(--error); }
@media (max-width: 560px) {
  .dr-stats { grid-template-columns: 1fr; }
  .dr-score-value { font-size: var(--fs-28); }
}
@media print {
  .dr-sheet { display: block; }
  .dr-block { break-inside: avoid; page-break-inside: avoid; box-shadow: none; margin-bottom: 4mm; padding: 3mm 4mm; }
  .dr-block .card-header { break-after: avoid; page-break-after: avoid; }
  .dr-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 3mm; }
  .dr-stat-value { font-size: 18pt; }
  .dr-score-value { font-size: 22pt; }
  .dr-sheet .table-scroll { overflow: visible !important; max-height: none !important; }
  /* Узкий лист: общая «карточная» раскладка таблиц для телефона (.stack) в печати не нужна — таблица остаётся таблицей. */
  .dr-sheet table.data-table.stack { display: table; width: 100%; }
  .dr-sheet table.data-table.stack tbody { display: table-row-group; width: auto; }
  .dr-sheet table.data-table.stack thead { position: static; width: auto; height: auto; overflow: visible; clip: auto; display: table-header-group; }
  .dr-sheet table.data-table.stack tr { display: table-row; width: auto; border: none; border-radius: 0; margin: 0; padding: 0; }
  .dr-sheet table.data-table.stack td { display: table-cell; width: auto; padding: 1.5mm 2mm; border-bottom: 1px solid var(--print-border); }
  .dr-sheet table.data-table.stack td::before { content: none; }
  .dr-sheet table.data-table.stack td.num { text-align: right; }
  .dr-table { width: 100%; font-size: 10pt; table-layout: auto; }
  .dr-table th, .dr-table td { padding: 1.5mm 2mm; word-break: break-word; }
  .dr-table td.num, .dr-sheet table.data-table.stack td.num { white-space: nowrap; word-break: normal; }
  .dr-table td:first-child { word-break: normal; }
  .dr-link { color: inherit; border-bottom: none; }
  .dr-delta.up, .dr-delta.down { color: inherit; }
  .dr-stat-label, .dr-score-sub, .dr-table .dr-note { color: var(--print-muted); }
}

/* «Мои звонки» оператора (ТЗ №79, п. 13) */
.my-scores { margin-bottom: var(--sp-3); }
.my-line { margin: 0 0 var(--sp-1); }
.my-examples, .my-calls, .my-manual { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.my-example blockquote { margin: var(--sp-1) 0 0; padding-left: var(--sp-2); border-left: 3px solid var(--border); color: var(--text-secondary); }
.my-call, .my-manual-item { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; }
.my-call-score { margin-left: auto; }

/* ТЗ №81, п. 6.6: строки «Клиент: … · риск» и «Bitrix24: …» в карточке звонка переносятся и на телефоне (390 px) не раздвигают страницу. */
#call-client-line,
#call-b24-line {
  min-width: 0;
  overflow-wrap: anywhere;
}
#call-client-line:not(:empty),
#call-b24-line:not(:empty) {
  margin-top: var(--sp-1);
}

/* ---------- Движение (ТЗ №81, п. 3; ТЗ №82) ----------
   Движение отвечает на три вопроса — что изменилось, куда делось, что сейчас происходит; всё остальное — тишина. Три длительности и одна кривая — переменные из tokens.css
   (--t-fast 120 мс, --t-base 200 мс, --t-slow 400 мс, --ease); других значений в стилях нет (webapp/lib/motion_tokens.test.js). Только CSS и классы состояния.
   «Не делать»: бегущие счётчики, пружины, масштабирование больше 1, волны от клика, появление строк таблиц по одной, анимацию графиков при каждом обновлении, переходы между страницами.
   На телефоне (до 720 px) сдвигов нет, только прозрачность: --move = 0. При prefers-reduced-motion длительности сведены к 1 мс (правило выше); в «Отчёте директору» и печати анимации нет вовсе (system.css). */
:root { --move: 6px; --settle: 4px; interpolate-size: allow-keywords; }
@media (max-width: 720px) { :root { --move: 0px; --settle: 0px; } }

/* Данные после загрузки появляются проявлением за --t-fast (только прозрачность: высота и положение не меняются). Анимация идёт при появлении элемента в странице, а не при каждом наведении. */
@keyframes content-reveal { from { opacity: 0; } to { opacity: 1; } }
.content .card:not(.skeleton), .content .tile-grid, .content .table-scroll, .content .empty-state, .content .error-state { animation: content-reveal var(--t-fast) var(--ease) backwards; }

/* Каркас: не показывается, пока загрузка короче 150 мс (иначе мигает), потом проявляется; внутри — мягкий блик (бесконечный индикатор «идёт загрузка»). */
@keyframes skeleton-appear { from { opacity: 0; } to { opacity: 1; } }
.skeleton { animation: skeleton-appear var(--t-fast) var(--ease) var(--t-skeleton-delay) backwards; }

/* Окна (components/dialog.js — <dialog>): открытие --t-base — проявление и подъём на 6 px; закрытие --t-fast; затемнение под окном мягкое, без размытия. Сдвигается не само окно, а его содержимое
   (.dialog-body), и только на время перехода: у окна с transform position: fixed внутри него (подсказки «?» ставятся внутрь окна, ui/hint.js) считается от окна и сбивает положение. */
dialog.dialog {
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease), overlay var(--t-fast) allow-discrete, display var(--t-fast) allow-discrete;
}
dialog.dialog[open] { opacity: 1; transition-duration: var(--t-base); }
dialog.dialog > .dialog-body { transform: translateY(var(--move)); transition: transform var(--t-fast) var(--ease); }
dialog.dialog[open] > .dialog-body { transform: none; transition-duration: var(--t-base); }
@starting-style { dialog.dialog[open] { opacity: 0; } dialog.dialog[open] > .dialog-body { transform: translateY(var(--move)); } }
dialog.dialog::backdrop { opacity: 0; transition: opacity var(--t-fast) var(--ease), overlay var(--t-fast) allow-discrete, display var(--t-fast) allow-discrete; }
dialog.dialog[open]::backdrop { opacity: 1; transition-duration: var(--t-base); }
@starting-style { dialog.dialog[open]::backdrop { opacity: 0; } }

/* Окна-панели (поиск, просмотры): подложка проявляется, панель всплывает на 6 px; закрытие --t-fast (класс is-closing ставит ui/motion.js). */
@keyframes modal-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-fade-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes modal-rise { from { opacity: 0; transform: translateY(var(--move)); } to { opacity: 1; transform: none; } }
.modal-overlay { animation: modal-fade var(--t-base) var(--ease) backwards; }
.modal-panel { animation: modal-rise var(--t-base) var(--ease) backwards; }
.modal-overlay.is-closing { animation: modal-fade-out var(--t-fast) var(--ease) forwards; pointer-events: none; }
/* Окна, которые страница прячет через style.display (карточка звонка: «Пометить», «Исключить», «Горячие клавиши»): закрытие --t-fast — display уходит в none после затухания, а скрипт видит «закрыто» сразу. */
.modal-overlay { transition: opacity var(--t-fast) var(--ease), display var(--t-fast) allow-discrete; }
.modal-overlay[style*="display: none"], .modal-overlay[style*="display:none"] { opacity: 0; pointer-events: none; }

/* Раскрытие блоков (<details>): по высоте за --t-base; закрытие — так же (::details-content: Chrome 131+, в остальных браузерах раскрытие мгновенное). */
@keyframes details-open { from { opacity: 0; transform: translateY(calc(-1 * var(--move))); } to { opacity: 1; transform: none; } }
@supports selector(details::details-content) {
  details:not(.row-menu):not(.user-menu)::details-content {
    block-size: 0; overflow-y: clip; opacity: 0;
    transition: block-size var(--t-base) var(--ease), opacity var(--t-base) var(--ease), content-visibility var(--t-base) allow-discrete;
  }
  details:not(.row-menu):not(.user-menu)[open]::details-content { block-size: auto; opacity: 1; }
}
@supports not selector(details::details-content) {
  details[open] > :not(summary) { animation: details-open var(--t-base) var(--ease) backwards; }
}

/* Меню (details.row-menu, меню профиля): список появляется со сдвигом на 6 px от кнопки за --t-base, исчезает за --t-fast. */
.row-menu[open] > :not(summary), .user-menu[open] > :not(summary) { animation: details-open var(--t-base) var(--ease) backwards; }
@supports selector(details::details-content) {
  .row-menu::details-content, .user-menu::details-content { opacity: 0; transition: opacity var(--t-fast) var(--ease), content-visibility var(--t-fast) allow-discrete; }
  .row-menu[open]::details-content, .user-menu[open]::details-content { opacity: 1; }
}

/* Наведение: смена фона за --t-fast — без подъёма и теней (в таблице на 50 строк «подпрыгивающие» строки мешают читать). Карточки (клиент, оператор): темнеет рамка. */
a.card, .card[data-href], .tile[data-href], a.tile, .call-card, .crit-card { transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
a.card:hover, .card[data-href]:hover, a.tile:hover, .tile[data-href]:hover { background: var(--bg-hover); }
.sidebar-link, .ui-select-option, .search-result, [role="menuitem"], .row-menu a, .row-menu button { transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }

/* Уведомления: всплывают снизу за --t-base и уходят за --t-fast; «Сохранено» теперь на самой кнопке (components/saved_flash.js), уведомление — для ошибок и действий «не на этом экране»;
   успех гаснет сам через 3–4 с, ошибка остаётся, пока её не закроют (js/components/toast.js). На телефоне — только прозрачность. */
.toast { opacity: 0; transform: translateY(calc(2 * var(--move))); transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease); position: relative; }
.toast.show { opacity: 1; transform: translateY(0); transition-duration: var(--t-base); }
.toast:has(> .toast-close) { padding-right: calc(var(--sp-4) + 28px); }
.toast-body { min-width: 0; overflow-wrap: anywhere; }
/* «×» нарисован стилем (не текстом): его нет в тексте уведомления, а положение не зависит от потока. */
.toast-close { position: absolute; top: var(--sp-2); right: var(--sp-2); width: 24px; height: 24px; border: 0; border-radius: var(--r-pill); background: transparent; color: inherit; cursor: pointer; opacity: 0.85; }
.toast-close::before { content: "×"; font-size: var(--fs-title); line-height: 24px; }
.toast-close:hover { opacity: 1; }

/* Вкладки без прыжка высоты: пока содержимое вкладки грузится (каркас), для него оставлена минимальная высота — страница не схлопывается и не дёргает полосу прокрутки. */
#tab-content:has(> .skeleton), #tab-content:has(> * > .skeleton) { min-height: 60vh; }

/* ---------- Единый поиск над списками (ТЗ №81, п. 1) — js/components/list_search.js ---------- */
.list-search-bar { display: flex; margin: 0 0 var(--sp-3); }
.list-search { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); min-width: 0; max-width: 100%; }
.list-search-field { position: relative; display: inline-flex; align-items: center; min-width: 0; max-width: 100%; }
.list-search-input { width: min(100%, 340px); min-width: 220px; padding-right: 32px; }
.list-search-input::-webkit-search-cancel-button, .list-search-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
.list-search-clear { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); width: 28px; height: 28px; border: 0; border-radius: var(--r-pill); background: transparent; color: var(--text-tertiary); font-size: var(--fs-title); line-height: 1; cursor: pointer; transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.list-search-clear:hover { background: var(--bg-hover); color: var(--text-primary); }
.list-search-clear[hidden] { display: none; }
.list-search-count { color: var(--text-secondary); font-size: var(--fs-caption); white-space: nowrap; }
.list-search-count[hidden] { display: none; }
.list-search-empty td { text-align: center; color: var(--text-secondary); padding: var(--sp-5) var(--sp-3); }
.list-search-empty-text { margin-right: var(--sp-2); }
table.data-table tr[hidden], tr[hidden] { display: none !important; }
/* На телефоне поле поиска — во всю ширину. */
@media (max-width: 600px) {
  .list-search, .list-search-field { width: 100%; }
  .list-search-input { width: 100%; min-width: 0; }
}
/* Крестик виден, только когда в поле есть текст (поле всегда с подписью-подсказкой, поэтому :placeholder-shown = пусто). */
.list-search-input:placeholder-shown ~ .list-search-clear { display: none; }
/* Поле поиска «Звонков»/«Удержания» остаётся в строке фильтров: узкое, как было (26ch), на телефоне — во всю ширину. */
.filters-bar .list-search { flex: 0 1 auto; }
.filters-bar .list-search-input.filters-search { min-width: 0; width: 100%; max-width: 100%; }
.filters-bar .list-search .list-search-input.filters-search { padding-right: 32px; }
@media (min-width: 601px) { .filters-bar .list-search-input.filters-search { width: 300px; } }
/* Телефон: панель фильтров — одна строка с прокруткой вбок (см. выше), поле поиска в ней — фиксированной ширины, чтобы подпись помещалась целиком. */
@media (max-width: 720px) { .filters-bar .list-search, .filters-bar .list-search-field { width: auto; flex: none; } .filters-bar .list-search-input.filters-search { width: 290px; } }
.list-search-empty-block { padding: var(--sp-5) var(--sp-3); text-align: center; color: var(--text-secondary); }

/* Редкие кнопки строки отдела («норма балла», «рабочий день») — под «Ещё», чтобы строка не росла (ТЗ №84, п. 2). */
.dept-more { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); }
.dept-more > summary { cursor: pointer; list-style: none; }
.dept-more > summary::-webkit-details-marker { display: none; }

/* «Настройки → Счёт» (ТЗ №86, п. 3): плитки, таблицы недель и отделов, документ «Счёт № … за …». На экране документ — карточка под таблицами; в печать идёт только он:
   всё, что помечено .inv-screen (плитки, тариф, прогноз, таблицы), и шапка страницы в печати скрыты. Себестоимости в документе нет никогда. */
.inv-stats-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.inv-total td { font-weight: 600; }
.inv-parties { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-3); }
.inv-party-label { font-weight: 600; color: var(--text-secondary); margin-bottom: var(--sp-1); }
.inv-line { margin-bottom: var(--sp-2); }
@media (max-width: 720px) {
  .inv-stats-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .inv-parties { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .inv-stats-4 { grid-template-columns: 1fr; }
}
@media print {
  .inv-screen { display: none !important; }
  .inv-parties { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6mm; }
  .inv-party-label { color: var(--print-muted); }
  .inv-doc { border: none; padding: 0; }
}

/* «Попробовать на своих записях» (ТЗ №86, п. 1): зона перетаскивания, список файлов, выбор карты, мини-отчёт на одной странице. */
.try-drop { border: 2px dashed var(--card-border); border-radius: var(--radius-md); padding: var(--sp-5) var(--sp-3); text-align: center; cursor: pointer; color: var(--text-secondary); }
.try-drop:hover, .try-drop:focus-visible, .try-drop.is-over { border-color: var(--btn-primary-bg); background: var(--tile-bg); }
.try-drop-title { font-size: var(--fs-lead); font-weight: 600; color: var(--text-primary); }
.try-drop-sub { font-size: var(--fs-caption); margin-top: var(--sp-1); }
.try-files { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-1); }
.try-file { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-md); background: var(--tile-bg); min-width: 0; }
.try-file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.try-file-meta { color: var(--text-secondary); font-size: var(--fs-caption); white-space: nowrap; }
.try-file-pending .try-file-meta { color: var(--text-tertiary); }
.try-count { color: var(--text-secondary); font-size: var(--fs-caption); }
.try-templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-2); }
.try-template { display: grid; gap: var(--sp-1); padding: var(--sp-3); border: 1px solid var(--card-border); border-radius: var(--radius-md); cursor: pointer; }
.try-template.is-picked { border-color: var(--btn-primary-bg); background: var(--tile-bg); }
.try-template input { justify-self: start; }
.try-template-name { font-weight: 600; }
.try-template-text { color: var(--text-secondary); font-size: var(--fs-caption); }
.try-price { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2); font-size: var(--fs-lead); }
.try-price-meta { color: var(--text-secondary); font-size: var(--fs-caption); }
.try-actions { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-2); margin-top: var(--sp-3); }
.try-progress-line { margin: var(--sp-2) 0 var(--sp-3); display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); color: var(--text-secondary); }
.try-name { overflow-wrap: anywhere; }
.try-report-grid { display: grid; grid-template-columns: minmax(160px, 220px) 1fr; gap: var(--sp-3); align-items: start; }
.try-calls { display: grid; gap: var(--sp-2); }
.try-call { padding: var(--sp-2) var(--sp-3); border: 1px solid var(--card-border); border-radius: var(--radius-md); }
.try-call-head { display: flex; align-items: center; gap: var(--sp-2); }
.try-call-text { margin-top: var(--sp-1); }
.try-call-meta { margin-top: var(--sp-1); color: var(--text-secondary); font-size: var(--fs-caption); overflow-wrap: anywhere; }
.try-block { margin-top: var(--sp-4); }
.try-h { font-size: var(--fs-body); font-weight: 600; margin: 0 0 var(--sp-1); }
.try-mistake-example { margin-top: var(--sp-1); color: var(--text-secondary); font-size: var(--fs-caption); }
.try-month-value { font-size: var(--fs-lead); font-weight: 600; }
.try-month-basis, .try-expires { color: var(--text-secondary); font-size: var(--fs-caption); }
.try-perday { max-width: 200px; }
.try-runs { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.try-run.is-current { font-weight: 600; }
@media (max-width: 640px) { .try-report-grid { grid-template-columns: 1fr; } }
@media print { .try-drop, .try-actions { display: none !important; } .try-report { break-inside: avoid; } }
