/* ============================================================
   Osanka CRM — прототип. Дизайн-система из DESIGN.md
   Спокойный клиничный · медицинская бирюза · продукт-режим
   ============================================================ */

/* Спрятанное должно быть спрятано. Без этого правила скрытие через hidden молча
   не работает у всего, чему задан свой display: поля формы остаются на экране,
   хотя код считает их убранными. */
[hidden] { display: none !important; }

:root {
  /* Поверхности и текст */
  --bg: oklch(1 0 0);
  --surface: oklch(0.985 0.004 220);
  --surface-sunken: oklch(0.968 0.005 220);
  --ink: oklch(0.24 0.015 235);
  --muted: oklch(0.47 0.02 235);
  --border: oklch(0.915 0.006 235);
  --border-strong: oklch(0.86 0.008 235);

  /* Бренд — медицинская бирюза */
  --primary: oklch(0.52 0.11 195);
  --primary-hover: oklch(0.47 0.115 195);
  --primary-tint: oklch(0.965 0.02 195);
  --primary-tint-strong: oklch(0.93 0.035 195);
  --on-primary: oklch(1 0 0);

  /* Семантика состояний */
  --success: oklch(0.58 0.13 150);
  --success-tint: oklch(0.965 0.03 150);
  --warning: oklch(0.70 0.14 75);
  --warning-tint: oklch(0.97 0.04 75);
  --danger: oklch(0.56 0.19 25);
  --danger-tint: oklch(0.965 0.03 25);

  /* Спейсинг — 4pt scale */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  /* Радиусы */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;

  /* Тени — мягкие, спокойные */
  --shadow-sm: 0 1px 2px oklch(0.24 0.015 235 / 0.06);
  --shadow-md: 0 2px 8px oklch(0.24 0.015 235 / 0.08), 0 1px 2px oklch(0.24 0.015 235 / 0.06);
  --shadow-lg: 0 8px 24px oklch(0.24 0.015 235 / 0.12);

  /* Типографика */
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* z-scale */
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-modal-backdrop: 300;
  --z-modal: 400;
  --z-toast: 500;
  --z-tooltip: 600;

  /* Ширина сайдбара */
  --sidebar-w: 232px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
}

body {
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv05" 1, "ss01" 1;
}

button { font-family: inherit; cursor: pointer; }
::selection { background: var(--primary-tint-strong); }

/* Скролл — спокойный, не системный «толстый» */
.board::-webkit-scrollbar, .col-body::-webkit-scrollbar { height: 10px; width: 10px; }
.board::-webkit-scrollbar-thumb, .col-body::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
.board::-webkit-scrollbar-thumb:hover, .col-body::-webkit-scrollbar-thumb:hover {
  background: var(--muted); background-clip: padding-box;
}

/* ============================================================
   Каркас приложения
   ============================================================ */
.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: 100dvh;
  overflow: hidden;
}

/* --- Сайдбар --- */
.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-4);
  height: 57px;
  border-bottom: 1px solid var(--border);
}
.brand-mark {
  width: 28px; height: 28px; border-radius: 8px;
  background: var(--primary);
  display: grid; place-items: center;
  color: var(--on-primary);
  flex-shrink: 0;
}
.brand-name { font-weight: 600; font-size: 15px; letter-spacing: -0.01em; }
.brand-name span { color: var(--muted); font-weight: 500; }

.nav { padding: var(--sp-3) var(--sp-2); display: flex; flex-direction: column; gap: 2px; flex: 1; }
.nav-section {
  font-size: 11px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--muted); padding: var(--sp-3) var(--sp-3) var(--sp-2);
}
.nav-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--ink);
  text-decoration: none;
  font-size: 14px; font-weight: 500;
  border: none; background: none; width: 100%; text-align: left;
  transition: background 150ms ease-out;
}
.nav-item:hover { background: var(--primary-tint); }
.nav-item.active { background: var(--primary-tint-strong); color: var(--primary-hover); }
.nav-item.active .icon { color: var(--primary); }
.nav-item .icon { color: var(--muted); flex-shrink: 0; }
.nav-item .count {
  margin-left: auto; font-size: 12px; font-weight: 600;
  background: var(--bg); color: var(--muted);
  padding: 1px 7px; border-radius: 999px; border: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
.nav-item.active .count { background: var(--primary); color: var(--on-primary); border-color: transparent; }
.nav-item.alert .count { background: var(--danger-tint); color: var(--danger); border-color: transparent; }

.sidebar-foot {
  border-top: 1px solid var(--border);
  padding: var(--sp-3);
  display: flex; align-items: center; gap: var(--sp-3);
}
.avatar {
  width: 30px; height: 30px; border-radius: 999px;
  background: var(--primary-tint-strong); color: var(--primary-hover);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 600; flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.sidebar-foot .who { min-width: 0; }
.sidebar-foot .who b { display: block; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-foot .who span { font-size: 12px; color: var(--muted); }

/* --- Главная область --- */
.main { display: flex; flex-direction: column; min-width: 0; height: 100dvh; }

/* Верхняя панель */
.topbar {
  height: 57px; flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-5);
  background: var(--bg);
}
.page-title { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; white-space: nowrap; }

/* Переключатель воронок */
.funnel-tabs { display: flex; gap: 2px; background: var(--surface-sunken); padding: 3px; border-radius: var(--r-md); }
.funnel-tab {
  border: none; background: none; color: var(--muted);
  font-size: 13px; font-weight: 500;
  padding: 5px 12px; border-radius: 7px;
  white-space: nowrap;
  transition: all 150ms ease-out;
}
.funnel-tab:hover { color: var(--ink); }
.funnel-tab.active { background: var(--bg); color: var(--ink); box-shadow: var(--shadow-sm); font-weight: 600; }

.topbar-spacer { flex: 1; }

.search {
  display: flex; align-items: center; gap: var(--sp-2);
  background: var(--surface-sunken);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  padding: 6px 10px;
  width: 240px;
  transition: border-color 150ms ease-out, background 150ms ease-out;
}
.search:focus-within { background: var(--bg); border-color: var(--primary); }
.search .icon { color: var(--muted); flex-shrink: 0; }
.search input {
  border: none; background: none; outline: none;
  font-family: inherit; font-size: 13px; color: var(--ink);
  width: 100%;
}
.search input::placeholder { color: var(--muted); }

.btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: 13px; font-weight: 600;
  padding: 7px 14px; border-radius: var(--r-sm);
  border: 1px solid transparent;
  transition: background 150ms ease-out, border-color 150ms ease-out;
  white-space: nowrap;
}
.btn-ghost { background: none; border-color: var(--border); color: var(--ink); }
.btn-ghost:hover { background: var(--surface-sunken); border-color: var(--border-strong); }
.btn-primary { background: var(--primary); color: var(--on-primary); }
.btn-primary:hover { background: var(--primary-hover); }
.btn .icon { flex-shrink: 0; }

/* Полоса фильтров */
.filterbar {
  height: 44px; flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-5);
  background: var(--bg);
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 500; color: var(--muted);
  padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg);
  transition: all 150ms ease-out;
}
.chip:hover { border-color: var(--border-strong); color: var(--ink); }
.chip.active { background: var(--primary-tint); border-color: var(--primary-tint-strong); color: var(--primary-hover); }
.chip .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.filter-spacer { flex: 1; }
.filter-note { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.filter-note b { color: var(--ink); font-weight: 600; }

/* ============================================================
   Доска воронки
   ============================================================ */
.board {
  flex: 1;
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  overflow-x: auto;
  overflow-y: hidden;
  background: var(--surface-sunken);
  align-items: flex-start;
}

.col {
  flex: 0 0 288px;
  width: 288px;
  max-height: 100%;
  display: flex; flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.col.drop-target { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint-strong); }

.col-head {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.col-head .name { font-size: 13px; font-weight: 600; letter-spacing: -0.005em; }
.col-head .count {
  font-size: 12px; font-weight: 600; color: var(--muted);
  background: var(--bg); border: 1px solid var(--border);
  padding: 0 7px; border-radius: 999px; min-width: 22px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.col-head .sla {
  margin-left: auto; font-size: 11px; font-weight: 500; color: var(--muted);
  display: inline-flex; align-items: center; gap: 4px;
}
.col-accent { width: 8px; height: 8px; border-radius: 3px; flex-shrink: 0; }

.col-body {
  padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-2);
  overflow-y: auto;
  flex: 1;
  min-height: 60px;
}

/* Карточка сделки */
.lead {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-2);
  cursor: grab;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 150ms ease-out, border-color 150ms ease-out, transform 150ms ease-out;
}
.lead:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.lead:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.lead.dragging { opacity: 0.5; cursor: grabbing; }
.lead.overdue { border-left: none; }

.lead-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2); }
.lead-name { font-size: 14px; font-weight: 600; letter-spacing: -0.005em; line-height: 1.3; }
.lead-phone {
  font-size: 12px; color: var(--muted);
  font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 5px; margin-top: 2px;
}

.lead-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.tag {
  font-size: 11px; font-weight: 500;
  padding: 2px 8px; border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted);
  display: inline-flex; align-items: center; gap: 4px;
}
.tag.source { background: var(--primary-tint); color: var(--primary-hover); }
.tag.child { background: var(--warning-tint); color: oklch(0.48 0.11 75); }
.tag.city { background: var(--surface-sunken); color: var(--muted); }

.lead-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
}
.lead-owner { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); min-width: 0; }
.lead-owner .avatar { width: 22px; height: 22px; font-size: 10px; }
.lead-owner .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lead-owner.unassigned { color: var(--danger); font-weight: 500; }
.lead-owner.unassigned .avatar {
  background: var(--danger-tint); color: var(--danger);
  border: 1px dashed var(--danger);
}
/* В «Неразобранных» отсутствие хозяина — норма, не тревога: нейтральный вид */
.lead-owner.unassigned-soft { color: var(--muted); }
.lead-owner.unassigned-soft .avatar {
  background: var(--surface-sunken); color: var(--muted);
  border: 1px dashed var(--border-strong);
}

.lead-meta { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }
.due {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 500; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.due.overdue { color: var(--danger); font-weight: 600; }
.due.soon { color: oklch(0.52 0.12 75); }
.task-dot {
  display: inline-grid; place-items: center;
  width: 22px; height: 22px; border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted);
}
.task-dot.has { background: var(--primary-tint); color: var(--primary); }

/* Пустая колонка */
.col-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); text-align: center;
  padding: var(--sp-5) var(--sp-3);
  color: var(--muted); font-size: 12px; line-height: 1.4;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  margin: 0;
}
.col-empty .icon { color: var(--border-strong); }

/* Группа «полки ожидания» */
.parking {
  flex: 0 0 248px; width: 248px;
  align-self: stretch;
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding-left: var(--sp-3);
  border-left: 1px dashed var(--border-strong);
}
.parking-title {
  font-size: 11px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--muted); padding: var(--sp-1) 0;
  display: flex; align-items: center; gap: 6px;
}
.parking .col { flex: 0 0 auto; width: 100%; }
.parking .col-body { max-height: 320px; }

/* Просроченная карточка — тонкий левый акцент допустим как индикатор состояния строки списка?
   Нет: используем метку due.overdue + без бордюра, по банам impeccable. */

/* Тост */
.toast {
  position: fixed; bottom: var(--sp-5); left: 50%; transform: translateX(-50%) translateY(20px);
  background: var(--ink); color: var(--bg);
  padding: 10px 18px; border-radius: var(--r-md);
  font-size: 13px; font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0; pointer-events: none;
  transition: opacity 200ms ease-out, transform 200ms ease-out;
  z-index: var(--z-toast);
  display: flex; align-items: center; gap: var(--sp-2);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast .icon { color: var(--success); }

/* Иконки */
.icon { display: inline-block; width: 18px; height: 18px; stroke-width: 1.6; }
.icon-sm { width: 14px; height: 14px; }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* Адаптив: сворачиваем сайдбар на узких */
@media (max-width: 900px) {
  :root { --sidebar-w: 60px; }
  .brand-name, .nav-section, .nav-item .count, .sidebar-foot .who { display: none; }
  .nav-item { justify-content: center; padding: var(--sp-2); font-size: 0; }
  .nav-item .icon { font-size: 14px; }
  .brand { justify-content: center; padding: var(--sp-4) 0; }
  .sidebar-foot { justify-content: center; }
  .search { width: 160px; }
}

/* ============================================================
   Многоэкранная надстройка: экраны, таблицы, KPI, графики, диалоги
   ============================================================ */
.main { overflow: hidden; }
.nav-item { text-decoration: none; }

.proto-badge {
  position: fixed; right: 12px; bottom: 12px; z-index: var(--z-tooltip);
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--muted); background: var(--bg);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 4px 11px; box-shadow: var(--shadow-sm); pointer-events: none;
}

.btn-sm { padding: 5px 10px; font-size: 12px; }

/* Прокручиваемая область экрана (не доска) */
.screen-scroll { flex: 1; overflow-y: auto; background: var(--surface-sunken); }
.screen-pad { max-width: 1080px; margin: 0 auto; padding: var(--sp-5) var(--sp-5) var(--sp-8); display: flex; flex-direction: column; gap: var(--sp-4); }
.lead-in { margin: 0; color: var(--muted); font-size: 13px; }

/* Панель */
.panel { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-4) var(--sp-5); }
.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.panel-head h2 { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.panel-note { font-size: 12px; color: var(--muted); }

/* KPI */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-3); }
.kpi { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-4); }
.kpi-val { font-size: 30px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.kpi-label { font-size: 13px; font-weight: 600; margin-top: 4px; }
.kpi-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.kpi.danger { border-color: var(--danger-tint); background: var(--danger-tint); }
.kpi.danger .kpi-val { color: var(--danger); }

/* Инсайты */
.insight-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-3); }
.insight { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); }
.insight.warn { border-color: var(--danger-tint); background: var(--danger-tint); }
.insight-num { font-size: 26px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; min-width: 52px; }
.insight.warn .insight-num { color: var(--danger); }
.insight-txt b { display: block; font-size: 13px; }
.insight-txt span { font-size: 12px; color: var(--muted); }

/* Таблица */
.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl thead th { text-align: left; font-weight: 600; color: var(--muted); font-size: 12px; padding: var(--sp-2) var(--sp-3); background: var(--surface-sunken); border-bottom: 1px solid var(--border); position: sticky; top: 0; }
.tbl thead th:first-child { border-top-left-radius: var(--r-sm); }
.tbl thead th:last-child { border-top-right-radius: var(--r-sm); }
.tbl tbody td { padding: var(--sp-3); border-bottom: 1px solid var(--border); vertical-align: middle; }
.tbl.tbl-hover tbody tr:hover { background: var(--primary-tint); }
.tbl tbody tr.row-alert { background: var(--danger-tint); }
.mono { font-variant-numeric: tabular-nums; color: var(--muted); }
.muted-cell { color: var(--muted); }
.cell-user { display: flex; align-items: center; gap: var(--sp-2); }
.cell-user.sm .avatar { width: 22px; height: 22px; font-size: 10px; }
.cell-user.unassigned { color: var(--danger); }
.cell-name { font-weight: 500; }
.avatar.soft { background: var(--surface-sunken); color: var(--muted); border: 1px dashed var(--border-strong); }

/* Пилюли */
.pill { display: inline-flex; align-items: center; font-size: 12px; font-weight: 500; padding: 2px 9px; border-radius: 999px; background: var(--surface-sunken); color: var(--muted); }
.pill.ok { background: var(--success-tint); color: var(--success); }
.pill.info { background: var(--primary-tint); color: var(--primary-hover); }
.pill.warn { background: var(--warning-tint); color: oklch(0.48 0.11 75); }
.pill.danger { background: var(--danger-tint); color: var(--danger); }
.pill.muted { background: var(--surface-sunken); color: var(--muted); }

/* Бары в ячейке (нагрузка менеджеров) */
.bar-cell { display: flex; align-items: center; gap: var(--sp-2); }
.bar-cell .bar { height: 8px; border-radius: 999px; background: var(--primary); min-width: 4px; }
.bar-cell b { font-variant-numeric: tabular-nums; font-weight: 600; }

/* Графики-бары */
.bars { display: flex; flex-direction: column; gap: 7px; }
.bar-row { display: grid; grid-template-columns: 190px 1fr 52px; align-items: center; gap: var(--sp-3); }
.bar-label { font-size: 12.5px; color: var(--ink); text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 4px; justify-content: flex-end; }
.bar-track { background: var(--surface-sunken); border-radius: var(--r-sm); height: 22px; overflow: hidden; }
.bar2 { display: block; height: 100%; border-radius: var(--r-sm); min-width: 3px; transition: width 300ms ease-out; }
.bar-val { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.legend { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.leg { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.leg-dot { width: 10px; height: 10px; border-radius: 3px; }

/* Callout */
.panel.callout { display: flex; gap: var(--sp-3); align-items: flex-start; font-size: 13px; line-height: 1.5; }
.panel.callout .icon { color: var(--muted); flex-shrink: 0; margin-top: 1px; }
.panel.callout.warn { background: var(--warning-tint); border-color: oklch(0.85 0.06 75); }
.panel.callout.warn .icon { color: oklch(0.55 0.12 75); }
.panel.callout b { font-weight: 600; }

/* Пустой блок */
.empty-block { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); padding: var(--sp-8); color: var(--muted); }
.empty-block .icon { color: var(--border-strong); width: 32px; height: 32px; }

/* Задачи */
.task-list { display: flex; flex-direction: column; gap: 6px; }
.task-row { display: grid; grid-template-columns: 110px 1fr auto; align-items: center; gap: var(--sp-3); background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: var(--sp-3); }
.task-type { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 500; color: var(--muted); }
.task-type.call { color: var(--primary); }
.task-text { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-side { display: flex; align-items: center; gap: var(--sp-3); }
.task-side .cell-user span { font-size: 12px; color: var(--muted); white-space: nowrap; }

/* Диалоги */
.inbox { flex: 1; display: grid; grid-template-columns: 340px 1fr; overflow: hidden; }
.inbox-list { border-right: 1px solid var(--border); overflow-y: auto; background: var(--bg); }
.inbox-hint { font-size: 12px; color: oklch(0.55 0.12 75); display: inline-flex; align-items: center; gap: 5px; }
.dlg { display: flex; gap: var(--sp-3); width: 100%; text-align: left; background: none; border: none; border-bottom: 1px solid var(--border); padding: var(--sp-3) var(--sp-4); align-items: flex-start; transition: background 120ms ease-out; }
.dlg:hover { background: var(--surface); }
.dlg.active { background: var(--primary-tint); }
.dlg-av { flex-shrink: 0; }
.dlg-main { min-width: 0; flex: 1; }
.dlg-top { display: flex; align-items: center; gap: var(--sp-2); }
.dlg-top b { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.src-mini { font-size: 10.5px; font-weight: 600; color: var(--primary); background: var(--primary-tint); padding: 1px 6px; border-radius: 999px; flex-shrink: 0; }
.dlg-last { display: block; font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.dlg-side { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; }
.unread { width: 8px; height: 8px; border-radius: 999px; background: var(--primary); }
.wait { display: inline-flex; align-items: center; gap: 3px; font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; }
.wait.bad { color: var(--danger); }
.wait.ok { color: oklch(0.55 0.12 75); }

.inbox-conv { display: flex; flex-direction: column; overflow: hidden; background: var(--surface-sunken); }
.conv-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-3) var(--sp-5); background: var(--bg); border-bottom: 1px solid var(--border); }
.conv-sub { font-size: 12px; color: var(--muted); }
.conv-actions { display: flex; align-items: center; gap: var(--sp-2); }
.conv-body { flex: 1; overflow-y: auto; padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.conv-day { align-self: center; font-size: 11px; color: var(--muted); background: var(--bg); border: 1px solid var(--border); padding: 2px 10px; border-radius: 999px; margin-bottom: var(--sp-2); }
.msg { max-width: 68%; padding: 9px 13px; border-radius: 14px; font-size: 13.5px; line-height: 1.45; }
.msg.in { align-self: flex-start; background: var(--bg); border: 1px solid var(--border); border-bottom-left-radius: 4px; }
.msg.out { align-self: flex-end; background: var(--primary); color: var(--on-primary); border-bottom-right-radius: 4px; }
.conv-note { align-self: center; margin-top: var(--sp-3); font-size: 11.5px; color: var(--muted); display: inline-flex; align-items: center; gap: 5px; }
.conv-input { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5); background: var(--bg); border-top: 1px solid var(--border); }
.conv-input input { flex: 1; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px 12px; font-family: inherit; font-size: 13.5px; outline: none; }
.conv-input input:focus { border-color: var(--primary); }

/* Свалка / полка — визуальные пометки колонок */
.col-dump .col-head { background: var(--danger-tint); border-radius: var(--r-md) var(--r-md) 0 0; }
.col-warn { color: var(--danger); display: inline-flex; }
.col-more { text-align: center; font-size: 11.5px; color: var(--muted); padding: var(--sp-2); }

@media (max-width: 900px) {
  .inbox { grid-template-columns: 1fr; }
  .inbox-conv { display: none; }
  .bar-row { grid-template-columns: 130px 1fr 44px; }
}

/* ============================================================
   Расписание, карта пациента, программа лечения, модалки
   ============================================================ */
.tbl.tbl-hover tbody tr { cursor: pointer; }

.week-nav { display: flex; align-items: center; gap: var(--sp-2); }
.week-label { font-size: 13px; font-weight: 600; color: var(--ink); min-width: 140px; text-align: center; font-variant-numeric: tabular-nums; }
.ic-btn { width: 28px; height: 28px; border: 1px solid var(--border); background: var(--bg); border-radius: var(--r-sm); color: var(--muted); font-size: 16px; line-height: 1; }
.ic-btn:hover { background: var(--surface-sunken); color: var(--ink); }

.sched-filters { height: 44px; flex-shrink: 0; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: var(--sp-2); padding: 0 var(--sp-5); background: var(--bg); }
.sched-legend { display: flex; gap: var(--sp-3); }
.sched-legend .leg { font-size: 11.5px; color: var(--muted); display: inline-flex; align-items: center; gap: 5px; }
.st-chip { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.st-chip.st-done { background: var(--success); }
.st-chip.st-conf { background: var(--primary); }
.st-chip.st-plan { background: var(--bg); border: 1.5px solid var(--border-strong); }
.st-chip.st-noshow { background: var(--danger); }
.st-chip.st-cancel { background: var(--border-strong); }

.sched-scroll { flex: 1; overflow: auto; background: var(--surface-sunken); }
.sched-grid { display: grid; min-width: 900px; }
.sched-grid.week { grid-template-columns: 56px repeat(6, 1fr); }
.sched-grid.specs { grid-template-columns: 56px repeat(var(--cols, 4), 1fr); min-width: 700px; }
.sc-corner { position: sticky; top: 0; left: 0; z-index: 3; background: var(--surface); border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); }
.sc-colhead { position: sticky; top: 0; z-index: 2; background: var(--surface); border-bottom: 1px solid var(--border); border-right: 1px solid var(--border); padding: var(--sp-2) var(--sp-3); font-size: 12.5px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
.sc-colhead span { color: var(--muted); font-weight: 500; font-variant-numeric: tabular-nums; }
.sc-colhead.today { background: var(--primary-tint); color: var(--primary-hover); }
.sc-timecol { position: sticky; left: 0; z-index: 1; background: var(--surface); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); font-size: 11px; color: var(--muted); padding: 4px 6px; text-align: right; font-variant-numeric: tabular-nums; }
.sc-cell { border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--bg); min-height: 46px; padding: 3px; display: flex; flex-direction: column; gap: 3px; }
.sc-cell.today { background: oklch(0.99 0.008 195); }
.sc-cell:hover { background: var(--primary-tint); }

.ev { text-align: left; border: 1px solid var(--border); border-left: 3px solid var(--primary); border-radius: 5px; background: var(--bg); padding: 4px 6px; display: flex; flex-direction: column; gap: 1px; cursor: pointer; transition: box-shadow 120ms ease-out; overflow: hidden; }
.ev:hover { box-shadow: var(--shadow-sm); }
.ev-time { font-size: 10px; color: var(--muted); font-variant-numeric: tabular-nums; }
.ev-pat { font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ev-meta { display: flex; align-items: center; gap: 5px; }
.ev-type { font-size: 10.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; }
.ev-spec { font-size: 10px; color: var(--muted); }
.ev-paid { color: var(--success); display: inline-flex; }
.ev-unpaid { color: var(--warning); display: inline-flex; }
.ev.st-done { border-left-color: var(--success); }
.ev.st-conf { border-left-color: var(--primary); }
.ev.st-plan { border-left-color: var(--border-strong); border-style: dashed; }
.ev.st-noshow { border-left-color: var(--danger); background: var(--danger-tint); }
.ev.st-cancel { border-left-color: var(--border-strong); opacity: 0.55; }
.ev.st-cancel .ev-pat { text-decoration: line-through; }

/* Модалка */
.modal-wrap { position: fixed; inset: 0; background: oklch(0.24 0.015 235 / 0.4); z-index: var(--z-modal); display: grid; place-items: center; padding: var(--sp-5); }
.modal-card { background: var(--bg); border-radius: var(--r-lg); box-shadow: var(--shadow-lg); width: 100%; max-width: 440px; overflow: hidden; }
.modal-card.wide { max-width: 620px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border); }
.modal-head h3 { margin: 0; font-size: 16px; font-weight: 600; }
.modal-x { border: none; background: none; color: var(--muted); font-size: 18px; width: 30px; height: 30px; border-radius: var(--r-sm); }
.modal-x:hover { background: var(--surface-sunken); color: var(--ink); }
.modal-body { padding: var(--sp-4) var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.ev-row { display: flex; justify-content: space-between; gap: var(--sp-4); font-size: 13.5px; padding: 5px 0; border-bottom: 1px solid var(--border); }
.ev-row span:first-child { color: var(--muted); }
.modal-foot { display: flex; gap: var(--sp-2); justify-content: flex-end; padding: var(--sp-3) var(--sp-5) var(--sp-4); }
.st-badge { font-size: 12px; font-weight: 600; padding: 2px 10px; border-radius: 999px; }
.st-badge.sm { font-size: 11px; padding: 1px 8px; }
.st-badge.st-done { background: var(--success-tint); color: var(--success); }
.st-badge.st-conf { background: var(--primary-tint); color: var(--primary-hover); }
.st-badge.st-plan { background: var(--surface-sunken); color: var(--muted); }
.st-badge.st-noshow { background: var(--danger-tint); color: var(--danger); }
.st-badge.st-cancel { background: var(--surface-sunken); color: var(--muted); }

/* Карта пациента */
.pc-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border); }
.avatar.lg { width: 44px; height: 44px; font-size: 15px; }
.avatar.sm-av { width: 26px; height: 26px; font-size: 10px; }
.pc-name { font-size: 17px; font-weight: 600; }
.pc-sub { font-size: 13px; color: var(--muted); }
.pc-tabs { display: flex; gap: var(--sp-1); padding: 0 var(--sp-5); border-bottom: 1px solid var(--border); }
.pc-tab { border: none; background: none; padding: var(--sp-3) var(--sp-3); font-size: 13px; font-weight: 500; color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -1px; }
.pc-tab:hover { color: var(--ink); }
.pc-tab.active { color: var(--primary-hover); border-bottom-color: var(--primary); font-weight: 600; }
.pc-body { padding: var(--sp-5); min-height: 240px; max-height: 60dvh; overflow-y: auto; }
.pc-empty { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); text-align: center; color: var(--muted); padding: var(--sp-6) var(--sp-4); }
.pc-empty.small { padding: var(--sp-4); }
.pc-empty .icon { color: var(--border-strong); width: 34px; height: 34px; }
.pc-empty p { margin: 0; max-width: 360px; font-size: 13.5px; line-height: 1.5; }

/* Программа лечения */
.prog-card { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-4); }
.prog-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.prog-course { font-size: 15px; font-weight: 600; }
.prog-spec { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.prog-bar-wrap { margin-bottom: var(--sp-4); }
.prog-bar { height: 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.prog-bar span { display: block; height: 100%; background: var(--primary); border-radius: 999px; transition: width 400ms ease-out; }
.prog-nums { font-size: 13px; color: var(--muted); margin-top: 6px; font-variant-numeric: tabular-nums; }
.prog-nums b { color: var(--ink); font-weight: 700; }
.prog-dots { display: flex; flex-wrap: wrap; gap: 5px; }
.pdot { width: 26px; height: 26px; border-radius: var(--r-sm); background: var(--bg); border: 1px solid var(--border); display: grid; place-items: center; font-size: 11px; font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; }
.pdot.on { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.prog-next { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--border); }
.next-info { font-size: 13px; display: flex; align-items: center; gap: 6px; }
.next-info.muted { color: var(--muted); }
.next-info b { font-weight: 600; }

/* Визиты */
.visit-list { display: flex; flex-direction: column; gap: 4px; }
.visit-row { display: grid; grid-template-columns: 12px 130px 1fr 150px auto; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 13px; }
.visit-when { font-variant-numeric: tabular-nums; color: var(--muted); }
.visit-spec { color: var(--muted); font-size: 12px; }

/* Курсы на завершении (контроль) */
.course-list { display: flex; flex-direction: column; gap: 4px; }
.course-row { display: grid; grid-template-columns: 26px 1fr 1.4fr auto 1.2fr auto; align-items: center; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border); font-size: 13px; }
.course-pat { font-weight: 500; }
.course-name { color: var(--muted); font-size: 12.5px; }
.course-left { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--warning); }
.course-left.zero { color: var(--danger); }
.course-spec { color: var(--muted); font-size: 12px; }

@media (max-width: 900px) {
  .visit-row { grid-template-columns: 12px 1fr auto; }
  .visit-type, .visit-spec { display: none; }
  .course-row { grid-template-columns: 26px 1fr auto auto; }
  .course-name, .course-spec { display: none; }
}

/* ============================================================
   Доработки: карточка сделки, оплаты, общение, группы, фильтры
   ============================================================ */
.ok-txt { color: var(--success); } .danger-txt { color: var(--danger); }
.mini-tag { font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: 999px; background: var(--surface-sunken); color: var(--muted); }
.mini-tag.ad { background: var(--primary-tint); color: var(--primary-hover); }
.mini-tag.partner { background: var(--success-tint); color: var(--success); }
.mini-tag.warn { background: var(--warning-tint); color: oklch(0.48 0.11 75); }

/* Карточка сделки */
.lc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-5); margin-bottom: var(--sp-4); }
.lc-field { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); }
.lc-field span { font-size: 11.5px; color: var(--muted); }
.lc-field b { font-size: 13.5px; font-weight: 500; display: flex; align-items: center; gap: 6px; }
.unassigned-txt { color: var(--danger); }
.lc-section { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; margin: var(--sp-3) 0 var(--sp-2); display: flex; align-items: baseline; gap: var(--sp-2); }
.lc-hint { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 11.5px; color: var(--muted); }
.lc-feed, .chat-feed { display: flex; flex-direction: column; gap: 6px; }
.feed-item { display: flex; align-items: flex-start; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); font-size: 13px; }
.feed-item .icon { color: var(--muted); flex-shrink: 0; margin-top: 1px; }
.feed-item.warn { background: var(--warning-tint); border-color: oklch(0.85 0.06 75); }
.feed-item.warn .icon { color: oklch(0.55 0.12 75); }
.feed-item b { font-weight: 500; display: block; }
.feed-item span { font-size: 11.5px; color: var(--muted); }
.lc-foot { align-items: center; }
.foot-spacer { flex: 1; }
.danger-btn { color: var(--danger); }
.danger-btn:hover { background: var(--danger-tint); border-color: var(--danger); }

/* Причины отказа */
.decline-list { display: flex; flex-direction: column; gap: 6px; }
.decline-opt { text-align: left; padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg); font-size: 13.5px; font-weight: 500; transition: all 120ms ease-out; }
.decline-opt:hover { border-color: var(--danger); background: var(--danger-tint); color: var(--danger); }

/* Оплаты */
.pay-summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); margin-bottom: var(--sp-4); }
.pay-kpi { background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); }
.pay-kpi span { font-size: 12px; color: var(--muted); display: block; }
.pay-kpi b { font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }

/* Общение (msg-line) */
.msg-line { display: flex; flex-direction: column; gap: 2px; }
.msg-line.out { align-items: flex-end; }
.msg-line.in { align-items: flex-start; }
.msg-note { font-size: 10.5px; color: var(--muted); padding: 0 6px; }

/* Программа: группа-примечание */
.prog-group { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.prog-group .icon { color: var(--primary); }
.visit-head { font-size: 13px; color: var(--muted); margin-bottom: var(--sp-3); display: flex; align-items: center; gap: 6px; }
.visit-head b { color: var(--ink); }

/* Группы (режим расписания) */
.groups-wrap { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--sp-3); padding: var(--sp-4) var(--sp-5); max-width: 1080px; }
.group-card { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.group-head { display: flex; align-items: flex-start; justify-content: space-between; }
.group-name { font-size: 15px; font-weight: 600; }
.group-sub { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.group-fill { height: 8px; background: var(--surface-sunken); border-radius: 999px; overflow: hidden; }
.group-fill span { display: block; height: 100%; background: var(--primary); border-radius: 999px; }
.group-members { display: flex; flex-wrap: wrap; gap: 5px; }
.gm { font-size: 11.5px; padding: 2px 8px; background: var(--surface-sunken); border-radius: var(--r-sm); color: var(--ink); }
.gm.more { background: var(--primary-tint); color: var(--primary-hover); font-weight: 600; }
.group-add { align-self: flex-start; }

/* Фильтры-селекты расписания */
.sched-sel { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--muted); }
.sched-sel select { font-family: inherit; font-size: 12.5px; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 4px 8px; background: var(--bg); color: var(--ink); outline: none; }
.sched-sel select:focus { border-color: var(--primary); }
.ev-conf { color: var(--success); display: inline-flex; }

@media (max-width: 720px) {
  .lc-grid { grid-template-columns: 1fr; }
  .pay-summary { grid-template-columns: 1fr; }
}

/* ============================================================
   Экран «Деньги» — касса, места хранения, ступени оплаты
   ============================================================ */

/* числовые колонки таблиц: цифры в столбик, минус читается как минус */
.tbl td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.tbl td.num.neg { color: var(--danger); }
.bar-cell .bar.out { background: var(--border-strong); }

/* пояснение под панелью — тише основного текста, но не спрятано */
.panel-foot { display: flex; align-items: flex-start; gap: var(--sp-2); margin-top: var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--border);
  font-size: 12.5px; line-height: 1.5; color: var(--muted); }
.panel-foot .icon { color: var(--warning); flex: none; margin-top: 1px; }

/* лента операций: дата · знак · сумма · кто · за что · чем платили */
.money-feed { display: flex; flex-direction: column; }
.money-row { display: grid; grid-template-columns: 46px 14px 108px 170px 1fr 132px;
  align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--border); font-size: 13px; }
.money-row:last-child { border-bottom: 0; }
.money-date { color: var(--muted); font-variant-numeric: tabular-nums; font-size: 12.5px; }
.money-dir { font-weight: 600; text-align: center; color: var(--success); }
.money-dir.out { color: var(--muted); }
.money-sum { font-variant-numeric: tabular-nums; font-weight: 600; }
.money-sum.out { color: var(--muted); font-weight: 500; }
.money-who { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.money-what { color: var(--muted); display: flex; align-items: center; gap: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.money-place { color: var(--muted); font-size: 12px; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 900px) {
  .money-row { grid-template-columns: 44px 12px 100px 1fr; }
  .money-what, .money-place { display: none; }
}

/* Воронка, которой ещё нет в FitBase (Реактивация) — объясняем, а не показываем пустую доску */
.funnel-planned { display: flex; align-items: flex-start; gap: var(--sp-3); margin: var(--sp-5);
  padding: var(--sp-4) var(--sp-5); max-width: 720px;
  background: var(--surface); border: 1px dashed var(--border-strong); border-radius: var(--r-md);
  font-size: 13.5px; line-height: 1.55; color: var(--muted); }
.funnel-planned .icon { color: var(--primary); flex: none; }
.funnel-planned b { color: var(--ink); }

/* ============================================================
   Экран «Сотрудники» (раздел руководителя)
   ============================================================ */

.cell-sub { font-size: 12px; color: var(--muted); margin-top: 1px; }
.tbl tbody tr.row-off { color: var(--muted); }
.tbl tbody tr.row-off .cell-name { font-weight: 400; }

/* роль — тихая метка: цвет означает рабочее место, а не «важность» человека */
.role-tag { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 12px;
  background: var(--surface-sunken); color: var(--ink); white-space: nowrap; }
.role-manager { background: oklch(0.95 0.03 265); }
.role-admin { background: oklch(0.95 0.03 200); }
.role-therapist { background: oklch(0.95 0.04 160); }
.role-head { background: oklch(0.95 0.04 75); }
.role-external { background: var(--surface-sunken); color: var(--muted); }

.pill.ok { background: oklch(0.95 0.05 150); color: oklch(0.42 0.12 150); }

.role-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-3); }
.role-card { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-4);
  display: flex; flex-direction: column; gap: var(--sp-2); }
.role-name { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: var(--sp-2); }
.role-count { font-size: 12px; font-weight: 500; color: var(--muted);
  background: var(--surface-sunken); border-radius: 999px; padding: 1px 8px; }
.role-what { font-size: 12.5px; color: var(--muted); line-height: 1.45; }
.role-sees { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.role-sees li { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }
.role-sees .icon { color: var(--success); flex: none; }
.role-system { background: var(--surface-sunken); color: var(--muted); font-style: italic; }

/* ============================================================
   Экраны настоящей системы (Django): вход, сотрудники, формы
   Дизайн-система общая с прототипом — см. app/DESIGN.md
   ============================================================ */

body.plain { background: var(--surface); }

.login-wrap { min-height: 100dvh; display: grid; place-items: center; padding: var(--sp-5); }
.login-card { width: 100%; max-width: 380px; background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-4); }
.login-brand { margin-bottom: var(--sp-2); }
.login-card h1 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -0.01em; }
.login-note { margin: 0; font-size: 12px; color: var(--muted); line-height: 1.5; }

.field { display: flex; flex-direction: column; gap: 5px; font-size: 13px; }
.field > span { font-weight: 500; }
/* Оформляем ТОЛЬКО поля, лежащие прямо в подписи: `.field > input`.
   Поля внутри готовых узлов (поиск с иконкой, выбор человека) правило не трогает
   вовсе — иначе получается рамка в рамке, а бороться с этим специфичностью
   бессмысленно: у общего правила два :not(), и оно всё равно перевешивает. */
.field > input:not([type="checkbox"]):not([type="radio"]),
.field > select, .field > textarea {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: 9px 11px; outline: none; }
.field > input:focus, .field > select:focus, .field > textarea:focus {
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.field > input:disabled { background: var(--surface-sunken); color: var(--muted); }
.field-hint { font-size: 11.5px; color: var(--muted); font-style: normal; line-height: 1.45; }
.field-error { font-size: 11.5px; color: var(--danger); font-style: normal; }
.field-check { flex-direction: row; align-items: center; gap: var(--sp-2); }
.field-check input { width: 16px; height: 16px; }

.form-error { background: var(--danger-tint); color: var(--danger); border-radius: var(--r-sm);
  padding: 9px 11px; font-size: 13px; }
.form-panel { max-width: 620px; }
/* Сетка формы: два столбца равной ширины. Поле НЕ растягивается из-за того,
   что у него есть подсказка — иначе сетка рвётся в клочья и поля прыгают
   по ширине от строки к строке. Растягивается только то, что помечено явно. */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4);
  align-items: start; }
.form-grid .field-check { grid-column: span 2; }
.form-grid > .field { min-width: 0; }
.form-grid > .field > input:not([type="checkbox"]):not([type="radio"]),
.form-grid > .field > select, .form-grid > .field > textarea { width: 100%; box-sizing: border-box; }
.form-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-5); }
.btn-wide { width: 100%; justify-content: center; }
.btn.danger { color: var(--danger); }

.card-head { display: flex; align-items: center; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.avatar.big { width: 52px; height: 52px; font-size: 18px; }
.card-name { font-size: 19px; font-weight: 600; display: flex; align-items: center; gap: var(--sp-2); }
.card-sub { display: flex; align-items: center; gap: var(--sp-2); margin-top: 5px;
  font-size: 12.5px; color: var(--muted); }

.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-4); margin: 0; }
.facts div { display: flex; flex-direction: column; gap: 3px; }
.facts dt { font-size: 12px; color: var(--muted); }
.facts dd { margin: 0; font-size: 14px; font-variant-numeric: tabular-nums; }

.role-sees.big li { font-size: 13.5px; }
.sidebar-exit { margin-left: auto; color: var(--muted); display: flex; }
.sidebar-exit:hover { color: var(--ink); }

/* Выход — форма, а не ссылка: система принимает выход только отправкой формы,
   иначе чужая страница смогла бы разлогинить сотрудника картинкой */
.sidebar-exit-form { margin-left: auto; }
.sidebar-exit { display: flex; align-items: center; gap: 5px; background: none; border: 0;
  padding: 4px 6px; border-radius: var(--r-sm); cursor: pointer;
  font-family: inherit; font-size: 12px; color: var(--muted); }
.sidebar-exit:hover { color: var(--ink); background: var(--surface-sunken); }

/* Главная: что уже работает на моём рабочем месте, а что ещё строится */
.ready-list { display: flex; flex-direction: column; }
.ready-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border); }
.ready-row:last-child { border-bottom: 0; }
.ready-row > .icon { color: var(--border-strong); flex: none; }
.ready-row.is-ready > .icon { color: var(--success); }
.ready-row > div { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.ready-row b { font-weight: 500; font-size: 13.5px; color: var(--muted); }
.ready-row.is-ready b { color: var(--ink); }
.ready-row span { font-size: 12.5px; color: var(--muted); }

/* Статусы пациента — тихие метки одного семейства с ролями */
.status-active { background: oklch(0.95 0.05 150); }
.status-potential { background: oklch(0.95 0.03 265); }
.status-new { background: oklch(0.95 0.03 200); }
.status-risk { background: oklch(0.95 0.06 75); }
.status-closed { background: var(--surface-sunken); color: var(--muted); }
.form-grid .field-wide { grid-column: span 2; }

/* Семья в карточке пациента: родитель и дети — живые ссылки, а не подпись в поле */
.family-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border); }
.family-row:last-child { border-bottom: 0; }
.family-row > div { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.family-row .cell-name { font-weight: 500; color: var(--primary); text-decoration: none; }
.family-row .cell-name:hover { text-decoration: underline; }
.family-row span { font-size: 12.5px; color: var(--muted); }

/* Выбор человека поиском: списком в тысячу карточек пользоваться невозможно */
.picker { position: relative; }
.picker .hidden { display: none; }
.picker-search { display: flex; align-items: center; gap: var(--sp-2); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: 0 11px; }
.picker-search .icon { color: var(--muted); flex: none; }
.picker-search input { flex: 1; border: 0; outline: none; padding: 9px 0; font-family: inherit;
  font-size: 14px; color: var(--ink); background: none; }
.picker-search:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }

.picker-chosen { display: flex; align-items: center; gap: var(--sp-2); padding: 8px 11px;
  background: var(--primary-tint); border: 1px solid var(--primary); border-radius: var(--r-sm);
  font-size: 14px; }
.picker-chosen .icon { color: var(--primary); }
.picker-chosen b { font-weight: 500; flex: 1; }
.picker-clear { background: none; border: 0; cursor: pointer; font-size: 18px; line-height: 1;
  color: var(--muted); padding: 0 4px; }
.picker-clear:hover { color: var(--danger); }

.picker-results { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  background: var(--bg); border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  box-shadow: 0 10px 24px oklch(0.2 0.02 235 / 0.12); max-height: 280px; overflow-y: auto; }
.picker-item { display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left;
  background: none; border: 0; border-bottom: 1px solid var(--border); padding: 9px 11px;
  cursor: pointer; font-family: inherit; }
.picker-item:last-child { border-bottom: 0; }
.picker-item:hover { background: var(--primary-tint); }
.picker-item b { font-size: 13.5px; font-weight: 500; }
.picker-item span { font-size: 12px; color: var(--muted); }
.picker-warn { font-size: 11.5px; color: var(--danger); font-style: normal; }
.picker-empty { padding: 12px; font-size: 13px; color: var(--muted); }

/* ============================================================
   Расписание — сетка «часы × дни»
   ------------------------------------------------------------
   Устроено как в кабинете FitBase, и это правильный выбор: администратор
   уже думает такой сеткой. В одном часу идут несколько приёмов у разных
   терапевтов и в разных залах, поэтому ячейка — стопка карточек, а не один
   слот, и записать в неё можно всегда, даже когда там уже кто-то стоит.

   Состояние приёма показывается фоном и меткой, а не цветной полосой слева:
   полоса кричит громче, чем значит (см. DESIGN.md → что осознанно не делаем).
   ============================================================ */

.grid { display: grid; grid-template-columns: 56px repeat(7, minmax(148px, 1fr));
  gap: 1px; background: var(--border); border-bottom: 1px solid var(--border); min-width: 980px; }

/* шапка дней и колонка часов держатся при прокрутке — иначе в четверг
   уже непонятно, какой это день и который час */
.grid-corner, .grid-day { position: sticky; top: 0; z-index: 2; background: var(--surface); }
.grid-day { display: flex; align-items: baseline; gap: 6px; padding: 9px 10px;
  border-bottom: 1px solid var(--border); }
.grid-day.is-today { background: var(--primary-tint); }
.grid-day.is-past { color: var(--muted); }
.grid-wd { font-weight: 600; font-size: 13px; }
.grid-date { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.grid-day .badge { margin-left: auto; }

/* счётчик приёмов в шапке дня. Красный означает «есть приёмы без отметки» —
   этого достаточно, заливка на пол-ячейки кричит громче, чем значит */
.badge { font-size: 11.5px; font-variant-numeric: tabular-nums; color: var(--muted); }
.badge.is-alert { color: var(--danger); font-weight: 600; }

.grid-hour { position: sticky; left: 0; z-index: 1; background: var(--surface);
  padding: 8px 8px 0 0; text-align: right; font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }

.grid-cell { background: var(--bg); padding: 5px; display: flex; flex-direction: column;
  gap: 4px; min-height: 46px; }
.grid-cell.is-today { background: oklch(0.995 0.006 195); }
.grid-cell.is-past { background: var(--surface); }

/* Карточка приёма. Три строки сверху вниз: когда, кто, что за приём и у кого.
   Заливок по статусу нет: на неделе сотня карточек, и сплошной зелёный с красным
   превращают сетку в светофор, где не видно главного. Состояние показывает
   один мелкий значок, и только «приём прошёл, отметки нет» имеет право на красную
   рамку — это единственная поломка учёта, которую нельзя пропустить. */
.appt { display: block; padding: 5px 7px 6px; text-decoration: none; color: inherit;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
  transition: border-color 160ms cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 160ms cubic-bezier(0.22, 1, 0.36, 1); }
.appt:hover { border-color: var(--border-strong); box-shadow: 0 1px 3px oklch(0.2 0.02 235 / 0.07); }
.appt:focus-visible { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }
.appt.is-done { background: var(--surface); }
.appt.is-off { background: var(--surface); }
/* отменённый и не пришедший: имя зачёркнуто — видно, что слот отработан, но пациента не было */
.appt.is-off .appt-name { text-decoration: line-through; color: var(--muted); }
.appt.is-alert { border-color: oklch(0.82 0.09 25); }

.appt-line { display: flex; align-items: center; gap: 4px; }
.appt-time { font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--muted); letter-spacing: 0.01em; }
.appt-marks { margin-left: auto; display: inline-flex; gap: 3px; }
.appt-name { display: block; font-size: 12.5px; font-weight: 500; margin: 1px 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.appt-sub { font-size: 11px; color: var(--muted); }
.appt-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* инициалы специалиста вместо фамилии: в колонке шириной 150px фамилия всё равно
   обрезалась многоточием, а инициалы читаются и не спорят с именем пациента */
.appt-spec { margin-left: auto; font-size: 10.5px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--muted); flex-shrink: 0; }

.mark { display: inline-flex; align-items: center; justify-content: center;
  min-width: 14px; height: 14px; border-radius: 4px; font-size: 10px; font-weight: 700;
  line-height: 1; padding: 0 3px; }
.mark-unpaid { background: oklch(0.95 0.06 75); color: oklch(0.42 0.12 75); }
/* «отметки нет» встречается у трети прошедших приёмов, поэтому значок мягкий:
   двенадцать сплошных красных квадратов на экране перестают быть сигналом.
   Сам сигнал держит рамка карточки — её видно, но она не кричит */
.mark-alert { background: var(--danger-tint); color: oklch(0.45 0.17 25); }
.mark-done { background: oklch(0.93 0.06 150); color: oklch(0.40 0.12 150); }
.mark-off { background: var(--surface-sunken); color: var(--muted); }

/* «Записать» лежит в каждой свободной ячейке и остаётся доступным, даже когда
   приёмы в этом часу уже есть.

   Знак виден всегда, без наведения (I-11, Ирада Ибрагимова). Наведения нет там,
   где она работает: расписание открывают с телефона по ходу переписки с пациентом,
   и подсказка, живущая на ховере, на тач-экране не существует вовсе.

   При этом знак — один плюс: без рамки и без слова. Пунктирный прямоугольник
   с надписью в каждой из девяноста ячеек давал стену одинаковых плашек, в которой
   тонули настоящие занятия — то есть ровно то, ради чего в сетку и смотрят.
   Ткань из тихих плюсов читается как «сюда можно», а спорить с карточками
   приёма не начинает. Цель нажатия при этом остаётся во всю ширину ячейки —
   попасть пальцем нужно в неё, а не в значок. */
.cell-add { display: flex; align-items: center; justify-content: center; min-height: 26px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  color: oklch(0.66 0.014 235); text-decoration: none;
  transition: color 140ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 140ms cubic-bezier(0.22, 1, 0.36, 1),
    border-color 140ms cubic-bezier(0.22, 1, 0.36, 1); }
.cell-add-mark { width: 15px; height: 15px; flex: none; stroke-width: 1.6;
  transition: transform 140ms cubic-bezier(0.22, 1, 0.36, 1); }

/* Второстепенное меньше, а не бледнее.
   Час, в котором уже кто-то стоит, и час, который уже прошёл, — ходы запасные:
   записывают туда реже. Но выцветший до невидимости знак — это ровно та жалоба,
   с которой задача началась, поэтому тише они становятся размером, а не цветом:
   контраст знака везде держится около 3:1, как положено органу управления. */
.cell-add.is-busy .cell-add-mark,
.cell-add.is-past .cell-add-mark { width: 12px; height: 12px; }

/* наведение и клавиатура — знак становится действием */
.cell-add:hover, .cell-add:focus-visible { color: var(--primary);
  border-color: var(--primary); background: var(--primary-tint); }
.cell-add:hover .cell-add-mark, .cell-add:focus-visible .cell-add-mark { transform: scale(1.12); }
.cell-add:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.cell-add:active { background: var(--primary-tint); border-color: var(--primary); }

/* Телефон и планшет: наведения нет, экран мельче и часто на свету — знак темнее
   и крупнее, а цель нажатия выше, чтобы попадать пальцем, а не ногтем. */
@media (hover: none) {
  .cell-add { min-height: 34px; color: oklch(0.62 0.016 235); }
  .cell-add-mark { width: 17px; height: 17px; }
  .cell-add.is-busy .cell-add-mark,
  .cell-add.is-past .cell-add-mark { width: 14px; height: 14px; }
}

/* Строка «вне часов»: сетка держит рабочее окно 8:00–21:00, но запись, поставленная
   на ночь или на раннее утро, не должна исчезать с экрана — она собирается сюда,
   над сеткой. Раньше из-за одной такой записи весь рабочий день уезжал под сгиб. */
.grid-hour.is-outside { font-size: 10.5px; line-height: 1.25; padding-top: 7px;
  color: var(--muted); }
.grid-cell.is-outside { background: var(--surface-sunken); }
.grid-cell.is-outside:empty { min-height: 32px; }

@media (prefers-reduced-motion: reduce) {
  .appt, .cell-add, .cell-add-mark { transition: none; }
  .cell-add:hover .cell-add-mark, .cell-add:focus-visible .cell-add-mark { transform: none; }
}

/* Навигация по неделям */
.weeknav { display: inline-flex; align-items: center; gap: 2px; }
.weeknav-arrow, .weeknav-now { display: inline-flex; align-items: center; justify-content: center;
  height: 28px; padding: 0 10px; border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--r-sm); font-size: 12.5px; color: var(--ink); text-decoration: none; }
.weeknav-arrow { width: 30px; padding: 0; color: var(--muted); }
.weeknav-arrow:hover, .weeknav-now:hover { border-color: var(--border-strong); }
.weeknav-range { display: inline-flex; align-items: baseline; gap: 6px; padding: 0 10px;
  font-size: 13px; font-weight: 500; white-space: nowrap; }
.weeknav-range em { font-style: normal; font-size: 11px; font-weight: 400; color: var(--primary);
  background: var(--primary-tint); border-radius: 999px; padding: 1px 7px; }

@media (max-width: 900px) {
  .grid { min-width: 780px; }
}

/* Только что созданная запись: подводим к ней экран и держим подсветку несколько секунд */
.appt.is-new { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint);
  animation: appt-arrive 420ms cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes appt-arrive {
  from { transform: scale(0.96); }
  to { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .appt.is-new { animation: none; }
}

/* Финансы: две колонки на широком экране, одна на узком */
.two-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--sp-4); }
.tbl tbody tr.row-current { background: var(--primary-tint); font-weight: 500; }
.tbl tbody tr.row-current a { color: var(--primary-hover); }

/* Касса: места хранения строкой сверху — по ним же фильтруется лента операций */
.places { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5);
  background: var(--surface); border-bottom: 1px solid var(--border); overflow-x: auto; }
.place-card { display: flex; flex-direction: column; gap: 2px; min-width: 150px;
  padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); text-decoration: none; white-space: nowrap;
  transition: border-color 140ms ease-out; }
.place-card:hover { border-color: var(--border-strong); }
.place-card.is-active { border-color: var(--primary); background: var(--primary-tint); }
.place-name { font-size: 12px; color: var(--muted); }
.place-card.is-active .place-name { color: var(--primary-hover); }
.place-sum { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.place-sum.neg { color: var(--danger); }

/* приход и расход различаются меткой, а не заливкой всей строки */
.op { font-size: 11.5px; padding: 1px 8px; border-radius: 999px; }
.op-in { background: oklch(0.95 0.05 150); color: oklch(0.42 0.12 150); }
.op-out { background: var(--surface-sunken); color: var(--muted); }
.op-detail { display: block; font-size: 11.5px; color: var(--muted); }
.op-move { background: oklch(0.95 0.03 265); color: oklch(0.45 0.1 265); }

/* ============================================================
   Окна быстрых действий
   ------------------------------------------------------------
   Нативный <dialog>: фокус, Esc и подложка достаются бесплатно.
   Используются там, где действие короткое и контекст важен —
   принять оплату, внести расход, перевести между кассами: список
   операций остаётся на виду, и после сохранения видно результат.
   Всё, что длиннее пяти полей, по-прежнему живёт отдельной страницей.
   ============================================================ */

.modal { border: 0; padding: 0; border-radius: var(--r-md); background: var(--bg);
  color: var(--ink); width: min(560px, calc(100vw - 32px)); max-height: calc(100dvh - 64px);
  overflow: hidden; box-shadow: 0 24px 64px oklch(0.2 0.02 235 / 0.22); }
.modal::backdrop { background: oklch(0.2 0.02 235 / 0.35); backdrop-filter: blur(1px); }
.modal[open] { animation: modal-in 180ms cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(6px) scale(0.99); }
  to { opacity: 1; transform: none; }
}

/* Шапка и низ окна стоят на месте, ездит только середина: иначе при длинной форме
   заголовок и кнопки уползают, и непонятно, где ты находишься. */
.modal-form { display: flex; flex-direction: column; max-height: calc(100dvh - 64px);
  min-height: 0; }
.modal-head { display: flex; align-items: center; gap: var(--sp-3); flex: none;
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border);
  background: var(--bg); }
.modal-head h2 { margin: 0; font-size: 16px; font-weight: 600; flex: 1; }
.modal-close { background: none; border: 0; font-size: 22px; line-height: 1; cursor: pointer;
  color: var(--muted); padding: 0 4px; border-radius: var(--r-sm); }
.modal-close:hover { color: var(--ink); }
.modal-close:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.modal-body { padding: var(--sp-5); overflow-y: auto; flex: 1 1 auto; min-height: 0; }
.modal-note { margin-top: var(--sp-4); font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.modal-foot { display: flex; gap: var(--sp-2); padding: var(--sp-4) var(--sp-5); flex: none;
  border-top: 1px solid var(--border); background: var(--surface); }

@media (prefers-reduced-motion: reduce) {
  .modal[open] { animation: none; }
}
/* остаток после операции — только когда выбрана одна касса: по всем сразу он бессмыслен */
.tbl td.running { font-weight: 600; }
.tbl tfoot td { padding: var(--sp-3); border-top: 1px solid var(--border-strong);
  font-size: 12.5px; color: var(--muted); }

/* ============================================================
   Верхняя панель экрана — одинаковая везде
   ------------------------------------------------------------
   Порядок слева направо всегда один: назад (если есть) → название экрана →
   вкладки раздела → пусто → действия. Без этого правила вкладки на разных
   экранах оказываются то слева, то справа, и меню «прыгает» при переходе.
   ============================================================ */
.topbar { display: flex; align-items: center; gap: var(--sp-3); }
/* «назад» всегда первой: без своего порядка она уезжала за распорку вправо,
   а кнопка в <form> (порядок по умолчанию 0) обгоняла даже название экрана */
.topbar .btn-back { order: 0; }
.topbar form { order: 5; }
.topbar .page-title { order: 1; }
.topbar .funnel-tabs { order: 2; }
.topbar .topbar-spacer { order: 3; flex: 1; }
.topbar .search { order: 4; }
.topbar .btn { order: 5; }

/* Сводка по выбранной кассе */
.kpi-row.tight { margin-bottom: var(--sp-4); }
.kpi-row.tight .kpi-val { font-size: 22px; }

/* остаток по дням: не график ради графика, а линия для сверки с ящиком */
.daybar { display: flex; align-items: flex-end; gap: 3px; height: 96px;
  padding-top: var(--sp-2); border-top: 1px solid var(--border); }
.daybar-col { flex: 1; min-width: 12px; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; height: 100%; gap: 4px; }
.daybar-fill { width: 100%; max-width: 26px; background: var(--primary); border-radius: 3px 3px 0 0;
  min-height: 2px; }
.daybar-fill.is-neg { background: var(--danger); }
.daybar-day { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ============================================================
   Курс лечения: сколько пройдено и сколько осталось
   ============================================================ */

.progress { position: relative; height: 20px; background: var(--surface-sunken);
  border-radius: var(--r-sm); overflow: hidden; min-width: 110px; }
.progress-bar { height: 100%; background: var(--primary); opacity: 0.25; }
.progress-bar.is-ending { background: var(--warning); opacity: 0.35; }
.progress-text { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* каждое занятие — точка: видно и пройденное, и оставшееся */
.course-progress { display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-4) 0; }
.course-dots { display: flex; flex-wrap: wrap; gap: 5px; }
.dot-visit { width: 22px; height: 22px; border-radius: 50%; border: 1.5px dashed var(--border-strong); }
.dot-visit.is-done { background: var(--primary); border: 0; }
.course-text { font-size: 13.5px; color: var(--muted); }
.course-text b { color: var(--ink); }
.course-row { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border); }
.course-row:last-child { border-bottom: 0; }
.course-name { flex: 1; font-weight: 500; color: var(--ink); text-decoration: none; }
.course-name:hover { color: var(--primary); }
.course-row .progress { width: 140px; flex: none; }
.course-state { font-size: 12.5px; color: var(--muted); min-width: 120px; text-align: right; }

/* ============================================================
   Доска сделок: колонки-этапы, карточки-сделки
   ============================================================ */

.board { display: flex; gap: 1px; background: var(--border); padding: 1px;
  align-items: flex-start; min-height: 100%; overflow-x: auto; }
.col { background: var(--bg); min-width: 232px; flex: 1; display: flex; flex-direction: column;
  max-height: calc(100dvh - 150px); }
.col.is-dump { background: var(--surface); }
.col.is-won .col-head { color: var(--success); }
.col.is-lost .col-head { color: var(--danger); }
.col.drop-target { background: var(--primary-tint); }

.col-head { display: flex; align-items: baseline; gap: var(--sp-2); padding: 10px 12px;
  border-bottom: 1px solid var(--border); position: sticky; top: 0; background: inherit; z-index: 1; }
.col-name { font-size: 12.5px; font-weight: 600; }
.col-count { margin-left: auto; font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.col-body { display: flex; flex-direction: column; gap: 6px; padding: 8px; overflow-y: auto; }
.col-empty { text-align: center; font-size: 11.5px; color: var(--muted); padding: 10px; }
.col-more { text-align: center; font-size: 11px; color: var(--muted); padding: 6px; }

.lead { border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
  cursor: grab; transition: border-color 140ms ease-out, box-shadow 140ms ease-out; }
.lead:hover { border-color: var(--border-strong); box-shadow: 0 1px 3px oklch(0.2 0.02 235 / 0.07); }
.lead.dragging { opacity: 0.5; }
.lead.is-overdue { border-color: oklch(0.88 0.06 25); background: var(--danger-tint); }
.lead-open { display: block; padding: 8px 10px; text-decoration: none; color: inherit; }
.lead-name { display: block; font-size: 13px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lead-phone { display: block; font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.lead-meta { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.lead-foot { display: flex; align-items: center; gap: 6px; margin-top: 7px; }
.lead-owner { width: 20px; height: 20px; border-radius: 50%; background: var(--surface-sunken);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 9.5px; font-weight: 600; color: var(--muted); }
.lead-owner.is-none { background: var(--danger-tint); color: var(--danger); }
.due { font-size: 11px; color: var(--muted); }
.due.overdue { color: var(--danger); font-weight: 500; }
.due.none { font-style: italic; }

/* Задачи: очередь дел, просроченное сверху */
.task-list { display: flex; flex-direction: column; }
.task { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border); }
.task:last-child { border-bottom: 0; }
.task-main { flex: 1; min-width: 0; }
.task-text { font-size: 13.5px; font-weight: 500; }
.task.is-done .task-text { color: var(--muted); text-decoration: line-through; }
.task-meta { font-size: 12px; color: var(--muted); margin-top: 2px; }
.task-kind { color: var(--ink); }
.task-side { display: flex; align-items: center; gap: var(--sp-2); flex: none; }
.task-owner { width: 22px; height: 22px; border-radius: 50%; background: var(--surface-sunken);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 600; color: var(--muted); }
.task.is-overdue .due { color: var(--danger); font-weight: 500; }
.task-close { display: flex; gap: 4px; }
.task-close input { border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 5px 9px; font-family: inherit; font-size: 12.5px; width: 190px; }
.task-close input:focus { outline: none; border-color: var(--primary); }

/* ============================================================
   Диалоги: слева переписки, справа выбранная
   ============================================================ */

.inbox { display: grid; grid-template-columns: 300px 1fr; height: calc(100dvh - 52px);
  background: var(--border); gap: 1px; }
.inbox-list { background: var(--bg); overflow-y: auto; display: flex; flex-direction: column; }
.inbox-filters { display: flex; gap: 4px; padding: 10px; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; background: var(--bg); z-index: 1; }

.dlg { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px;
  border-bottom: 1px solid var(--border); text-decoration: none; color: inherit; }
.dlg:hover { background: var(--surface); }
.dlg.is-active { background: var(--primary-tint); }
.dlg.is-late { border-left: 0; }
.dlg-top { display: flex; align-items: baseline; gap: var(--sp-2); }
.dlg-name { font-size: 13px; font-weight: 500; flex: 1; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.dlg-wait { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.dlg-wait.is-late { color: var(--danger); font-weight: 600; }
.dlg-last { font-size: 12px; color: var(--muted); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.dlg-meta { font-size: 11px; color: var(--muted); }

.inbox-chat { background: var(--bg); display: flex; flex-direction: column; min-width: 0; }
.chat-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5); border-bottom: 1px solid var(--border); }
.chat-name { font-size: 15px; font-weight: 600; }
.chat-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.chat-actions { display: flex; gap: var(--sp-2); align-items: center; }

.chat-body { flex: 1; overflow-y: auto; padding: var(--sp-5); display: flex;
  flex-direction: column; gap: var(--sp-3); background: var(--surface); }
.msg { max-width: 68%; padding: 9px 12px; border-radius: var(--r-md); font-size: 13.5px;
  line-height: 1.45; }
.msg.is-in { background: var(--bg); border: 1px solid var(--border); align-self: flex-start;
  border-bottom-left-radius: 4px; }
.msg.is-out { background: var(--primary-tint); border: 1px solid oklch(0.9 0.03 195);
  align-self: flex-end; border-bottom-right-radius: 4px; }
.msg-meta { font-size: 11px; color: var(--muted); margin-top: 4px; }

.chat-send { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border); }
.chat-send input { flex: 1; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 10px 12px; font-family: inherit; font-size: 14px; outline: none; }
.chat-send input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.chat-note { padding: 8px var(--sp-5) var(--sp-3); font-size: 12px; color: var(--muted); }
.badge-warn { background: oklch(0.95 0.06 75); color: oklch(0.45 0.12 75); padding: 3px 9px;
  border-radius: 999px; font-size: 11.5px; }

@media (max-width: 900px) {
  .inbox { grid-template-columns: 1fr; }
}

/* перенесённая карточка: видно, куда она уехала. Подсветка гаснет сама */
.lead.is-moved { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.lead-open:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-sm); }
.col-name { color: inherit; text-decoration: none; }
.col-name:hover { color: var(--primary); }
a.col-more { display: block; text-align: center; font-size: 11px; color: var(--muted);
  padding: 6px; text-decoration: none; border-radius: var(--r-sm); }
a.col-more:hover { color: var(--primary); background: var(--primary-tint); }

/* быстрое окно сделки */
.quick-sub { font-size: 12px; color: var(--muted); margin-top: 3px; }
.quick-links { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-4);
  padding-top: var(--sp-3); border-top: 1px solid var(--border); font-size: 12.5px; }
.dot-has-card { width: 5px; height: 5px; border-radius: 50%; background: var(--success);
  display: inline-block; }
/* инициалы ответственного: 9.5px были за пределом читаемости */
.lead-owner { font-size: 11px; }
/* следующий шаг прямо на карточке: дата без содержания ничего не говорит */
.lead-step { display: block; font-size: 11.5px; color: var(--ink); margin-top: 4px;
  padding: 3px 6px; background: var(--surface-sunken); border-radius: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Быстрое окно: название правится карандашом, история — лентой */
.quick-title-row { display: flex; align-items: center; gap: var(--sp-2); flex: 1; }
.quick-title-row h2 { margin: 0; }
.icon-btn { background: none; border: 0; padding: 3px; border-radius: var(--r-sm);
  color: var(--muted); cursor: pointer; display: inline-flex; }
.icon-btn:hover { color: var(--primary); background: var(--primary-tint); }
.rename-form { display: flex; gap: 6px; flex: 1; }
.rename-form input { flex: 1; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 6px 10px; font-family: inherit; font-size: 15px; }
.rename-form input:focus { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }
.hidden { display: none !important; }

.notes { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.notes-head { font-size: 12px; color: var(--muted); margin-bottom: var(--sp-2); }
.note { padding: 7px 0; border-bottom: 1px solid var(--border); }
.note:last-child { border-bottom: 0; }
.note-text { font-size: 13px; line-height: 1.45; }
.note-meta { font-size: 11px; color: var(--muted); margin-top: 2px; }
.note-empty { font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.note-add { display: flex; gap: var(--sp-2); padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border); background: var(--surface); }
.note-add textarea { flex: 1; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 8px 11px; font-family: inherit; font-size: 13px; resize: vertical; }
.note-add textarea:focus { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }
.note-add-page { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.note-add-page textarea { flex: 1; border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); padding: 9px 11px; font-family: inherit; font-size: 13px; }

/* ============================================================
   Перенос карточки: она должна вести себя как бумажка в руке
   ============================================================ */

.lead { touch-action: manipulation; }         /* чтобы перенос работал и на планшете */
.lead.is-dragging { opacity: 0; }             /* оригинал прячется, летит копия */

.lead-ghost { position: fixed; top: 0; left: 0; z-index: 60; pointer-events: none;
  margin: 0; background: var(--bg); border: 1px solid var(--primary);
  box-shadow: 0 12px 28px oklch(0.2 0.02 235 / 0.22); cursor: grabbing;
  /* положение карточке задаёт скрипт через translate — здесь только подъём и наклон,
     иначе анимация затирает координаты и карточка «залипает» в углу экрана */
  animation: lead-lift 140ms cubic-bezier(0.22, 1, 0.36, 1) forwards; }
@keyframes lead-lift {
  from { transform: scale(1) rotate(0deg); }
  to { transform: scale(1.03) rotate(1.5deg); }
}

/* след на прежнем месте: видно, откуда карточка ушла */
.lead-hole { border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface); }

.col.drop-target { background: var(--primary-tint); }
.col.drop-target .col-head { background: var(--primary-tint); }

@media (prefers-reduced-motion: reduce) {
  .lead-ghost { animation: none; }
}

/* Отказ: причины выбираются одним нажатием ------------------------------------
   Выпадающий список на восьми причинах стоит двух кликов и попадания мышью, поэтому
   менеджер жмёт первое попавшееся — а именно причина отказа и есть всё, ради чего
   форма существует. Плитки: видно все варианты сразу, выбор одним движением. */
.reasons { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--sp-2); margin-bottom: var(--sp-4); }
.reason { display: flex; align-items: center; gap: var(--sp-2); padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface);
  cursor: pointer; font-size: 14px; line-height: 1.25;
  transition: border-color 120ms ease, background 120ms ease; }
.reason:hover { border-color: var(--border-strong); background: var(--surface-sunken); }
.reason input { margin: 0; accent-color: var(--danger); flex: none; }
.reason:has(input:checked) { border-color: var(--danger); background: var(--danger-tint); }
.reason:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }

.btn-primary.danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-primary.danger:hover { background: oklch(0.46 0.16 25); border-color: oklch(0.46 0.16 25); }

/* «← к сделке» стоит с краю: это не отмена, а возврат на шаг назад внутри окна */
.modal-foot .modal-aside { margin-left: auto; }

@media (prefers-reduced-motion: reduce) { .reason { transition: none; } }

/* Перетаскивание карточек: жест принадлежит нам ------------------------------
   Ссылка внутри карточки тащится браузером сама и забирает события себе — тогда
   доска не перетаскивается вообще. Плюс без запрета выделения жест «тянуть» просто
   выделяет текст карточки синим. */
.lead a { -webkit-user-drag: none; }
.lead, .lead a { user-select: none; }
.lead-ghost, .lead-ghost * { user-select: none; }

/* ============================================================
   Задачи — окно новой задачи
   ------------------------------------------------------------
   Поле «про кого» ищет разом пациентов и сделки, поэтому в подсказке
   рядом с именем стоит метка вида. В подсказках раскладка колонкой —
   без выравнивания метка растянулась бы на всю ширину строки.
   ============================================================ */
.picker-item .tag { align-self: flex-start; margin: 3px 0 1px; font-size: 11px; }
.picker-chosen .tag { margin-left: var(--sp-1); }

/* Колонки одной высоты: пустая колонка тоже мишень ---------------------------
   Колонка росла по своему содержимому, и пустой «Отказ» был полоской в 100 пикселей
   у верхнего края — попасть в неё карточкой почти нельзя, а именно туда чаще всего
   и тащат. Теперь все колонки во всю доску, и бросок засчитывается на любой высоте. */
.board { align-items: stretch; }
.col { height: calc(100dvh - 150px); }
.col-body { flex: 1 1 auto; }

/* Доска: колонки — отдельные панели, карточки — отдельные объекты ------------
   Разбор с Пашей 15.08.2026 по утверждённому прототипу. Доска была сеткой в один
   пиксель разделителя: колонки сливались в сплошное полотно, а карточки внутри —
   в ленту без границ между собой. Глаз не мог отделить одну сделку от другой,
   и перетаскивание выглядело как перекладывание строк таблицы, а не карточек.

   Из прототипа взято: утопленный фон доски, колонка-панель с рамкой и радиусом,
   зазор между колонками, тень и отступы у карточки, разделитель перед подвалом. */
.board { gap: var(--sp-3); padding: var(--sp-4); background: var(--surface-sunken);
  align-items: stretch; }
.col { border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface);
  min-width: 264px; flex: 0 0 264px; height: calc(100dvh - 158px); overflow: hidden; }
.col-head { background: var(--surface); border-radius: var(--r-md) var(--r-md) 0 0;
  gap: var(--sp-2); align-items: center; }
.col-accent { width: 8px; height: 8px; border-radius: 3px; flex: none;
  background: var(--border-strong); }
.col-accent[data-role="work"] { background: var(--primary); }
.col-accent[data-role="won"] { background: var(--success); }
.col-accent[data-role="lost"] { background: var(--danger); }
.col-accent[data-role="dump"] { background: oklch(0.62 0.13 75); }
.col-count { background: var(--bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 0 7px; min-width: 22px; text-align: center; font-weight: 600; }
.col-body { gap: var(--sp-2); padding: var(--sp-3); }

.lead { padding: var(--sp-3); display: flex; flex-direction: column; gap: 6px;
  box-shadow: var(--shadow-sm); position: relative;
  transition: box-shadow 150ms ease-out, border-color 150ms ease-out; }
.lead:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.lead-open { display: flex; flex-direction: column; gap: 6px; }
.lead-name { font-size: 14px; font-weight: 600; line-height: 1.3; }
.lead-phone { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  color: var(--muted); font-variant-numeric: tabular-nums; }
.lead-foot { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); padding-top: var(--sp-2); margin-top: 2px;
  border-top: 1px solid var(--border); }

/* Переход в переписку: студия работает в WhatsApp, и номер копировался руками */
.lead-wa { position: absolute; top: 8px; right: 8px; display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: var(--r-sm); color: var(--muted);
  background: var(--surface-sunken); transition: color 120ms ease, background 120ms ease; }
.lead-wa:hover { color: var(--success); background: var(--success-tint); }
.lead-open { padding-right: 30px; }

/* Пустая колонка — видимая зона броска, а не серая надпись */
.col-drop { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); text-align: center; padding: var(--sp-5) var(--sp-3); margin-top: var(--sp-2);
  color: var(--muted); font-size: 12px; line-height: 1.4;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm); }
.col-drop .icon { color: var(--border-strong); }
/* Есть хоть одна карточка — приглашения нет. Разметка его не убирает: карточки
   приезжают и уезжают без перезагрузки, и решать это должен экран, а не сервер. */
.col-body:has(.lead) .col-drop { display: none; }

/* Цель броска подсвечивается рамкой, а не заливкой: заливка перекрашивала карточки */
.col.drop-target { background: var(--surface); border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }
.col.drop-target .col-head { background: var(--primary-tint); }
.col.drop-target .col-drop { border-color: var(--primary); color: var(--primary-hover); }

/* Имя, которого нет, и хозяин, которого нет ---------------------------------
   Телефон подставлялся вместо имени — и строка контакта пряталась как дубль:
   на карточке не оставалось ни имени, ни телефона. Теперь «Без имени» сказано
   прямо и приглушённо, а контакт стоит своей строкой.

   Красный «?» вместо ответственного горел на 94% карточек — сигнал, который горит
   всегда, равен его отсутствию. Отсутствие хозяина показываем спокойно; кто именно
   тревожный, отвечает фильтр «Ничьи» наверху. */
.lead-name.is-noname { color: var(--muted); font-weight: 500; }
.lead-owner.is-none { background: var(--surface-sunken); color: var(--muted);
  border: 1px dashed var(--border-strong); }

/* Призрак карточки объявляется последним ------------------------------------
   `.lead` из блока доски получил position: relative, и одинаковая специфичность
   отдала победу более позднему правилу — призрак переставал быть fixed и падал
   в конец страницы. Правило дублей: побеждает тот, кто ниже. */
.lead-ghost { position: fixed; top: 0; left: 0; opacity: 1;
  box-shadow: 0 16px 32px oklch(0.2 0.02 235 / 0.24); }

/* Шаг сделки открывается как задача */
.quick-step-link { padding: var(--sp-2) 0; font-size: 12.5px; }

/* Окно самой задачи: поля правятся сразу, внизу одна главная кнопка «Сохранить»,
   а завершение — отдельной полосой под ней. Две зелёные кнопки в одном окне
   заставляют выбирать, какая из них «та самая» (замечание Паши 17.08.2026). */
.task-modal { display: flex; flex-direction: column; max-height: calc(100dvh - 64px); }
.task-modal-form { display: flex; flex-direction: column; min-height: 0; }
.task-card-state { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  font-size: 12.5px; color: var(--muted); }
.task-card-links { display: flex; gap: var(--sp-1); flex-wrap: wrap;
  margin-bottom: var(--sp-4); }
.task-card-later { display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  margin-top: 6px; font-size: 12px; color: var(--muted); }
.task-card-later .btn { padding: 3px 9px; font-size: 12px; }
.task-card-result { margin-top: var(--sp-4); font-size: 13px;
  padding: var(--sp-2) var(--sp-3); background: var(--surface-sunken);
  border-radius: var(--r-sm); }
.modal-foot-spacer { flex: 1; }
/* та же карточка отдельной страницей — по ссылке из сделки */
.screen-pad > .task-modal { max-height: none; background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
/* полоса завершения — как строка «записать» в окне сделки: своё поле,
   своя тихая кнопка, и она не спорит с «Сохранить» */
.task-card-close { display: flex; gap: var(--sp-2); align-items: center;
  padding: var(--sp-3) var(--sp-5) var(--sp-4);
  border-top: 1px solid var(--border); background: var(--surface); }
.task-card-close input { flex: 1; }

/* Очередь — строками-карточками, как в прототипе: слева срок, посередине дело,
   справа хозяин. Ритм задаёт колонка срока: с неё и начинают смотреть очередь. */
.task-group { margin-bottom: var(--sp-5); }
.task-group-head { display: flex; align-items: baseline; gap: var(--sp-2);
  margin-bottom: var(--sp-2); font-size: 13px; }
.task-group-head b.group-overdue { color: var(--danger); }
.task-group-head b.group-today { color: var(--primary-hover); }
.task-list { display: flex; flex-direction: column; gap: 6px; }
.task-row { display: grid; grid-template-columns: 150px 1fr auto; align-items: center;
  gap: var(--sp-3); background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--sp-3) var(--sp-4);
  color: inherit; text-decoration: none; transition: border-color 120ms ease-out; }
.task-row:hover { border-color: var(--border-strong); }
.task-row.is-done .task-text { color: var(--muted); }
.task-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.task-text { font-size: 13.5px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-meta { font-size: 12px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-who { display: flex; align-items: center; gap: var(--sp-2); }
.task-who span:last-child { font-size: 12px; color: var(--muted); white-space: nowrap; }
@media (max-width: 900px) {
  .task-row { grid-template-columns: 120px 1fr; }
  .task-who { grid-column: 2; justify-content: flex-start; }
}

.filter-sep { width: 1px; height: 18px; background: var(--border); margin: 0 var(--sp-1); }

/* Подвал карточки: живой, как в прототипе -----------------------------------
   Карточка была монохромной: серые инициалы в квадрате и сухое «до 15.08».
   В прототипе те же данные читаются с одного взгляда — круглый аватар в фирменной
   бирюзе, фамилия рядом, срок словами («сегодня», «завтра», «просрочено 3 дн»)
   с иконкой часов, и значок шага, который загорается только когда шаг есть.

   Цвет здесь работает как признак, а не как украшение: фирменный тон — на людях
   и на назначенном шаге, тревожный — только на просрочке. */
.lead-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.tag { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted);
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tag.source { background: var(--primary-tint); color: var(--primary-hover); }
.tag.step { background: var(--surface-sunken); color: var(--ink); font-weight: 400; }

.lead-owner { display: flex; align-items: center; gap: 6px; font-size: 12px;
  color: var(--muted); min-width: 0; }
.lead-owner .avatar { width: 22px; height: 22px; border-radius: 999px; display: grid;
  place-items: center; font-size: 10px; font-weight: 600; flex: none;
  background: var(--primary-tint-strong); color: var(--primary-hover); }
.lead-owner .name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lead-owner.is-none { color: var(--muted); }
.lead-owner.is-none .avatar { background: var(--surface-sunken); color: var(--muted);
  border: 1px dashed var(--border-strong); }

.lead-meta { display: flex; align-items: center; gap: var(--sp-2); flex: none; }
.due { display: inline-flex; align-items: center; gap: 4px; font-size: 12px;
  font-weight: 500; color: var(--muted); font-variant-numeric: tabular-nums; }
.due.overdue { color: var(--danger); font-weight: 600; }
.due.soon { color: oklch(0.52 0.12 75); }
.due.none { font-style: italic; }
.task-dot { display: inline-grid; place-items: center; width: 22px; height: 22px;
  border-radius: var(--r-sm); background: var(--surface-sunken); color: var(--border-strong); }
.task-dot.has { background: var(--primary-tint); color: var(--primary); }

/* Место под карточку и приземление ------------------------------------------
   Перенос теперь показывает, куда карточка ляжет: соседи расступаются заранее,
   на их месте стоит пунктирный прямоугольник ровно её высоты. Отпустил — карточка
   встаёт туда же и коротко подсвечивается, а страница не перезагружается.
   Раньше до самого отпускания не двигалось ничего, а потом доска мигала целиком
   и уезжала в начало. */
.lead-hole { border: 1px dashed var(--primary); background: var(--primary-tint);
  border-radius: var(--r-sm); flex: none; box-sizing: border-box; }
.lead.is-settled { animation: lead-settle 900ms ease-out; }
@keyframes lead-settle {
  from { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
  to { border-color: var(--border); box-shadow: var(--shadow-sm); }
}

/* Сообщение о неудаче — красным: перенос отменён, и это надо заметить */
.toast.bad { background: var(--danger); color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .lead.is-settled { animation: none; }
}

/* ============================================================
   Окно приёма (расписание → карточка в сетке)
   ------------------------------------------------------------
   Клик по записи открывает окно, а не уводит страницей: неделя остаётся на виду,
   и после отметки человек стоит там же, где стоял. Устройство то же, что у окна
   «Записать на приём», — шапка, тело, футер с действиями: два окна одного экрана
   не должны выглядеть как из разных систем.
   ============================================================ */
.modal-peek { width: min(520px, calc(100vw - 32px)); }
.modal-peek .modal-head { align-items: flex-start; }
.modal-peek .modal-head:focus { outline: none; }

/* Шапка окна: имя строкой, под ним когда и телефон. Длинная фамилия обрезается,
   а не ломает строку — иначе состояние («Записан») уезжает на третий этаж. */
.peek-heading { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.peek-title { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.peek-title h2 { flex: 0 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.peek-title .role-tag, .peek-title .tag { flex-shrink: 0; }
.modal-peek .quick-sub { font-size: 12.5px; color: var(--muted); }

/* ссылка-кнопка не подчёркивается: «Перенести» рядом с «Пришёл» должна выглядеть
   такой же кнопкой, а не ссылкой в тексте */
a.btn { text-decoration: none; }

/* кольцо фокуса в окне — брендовое, а не синее браузерное */
.modal .btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* строка «приём прошёл, отметки нет» — единственный красный сигнал окна:
   он означает дыру в учёте, а не просто прошедшее время */
.peek-alert { display: flex; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-3); margin-bottom: var(--sp-4); border-radius: var(--r-sm);
  background: var(--danger-tint); color: oklch(0.42 0.15 25); font-size: 12.5px;
  line-height: 1.45; }
.peek-alert .icon { flex-shrink: 0; margin-top: 1px; }

.peek-facts { display: flex; flex-direction: column; gap: 0; margin: 0; }
.peek-facts > div { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-4); padding: 7px 0; border-bottom: 1px solid var(--border); }
.peek-facts > div:last-child { border-bottom: 0; }
.peek-facts dt { font-size: 12.5px; color: var(--muted); }
.peek-facts dd { margin: 0; font-size: 13px; font-weight: 500; text-align: right; }
.peek-unpaid { color: oklch(0.42 0.12 75); }

.peek-note { margin-top: var(--sp-3); padding: var(--sp-3); border-radius: var(--r-sm);
  background: var(--surface-sunken); font-size: 12.5px; line-height: 1.5; }

/* Отметка посещения — главное действие окна, поэтому слева и крупно.
   Перенос и отмена уходят вправо: они нужны реже и не должны попадаться под руку. */
.peek-foot { flex-wrap: wrap; align-items: center; }
.peek-foot form { display: inline; }
.peek-foot-rest { display: flex; gap: var(--sp-2); align-items: center; margin-left: auto; }
.peek-hint { font-size: 12px; color: var(--muted); }

.peek-links { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5); border-top: 1px solid var(--border); font-size: 12.5px; }
.peek-links a { color: var(--primary); text-decoration: none; }
.peek-links a:hover { text-decoration: underline; }
.peek-links .peek-hint { margin-left: auto; }

/* Просрочка помечает срок, а не заливает карточку ----------------------------
   17.08.2026 на доске оказалось 542 просроченных сделки из 652 — розовыми стали
   восемь карточек из десяти, и доска превратилась в сплошное красное поле, где
   ничего не выделено, потому что выделено всё. Тревога остаётся там, где её можно
   прочитать: в самой строке срока и в фильтре «Просрочено» наверху. */
.lead.is-overdue { background: var(--bg); border-color: var(--border); }
.lead.is-overdue:hover { border-color: var(--border-strong); }

/* Карточка сделки — перенесена из прототипа как есть -------------------------
   Паша 17.08.2026: «в прототипе всё по местам, у нас криво». Разбор показал три
   причины, и ни одна не про шрифт (он один и тот же): карточка была обёрнута
   в ссылку со своим набором отступов, справа выедался тридцатипиксельный отступ
   под угловую кнопку переписки, а телефон стоял сплошной строкой цифр.

   Здесь блоки и размеры взяты из прототипа один в один: 12 пикселей внутри,
   8 между блоками, имя 14/600, телефон 12 приглушённым, плашки 11, подвал
   отделён линией. Переписка вернулась плашкой в общий ряд — там, где она
   и была нарисована. */
.lead { padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2);
  box-shadow: var(--shadow-sm); position: relative; }
.lead-open { display: block; padding: 0; }
.lead-top { display: flex; flex-direction: column; gap: 2px; }
.lead-name { font-size: 14px; font-weight: 600; letter-spacing: -0.005em; line-height: 1.3;
  color: var(--ink); }
.lead-name.is-noname { color: var(--muted); font-weight: 500; }
.lead-phone { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums;
  display: flex; align-items: center; gap: 5px; margin-top: 2px; }

.lead-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.lead-tags:empty { display: none; }
.tag { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted);
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Плашка переписки — в фирменной бирюзе, как в прототипе. Зелёный «как у WhatsApp»
   на нашем экране чужой: он тянет цвет чужого продукта в интерфейс студии. */
.tag.wa { background: var(--primary-tint); color: var(--primary-hover); font-weight: 600;
  text-decoration: none; }
.tag.wa:hover { background: var(--primary-tint-strong); }
.tag.source { background: var(--primary-tint); color: var(--primary-hover); }
.tag.step { background: var(--surface-sunken); color: var(--ink); font-weight: 400; }

.lead-foot { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); padding-top: var(--sp-2); margin-top: 0;
  border-top: 1px solid var(--border); }
.lead-owner .avatar { width: 22px; height: 22px; font-size: 10px; }

/* Окно сделки — по утверждённому прототипу (app/screens/lead-card.js) ---------
   Прежнее окно было формой в рамке: подписи и поля одного веса, всё в один
   столбец, действия вперемешку. Прототип решает то же самое иначе — крупная
   шапка «кто это», сетка коротких полей, секции с тихими заголовками, и подвал,
   где слева справочные кнопки, справа решающие. Читается за один взгляд.

   Отличие от прототипа намеренное: поля здесь не только показываются, но и
   правятся — ради этого окно и открывают. Поэтому в сетке живут настоящие
   элементы ввода, приведённые к тому же росту, что и текстовые значения. */
.lc-head { display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border); }
.lc-who { min-width: 0; flex: 1; }
.lc-head h2 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.lc-sub { font-size: 13px; color: var(--muted); margin-top: 2px; }
.avatar.lg { width: 44px; height: 44px; font-size: 15px; border-radius: 999px;
  display: grid; place-items: center; flex: none;
  background: var(--primary-tint-strong); color: var(--primary-hover); font-weight: 600; }

.lc-body { padding: var(--sp-4) var(--sp-5); overflow-y: auto; max-height: min(62dvh, 560px); }
.lc-section { font-size: 12px; font-weight: 600; color: var(--muted); letter-spacing: 0.03em;
  text-transform: uppercase; margin: var(--sp-4) 0 var(--sp-2);
  display: flex; align-items: baseline; gap: var(--sp-2); }
.lc-body > .lc-section:first-child { margin-top: 0; }
.lc-hint { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 11.5px;
  color: var(--muted); }

.lc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-5); }
.lc-field { display: flex; flex-direction: column; gap: 3px; padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--border); min-width: 0; }
.lc-field > span { font-size: 11.5px; color: var(--muted); }
.lc-field > b { font-size: 13.5px; font-weight: 500; display: flex; align-items: center;
  gap: 6px; min-height: 26px; }
.lc-field > input, .lc-field > select {
  width: 100%; box-sizing: border-box; border: 1px solid transparent; background: none;
  padding: 2px 0; font: inherit; font-size: 13.5px; font-weight: 500; color: var(--ink);
  border-radius: var(--r-sm); min-height: 26px; }
.lc-field > input:hover, .lc-field > select:hover { background: var(--surface-sunken); }
.lc-field > input:focus, .lc-field > select:focus { outline: none; background: var(--bg);
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint);
  padding-left: 6px; padding-right: 6px; }
.lc-field.hidden { display: none; }

.mini-tag { font-size: 10.5px; font-weight: 600; padding: 1px 7px; border-radius: 999px;
  background: var(--surface-sunken); color: var(--muted); }
.mini-tag.ad { background: var(--primary-tint); color: var(--primary-hover); }
.mini-tag.warn { background: var(--warning-tint); color: oklch(0.48 0.11 75); }

.lc-feed { display: flex; flex-direction: column; gap: 6px; }
.feed-item { display: flex; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border);
  border-radius: var(--r-sm); font-size: 13px; color: var(--ink); text-decoration: none; }
a.feed-item:hover { border-color: var(--primary); background: var(--primary-tint); }
.feed-item .icon { color: var(--muted); flex-shrink: 0; margin-top: 1px; }
.feed-item b { font-weight: 500; display: block; }
.feed-item span { font-size: 11.5px; color: var(--muted); }
.feed-item.warn { background: var(--warning-tint); border-color: oklch(0.85 0.06 75); }
.feed-item.warn .icon { color: oklch(0.55 0.12 75); }

.lc-foot { display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5) var(--sp-4); border-top: 1px solid var(--border); }
.foot-spacer { flex: 1; }
.btn-sm { padding: 5px 10px; font-size: 12.5px; }
.danger-btn { color: var(--danger); }
.danger-btn:hover { background: var(--danger-tint); border-color: var(--danger); }

/* Причины отказа — крупными строками: одно нажатие, без прицеливания в кружок */
.decline-list { display: flex; flex-direction: column; gap: 6px; }
.decline-opt { text-align: left; padding: var(--sp-3); border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--bg); font-size: 13.5px; font-weight: 500;
  color: var(--ink); transition: border-color 120ms ease-out, background 120ms ease-out,
  color 120ms ease-out; }
.decline-opt:hover { border-color: var(--danger); background: var(--danger-tint);
  color: var(--danger); }
.decline-opt:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.decline-other { margin-top: var(--sp-3); display: flex; flex-direction: column;
  gap: var(--sp-2); align-items: flex-start; }
.decline-other.hidden { display: none; }

/* Лента заметок в окне и строка добавления */
.modal .notes { display: flex; flex-direction: column; gap: 6px; }

@media (max-width: 720px) {
  .lc-grid { grid-template-columns: 1fr; }
  .lc-body { max-height: 70dvh; }
}
@media (prefers-reduced-motion: reduce) { .decline-opt { transition: none; } }

/* Запись в историю — там, где историю читают */
.lc-body .note-add { display: flex; gap: var(--sp-2); align-items: flex-start;
  margin-bottom: var(--sp-3); }
.lc-body .note-add textarea { flex: 1; resize: vertical; min-height: 38px;
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px 10px;
  font: inherit; font-size: 13px; background: var(--bg); color: var(--ink); }
.lc-body .note-add textarea:focus { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }

/* Переписка — в угол, шаг — строкой ------------------------------------------
   Разбор с Пашей 17.08.2026. Плашка «WhatsApp» стояла на каждой карточке и весила
   столько же, сколько текст задачи, хотя это не сведения о сделке, а кнопка. Ушла
   значком в угол — рядом с именем, но вне ряда.

   Шаг остался: «сегодня» отвечает когда, но не что, и решение «за что взяться
   первым» принимается по тексту. Но он больше не плашка — обычная строка, тише
   имени и телефона, в одну строку с обрезкой по ширине карточки. */
.lead-wa { position: absolute; top: 10px; right: 10px; display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: var(--r-sm); color: var(--muted);
  background: var(--surface-sunken);
  transition: color 120ms ease, background 120ms ease; }
.lead-wa:hover { color: var(--primary-hover); background: var(--primary-tint); }
.lead-top { padding-right: 30px; }          /* только шапка карточки, не подвал */

.lead-step { font-size: 12.5px; color: var(--ink); line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  /* прежний блок красил шаг как плашку — гасим явно: правило-дубль иначе
     оставляет старую заливку, и строка выглядит тегом */
  background: none; border: none; padding: 0; margin: 0; }
.lead-step::before { content: "→ "; color: var(--muted); }

/* Перенос карточки: вид жеста ------------------------------------------------
   Карточка при переносе пропадала с экрана: правила `.lead` из более поздних
   блоков (padding, display, position: relative) перебивали `.lead-ghost` — вес
   селекторов одинаковый, побеждает тот, кто ниже. Лечится не гонкой «допиши ещё
   ниже», а весом: `.lead.lead-ghost` сильнее любого `.lead`, и порядок блоков
   больше ничего не решает.

   Заодно жест стал плавным: место под карточку раскрывается, а не появляется
   рывком, соседи разъезжаются за 160 мс, и карточка садится на место без скачка. */
.lead.lead-ghost {
  position: fixed; top: 0; left: 0; z-index: var(--z-modal-backdrop);
  margin: 0; pointer-events: none; opacity: 1;
  background: var(--bg); border: 1px solid var(--primary);
  box-shadow: 0 18px 36px oklch(0.2 0.02 235 / 0.26);
  cursor: grabbing; will-change: translate;
}
/* Оригинал убирается из потока целиком. Прозрачным он продолжал занимать высоту,
   и колонка ехала вниз дважды: под невидимую карточку и под место для неё. */
.lead.is-dragging { display: none; }

.lead-hole {
  border: 1px dashed var(--primary); background: var(--primary-tint);
  border-radius: var(--r-sm); flex: none; box-sizing: border-box;
  overflow: hidden;
  transition: height 160ms cubic-bezier(0.22, 1, 0.36, 1),
              margin 160ms cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
  .lead-hole { transition: none; }
}

/* Подвал карточки — рабочий, а не подпись ------------------------------------
   Ответственный и срок открывают окно сделки сразу на своём поле: переназначить
   и передвинуть срок — самые частые правки за день. Значок шага ведёт в задачу,
   если она есть, и предлагает её поставить, если нет.
   Подсветка сдержанная: это по-прежнему сведения, а не кнопки. */
a.lead-owner, a.due, a.task-dot { text-decoration: none; border-radius: var(--r-sm);
  transition: background 120ms ease, color 120ms ease; }
a.lead-owner { padding: 2px 6px 2px 2px; margin-left: -2px; }
a.lead-owner:hover { background: var(--primary-tint); color: var(--primary-hover); }
a.due { padding: 2px 6px; margin-right: -2px; }
a.due:hover { background: var(--surface-sunken); }
a.due.overdue:hover { background: var(--danger-tint); }
a.task-dot:hover { background: var(--primary-tint); color: var(--primary); }
a.lead-owner:focus-visible, a.due:focus-visible, a.task-dot:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px; }

/* Меню у карточки: короткий список вместо окна ------------------------------
   Назначить ответственного и передвинуть срок — движения на секунду, и окно
   поверх всего экрана ради них слишком тяжёлое. Панель встаёт у самой карточки
   и не затемняет доску: человек не теряет из виду, где он находится.
   Вид у обоих меню один — иначе на карточке заводится третий язык всплывашек. */
.menu-pop { position: fixed; z-index: var(--z-modal); min-width: 208px; max-width: 260px;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-lg); padding: 6px; overflow: hidden;
  animation: menu-in 120ms cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes menu-in { from { opacity: 0; translate: 0 -4px; } to { opacity: 1; translate: 0 0; } }
.menu-loading { padding: 10px 12px; color: var(--muted); font-size: 12.5px; }
.menu-title { font-size: 11px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--muted); padding: 6px 10px 4px; }
.menu-form { display: flex; flex-direction: column; gap: 1px; }
.menu-item { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 7px 10px; border: none; background: none; border-radius: var(--r-sm);
  font: inherit; font-size: 13px; color: var(--ink); }
.menu-item:hover { background: var(--surface-sunken); }
.menu-item.is-current { background: var(--primary-tint); color: var(--primary-hover);
  font-weight: 600; }
.menu-item .avatar { width: 22px; height: 22px; border-radius: 999px; display: grid;
  place-items: center; font-size: 10px; font-weight: 600; flex: none;
  background: var(--primary-tint-strong); color: var(--primary-hover); }
.menu-item.menu-quiet { color: var(--muted); font-size: 12.5px; }
.menu-item.menu-quiet:hover { color: var(--danger); background: var(--danger-tint); }
.menu-item.menu-apply { justify-content: center; background: var(--primary); color: #fff;
  font-weight: 600; margin-top: 2px; }
.menu-item.menu-apply:hover { background: var(--primary-hover); }
.menu-date { display: flex; flex-direction: column; gap: 3px; padding: 6px 10px 2px; }
.menu-date span { font-size: 11.5px; color: var(--muted); }
.menu-date input { border: 1px solid var(--border); border-radius: var(--r-sm); padding: 5px 8px;
  font: inherit; font-size: 13px; background: var(--bg); color: var(--ink); }
.menu-date input:focus { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }

/* курсор подсказывает, что карточка открывается целиком */
.lead { cursor: pointer; }
.lead:active { cursor: grabbing; }

@media (prefers-reduced-motion: reduce) { .menu-pop { animation: none; } }

/* Завершение задачи — полосой под кнопками, а не второй формой.
   Полоса отделена цветом: она появляется по отметке «выполнена» и должна быть
   видна сразу, иначе нажатие выглядит как «ничего не произошло». */
.task-done { display: block; padding: var(--sp-4) var(--sp-5);
  border-top: 1px solid var(--border); background: var(--primary-tint); }
.task-done.hidden { display: none; }
.task-done .field { margin-bottom: var(--sp-3); }
.task-done input { width: 100%; border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 7px 10px; font: inherit; font-size: 13px; background: var(--bg); color: var(--ink); }
.task-done input:focus { outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint); }
.task-done-actions { display: flex; gap: var(--sp-2); justify-content: flex-end; }

/* Нажатая тихая кнопка: отметка остаётся видно выбранной, пока пишут результат */
.btn.is-on { background: var(--primary-tint); border-color: var(--primary);
  color: var(--primary-hover); font-weight: 600; }

/* Строка контакта стоит всегда — даже когда контакта нет.
   Иначе у соседних карточек на одном месте разные вещи: у одной телефон,
   у другой следующий шаг, и колонку невозможно просматривать взглядом. */
.lead-phone.is-none { color: var(--border-strong); font-style: italic; }

/* Строка шага стоит всегда: без неё пустота читается как «так и надо»,
   хотя это «шаг не назначен» — то самое, из-за чего сделки теряются.
   Тон приглушённый: таких карточек сотни, кричать нельзя. */
.lead-step.is-none { color: var(--border-strong); font-style: italic;
  text-decoration: none; display: block; }
.lead-step.is-none::before { content: "→ "; }
.lead-step.is-none:hover { color: var(--primary-hover); }

/* Текст шага — ссылка в задачу, но выглядит по-прежнему строкой, а не кнопкой:
   на карточке и так три действия, четвёртая подсветка сделала бы её пёстрой. */
a.lead-step { text-decoration: none; display: block; color: var(--ink); }
a.lead-step:hover { color: var(--primary-hover); }

/* Ссылка шага занимает ровно свой текст, а не всю строку ---------------------
   Растянутая на всю ширину, она перехватывала клики по пустому месту справа —
   человек метил в карточку, а открывалась задача (Паша, 23.08.2026).
   Пустое место карточки принадлежит карточке. */
a.lead-step, a.lead-step.is-none { display: inline-block; max-width: 100%;
  /* карточка — колонка-флекс, а она растягивает детей на всю ширину независимо
     от display: без align-self ссылка снова перехватит клики по пустому месту */
  align-self: start; }

/* Значок переписки без номера — приглушённый и неактивный, как строка телефона.
   Исчезая совсем, он оставлял дыру в углу карточки. */
.lead-wa.is-none { color: var(--border-strong); background: none; cursor: default;
  pointer-events: none; }

/* Второй слой окна: задача поверх сделки -------------------------------------
   Сделку под задачей видно — человек помнит, где он. Верхнее окно уже нижнего
   и с более плотной тенью: понятно, что оно сверху и закроется первым. */
.modal-upper { max-width: 520px; width: calc(100% - 64px);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: 0 24px 48px oklch(0.2 0.02 235 / 0.28); padding: 0; background: var(--bg);
  animation: upper-in 140ms cubic-bezier(0.22, 1, 0.36, 1); }
.modal-upper::backdrop { background: oklch(0.24 0.015 235 / 0.28); }
@keyframes upper-in { from { opacity: 0; translate: 0 8px; } to { opacity: 1; translate: 0 0; } }
@media (prefers-reduced-motion: reduce) { .modal-upper { animation: none; } }

/* Поля окна не дёргаются при нажатии ----------------------------------------
   Отступы у поля менялись по фокусу (2px → 6px по бокам), и текст подпрыгивал
   в момент клика — особенно заметно на «Этапе», где список ещё и раскрывается
   (Паша, 24.08.2026). Отступ теперь постоянный: по фокусу меняются только фон,
   рамка и подсветка — то, что не двигает содержимое. */
.lc-field > input, .lc-field > select { padding: 2px 6px; margin-left: -6px;
  width: calc(100% + 12px); }
.lc-field > input:focus, .lc-field > select:focus { padding-left: 6px; padding-right: 6px; }

/* Окно стоит на месте, а не пляшет от своей высоты --------------------------
   Браузер центрирует <dialog> по содержимому: стоило выбрать другой этап и
   содержимому подрасти на несколько пикселей, как всё окно дёргалось вверх
   (Паша, 24.08.2026). Прибиваем к постоянной высоте — окно растёт вниз,
   а точка, куда человек смотрит и целится, не двигается. */
.modal { position: fixed; top: 7dvh; margin: 0 auto; inset-block-end: auto;
  max-height: min(86dvh, calc(100dvh - 96px)); overflow: auto; }
.modal-upper { top: 10dvh; }
/* Форма внутри окна — не выше самого окна. Раньше она была на 32px выше, низ с
   кнопками вылезал за край окна, и до «Отмены» надо было докручивать само окно —
   на телефоне это не удавалось (Паша, 30.09.2026, окно «Выставить счёт»). Теперь
   кнопки стоят на месте, прокручивается только середина. */
.modal .modal-form { max-height: min(86dvh, calc(100dvh - 96px)); }

/* Подзаголовок окна — в одну строку. Длинное название этапа переносило его
   на вторую, шапка подрастала на шесть пикселей, и содержимое под ней уезжало
   вниз прямо во время выбора. */
.lc-sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Пояснение в меню: почему система вообще спрашивает */
.menu-note { padding: 0 10px 6px; font-size: 11.5px; color: var(--muted); line-height: 1.35; }

/* Окно одного вопроса ---------------------------------------------------------
   Назначить ответственного, выбрать причину — действия, где вопрос ровно один.
   Окно под них уже обычного: широкое полотно вокруг одной строки выглядит так,
   будто система чего-то недоговаривает. */
.modal.is-narrow { width: min(420px, calc(100vw - 32px)); }
.ask-body { display: flex; flex-direction: column; gap: var(--sp-4); }
.ask-who { display: flex; align-items: center; gap: var(--sp-3); }
.ask-who b { display: block; font-size: 14px; font-weight: 600; }
.ask-who span:last-child { font-size: 12.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.ask-note { font-size: 12.5px; line-height: 1.45; color: var(--primary-hover);
  background: var(--primary-tint); border-radius: var(--r-sm); padding: 9px 12px; }

/* Подвал карточки: одна левая линия и живая фамилия ---------------------------
   Кружок ответственного вылезал на восемь пикселей левее колонки текста — имя,
   телефон и шаг начинались в одном месте, а он в другом, и карточка выглядела
   косой (Паша, 24.08.2026). Отрицательный отступ ссылки убран: подсветка при
   наведении рисуется внутрь, а не наружу.

   Вторая беда там же: фамилия сжималась в ноль, потому что ссылка в флексе
   отдавала всё место сроку. Теперь имя занимает свободное место и обрезается
   многоточием только когда его действительно не хватает. */
.lead-foot { align-items: center; }
a.lead-owner, .lead-owner { padding: 2px 4px 2px 0; margin-left: 0;
  min-width: 0; flex: 1 1 auto; }
a.lead-owner:hover { background: none; color: var(--primary-hover); }
a.lead-owner:hover .avatar { background: var(--primary); color: #fff; }
.lead-owner .name { min-width: 0; flex: 1 1 auto; }
.lead-meta { flex: 0 0 auto; }

/* Пунктирный кружок «ничья» — того же размера, что и обычный аватар:
   рамка съедала пиксель, и он вставал на волос левее остальных. */
.lead-owner.is-none .avatar { box-sizing: border-box; }

/* Ответственный прижат влево: ссылка растянута ради удобного нажатия, но
   содержимое в ней центрировалось — и у ничьей сделки пустой кружок вставал
   посреди строки, ломая левую линию карточки. */
a.lead-owner, .lead-owner { justify-content: flex-start; }

/* Пунктирный кружок рисуется тенью, а не рамкой: рамка добавляла полпикселя
   и сдвигала «ничью» карточку с общей левой линии. */
.lead-owner.is-none .avatar { border: none;
  box-shadow: inset 0 0 0 1px var(--border-strong); }

/* Старая рамка вокруг всей ссылки «ничья» — наследие первой версии подвала:
   пунктир нужен кружку, а не строке, и именно он сдвигал карточку с линии. */
a.lead-owner.is-none, .lead-owner.is-none { border: none; background: none; }

/* Наследие первой версии подвала: ссылка ответственного была сама кружком —
   с фоном и круглыми краями. Отсюда серая плашка вокруг фамилии. Кружок теперь
   отдельный элемент внутри, а сама строка — просто строка. */
a.lead-owner, .lead-owner { width: auto; height: auto; border-radius: var(--r-sm);
  background: none; }
a.lead-owner:hover { background: var(--surface-sunken); }

/* Когда горит просрочка, ей нужно место -------------------------------------
   «просрочено 10 дн» и фамилия в одну строку карточки не помещаются, и фамилия
   превращалась в огрызок «К…» — мусор вместо сведений. В такой карточке важнее
   просрочка: остаётся кружок с инициалами, а полное имя — в подсказке. */
.lead:has(.due.overdue) .lead-owner .name { display: none; }

/* Графики работы: неделя терапевтов и неделя залов ---------------------------
   Строка — человек или зал, клетка — конкретный день. Как в FitBase, но без их
   заливки во всю клетку: там зелёным закрашена вся рабочая неделя, и на цветном
   поле перестаёт быть виден единственный важный день — выходной посреди недели. */
.hours-tbl th:not(:first-child):not(:last-child) { text-align: center; width: 96px; }
/* имя, «Постоянный график» и подпись под ним не должны рубиться на слоги */
.hours-tbl th:first-child, .hours-tbl td:first-child { min-width: 200px; }
.hours-tbl th .hours-wd { display: block; font-weight: 600; }
.hours-tbl th .hours-date { display: block; font-size: 11px; color: var(--muted); font-weight: 400; }
.hours-tbl th.is-today .hours-wd, .hours-tbl th.is-today .hours-date { color: var(--primary); }
.hours-tbl .cell-plan { display: block; font-size: 12px; }
.hours-tbl .hours-cell { text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
.hours-tbl .hours-cell.is-idle { color: var(--muted); }
.hours-tbl .hours-cell.is-break { color: var(--danger); }
/* час, поставленный на саму эту дату, отличается от постоянного графика: иначе
   не видно, что суббота открыта разово, а не всегда */
.hours-tbl .hours-val { display: block; }
.hours-tbl .hours-cell.is-own .hours-val { border-bottom: 1px dashed var(--border-strong); }
.hours-tbl .hours-cell.is-today { background: var(--surface-sunken); }
.hours-tbl .tbl-act { text-align: right; white-space: nowrap; }
/* сколько приёмов уже стоит в этот день: выходной поверх шести записей ставят
   по недосмотру, и цифра рядом с часами — единственное, что от этого удерживает */
.hours-count { display: inline-block; margin-left: 6px; padding: 0 5px; border-radius: 999px;
  background: var(--surface-sunken); color: var(--muted); font-size: 11px; }
/* клетка целиком — место нажатия: целиться в мелкую надпись неудобно */
.hours-tbl .hours-pick { display: block; padding: 6px 2px; margin: -6px -2px;
  border-radius: var(--r-sm); color: inherit; text-decoration: none; }
.hours-tbl .hours-pick:hover { background: var(--surface-sunken); color: var(--ink); }

/* Тип дня: рабочий, выходной, отпуск, больничный — как переключатель в FitBase */
.daykind { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--sp-4); }
.daykind-opt { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
  border: 1px solid var(--border); border-radius: 999px; cursor: pointer; font-size: 13px; }
.daykind-opt input { margin: 0; }
.daykind-opt:has(input:checked) { border-color: var(--primary); color: var(--primary); font-weight: 600; }

/* Интервалы дня: пара полей и «+», когда день разрывает обед */
.ivals { display: flex; flex-direction: column; gap: 8px; }
.ival { display: flex; align-items: flex-end; gap: 8px; }
.ival .field { margin: 0; }
.ival-drop { padding: 4px 10px; }
.ival-add { align-self: flex-start; }

/* Постоянный график: семь дней подряд, снятый день гаснет целиком */
.planday { padding: 10px 0; border-bottom: 1px solid var(--border); }
.planday:last-of-type { border-bottom: none; }
.planday-head { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 8px;
  cursor: pointer; font-weight: 500; }
.planday.is-off .ivals { opacity: .4; pointer-events: none; }

.empty-note { padding: 12px 16px; color: var(--muted); }

/* Настройки: дни недели галочками в ряд */
.daypick ul { display: flex; flex-wrap: wrap; gap: 12px; list-style: none; padding: 0; margin: 0; }
.daypick label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }

/* «Назад» обязана стоять первой, как и написано в правиле выше: у .topbar .btn
   тот же вес, и более позднее правило (order: 5) уносило её вправо на все экраны. */
.topbar .btn.btn-back { order: 0; }

/* Подтверждение записи вне графика: галочка нужна редко и не должна выглядеть
   рядовым полем формы — иначе её начнут ставить не глядя. */
.field-check.anyway { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 4px; }

/* справочник источников: строка правится на месте, вложенные партнёры со сдвигом */
.inline-rename { display: flex; align-items: center; gap: var(--sp-2); }
.rename-input { border: 1px solid transparent; background: none; padding: 4px 6px;
  border-radius: var(--r-sm); font: inherit; color: inherit; min-width: 200px; }
.rename-input:hover { border-color: var(--border); }
.rename-input:focus { border-color: var(--primary); outline: none; background: var(--bg); }
.inline-rename .btn { opacity: 0; }
.inline-rename:focus-within .btn { opacity: 1; }
.child-row { padding-left: var(--sp-5); }
.child-mark { color: var(--muted); }
.row-muted { opacity: 0.55; }
.row-actions { text-align: right; }

/* ============================================================
   Настройки: подразделы списком слева (05.09.2026)
   Раздел был одной плоской страницей: два блока полей и ссылка «Источники →»
   в конце. Пока настроек три штуки, это терпимо, но справочники студии
   (прайс, кассы, залы) идут сюда же, и ссылками в подвале они превратятся
   в свалку. Список слева показывает состав раздела целиком и говорит,
   где человек сейчас, — то же, что делает меню системы, только на уровень ниже.
   ============================================================ */
.settings-layout {
  display: grid; grid-template-columns: 216px minmax(0, 1fr);
  gap: var(--sp-5); align-items: start;
}
.settings-body { display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }

.settings-nav { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 0; }
.settings-nav-group {
  font-size: 11px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--muted); padding: var(--sp-4) var(--sp-3) var(--sp-2);
}
.settings-nav-group:first-child { padding-top: var(--sp-1); }
.settings-nav-item {
  display: block; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
  color: var(--ink); text-decoration: none; font-size: 13.5px; font-weight: 500;
  transition: background 150ms ease-out;
}
.settings-nav-item:hover { background: var(--primary-tint); }
.settings-nav-item.active { background: var(--primary-tint-strong); color: var(--primary-hover); }

/* Рабочие дни: семь галочек — это выбор, а не список. Без своего оформления
   браузер рисует их столбиком с маркерами, и неделя перестаёт читаться неделей. */
.daypick > * { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.daypick label {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); font-size: 13px; cursor: pointer;
  transition: border-color 150ms ease-out, background 150ms ease-out;
}
.daypick label:hover { border-color: var(--border-strong); }
.daypick label:has(input:checked) { border-color: var(--primary); background: var(--primary-tint); }
.daypick label:focus-within { outline: 2px solid var(--primary); outline-offset: 1px; }
.daypick input { width: 15px; height: 15px; margin: 0; accent-color: var(--primary); }

/* Узкий экран: список подразделов ложится строкой над содержимым */
@media (max-width: 860px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); }
  .settings-nav { position: static; flex-direction: row; flex-wrap: wrap; align-items: center; }
  .settings-nav-group { display: none; }
  .settings-nav-item { border: 1px solid var(--border); background: var(--bg); }
}

@media (prefers-reduced-motion: reduce) {
  .settings-nav-item, .daypick label { transition: none; }
}

/* ── Карточка пациента ───────────────────────────────────────────────────────
   Слева работа (лечение, приёмы, деньги), справа справочное (связь, семья,
   служебные поля). Раньше всё шло одинаковыми панелями во всю ширину, и у нового
   пациента самым заметным блоком оказывалась история изменений. */

.pcard-head { display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5); background: var(--bg);
  border: 1px solid var(--border); border-radius: var(--r-md); }
.pcard-who { flex: 1; min-width: 0; }
.pcard-who h1 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.015em; }
.pcard-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: 6px; font-size: 12.5px; color: var(--muted); }
.pcard-actions { display: flex; align-items: center; gap: var(--sp-2); flex: none; }

/* Тревога — строка, а не панель: она про действие, а не про раздел */
.notice { display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); font-size: 13px;
  line-height: 1.45; border: 1px solid var(--border); background: var(--bg); }
.notice b { font-weight: 600; }
.notice .icon { flex: none; }
.notice .btn { flex: none; margin-left: auto; }
.notice-warning { border-color: oklch(0.86 0.08 75); background: oklch(0.98 0.03 75); }
.notice-warning .icon { color: var(--warning); }

.pcard-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--sp-4); align-items: start; }
.pcard-main, .pcard-side { display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }

/* Пустой раздел говорит, что делать дальше, а не «данных нет» */
.blank-line { margin: 0; padding: var(--sp-2) 0; font-size: 13px; color: var(--muted); }
.blank-line a { color: var(--primary); }

.panel-note.danger-note { color: var(--danger); font-weight: 500; }

/* Правая колонка: пары «подпись — значение», без таблиц */
.side-row { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.side-row:last-of-type { border-bottom: 0; }
.side-label { color: var(--muted); flex: none; }
.side-value { text-align: right; font-variant-numeric: tabular-nums; }
.side-value em { display: block; font-style: normal; font-size: 12px; color: var(--muted); }
.side-comment { margin: var(--sp-3) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--border);
  font-size: 12.5px; line-height: 1.5; color: var(--muted); }

.side-person { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0;
  border-bottom: 1px solid var(--border); color: inherit; }
.side-person:last-of-type { border-bottom: 0; }
.side-person:hover b { color: var(--primary); }
.side-person-who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.side-person-who b { font-size: 13px; font-weight: 500; }
.side-person-who em { font-style: normal; font-size: 12px; color: var(--muted); }

/* История карточки — служебное: свёрнута, пока её не спросили */
.side-history { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
.side-history summary { cursor: pointer; font-size: 12.5px; color: var(--muted);
  list-style: none; display: flex; align-items: center; gap: 6px; }
.side-history summary::-webkit-details-marker { display: none; }
.side-history summary::before { content: "›"; display: inline-block; transition: transform 160ms ease-out; }
.side-history[open] summary::before { transform: rotate(90deg); }
.side-history summary span { color: var(--border-strong); }
.side-history summary:hover { color: var(--ink); }
.hist-row { display: flex; flex-direction: column; gap: 1px; padding: var(--sp-2) 0 var(--sp-2) 14px;
  border-bottom: 1px solid var(--border); font-size: 12px; }
.hist-row:last-child { border-bottom: 0; }
.hist-when { color: var(--muted); font-variant-numeric: tabular-nums; }
.hist-what { color: var(--ink); }
.hist-who { color: var(--muted); }

@media (max-width: 900px) {
  .pcard-grid { grid-template-columns: 1fr; }
  .pcard-head { flex-wrap: wrap; }
  .pcard-actions { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .side-history summary::before { transition: none; }
}
.notice-danger { border-color: oklch(0.85 0.09 25); background: oklch(0.975 0.02 25); }
.notice-danger .icon { color: var(--danger); }
.side-person, .side-person:hover { text-decoration: none; }
.side-person b { text-decoration: none; }

/* ============================================================
   Пояснение за знаком вопроса (05.09.2026)
   На экране не должно быть подписей-объяснялок: они висят перед глазами
   у того, кто и так всё знает, и засоряют рабочее окно. Но новому человеку
   слово вроде «рабочий день» расшифровать надо. Поэтому знак вопроса
   держит своё место в строке, но проявляется только при наведении
   на подпись — а на планшете, где наведения нет, виден всегда.
   ============================================================ */
.hint { display: inline-flex; align-items: center; margin-left: 5px; }
.hint-mark {
  width: 15px; height: 15px; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: 999px;
  background: var(--bg); color: var(--muted);
  font: 600 10px/1 var(--font); cursor: pointer;
  opacity: 0; transition: opacity 150ms ease-out, color 150ms ease-out,
                          border-color 150ms ease-out;
}
/* проявляется от наведения на саму подпись — родителя знака */
*:hover > .hint > .hint-mark,
*:focus-within > .hint > .hint-mark,
.hint:hover > .hint-mark,
.hint-mark:focus-visible,
.hint:has(.hint-bubble:popover-open) > .hint-mark { opacity: 1; }
.hint-mark:hover, .hint-mark:focus-visible,
.hint:has(.hint-bubble:popover-open) > .hint-mark {
  color: var(--primary); border-color: var(--primary);
}
.hint-mark:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.hint-bubble {
  position: fixed; margin: 0; inset: auto;
  max-width: 300px; padding: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); color: var(--ink); box-shadow: var(--shadow-lg);
  font: 400 12.5px/1.5 var(--font); text-align: left; text-transform: none;
  letter-spacing: normal;
}
/* появление — только движением: видимость пузыря не должна зависеть от того,
   проигралась анимация или нет, иначе текст открывается пустым окном */
.hint-bubble:popover-open { animation: hint-in 150ms cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes hint-in { from { transform: translateY(-4px); } }

/* без наведения (планшет, телефон) знак виден всегда: иначе до него не добраться */
@media (hover: none) {
  .hint-mark { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hint-mark { transition: none; }
  .hint-bubble:popover-open { animation: none; }
}

/* Глазок у пароля -----------------------------------------------------------
   Пароль в студии набирают с планшета и вслепую: ошибка в одном символе выглядит
   так же, как неверный пароль, и человек начинает думать, что доступ закрыли.
   Кнопка лежит поверх поля, а не оборачивает его: input должен остаться прямым
   потомком .field, иначе теряет общий стиль и становится ниже соседних. */
.field-pass { position: relative; }
.field-pass > input { padding-right: 40px; }
.pass-eye { position: absolute; right: 5px; bottom: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; border: none; border-radius: var(--r-sm);
  background: none; color: var(--muted); cursor: pointer; }
.pass-eye:hover { color: var(--ink); background: var(--surface-sunken); }
.pass-eye[aria-pressed="true"] { color: var(--primary); }

/* Личный счёт пациента (аванс) ----------------------------------------------
   Аванс — чужие деньги у студии на руках, и на карточке он должен читаться как
   справка, а не как ещё одна покупка. Поэтому строка тихая, в одну линию с
   действием, и появляется только когда на счету что-то есть: подпись «на счету
   0 ₸» стоит у каждого пациента и не сообщает ничего. */
.account-strip { display: flex; align-items: center; gap: var(--sp-2);
  margin-bottom: var(--sp-3); }
.account-gap { flex: 1; }
.account-sum { font-size: 12px; color: var(--muted); }
.account-sum b { margin-left: 4px; font-size: 13.5px; font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums; }

/* Операции по счёту убраны под раскрытие: их смотрят, когда цифра не сошлась,
   а не каждый раз, когда открывают карточку. */
.account-log { margin-bottom: var(--sp-4); }
.account-log > summary { cursor: pointer; font-size: 12.5px; color: var(--muted);
  list-style: none; display: flex; align-items: center; gap: 6px; }
.account-log > summary::-webkit-details-marker { display: none; }
.account-log > summary::before { content: "\203a"; display: inline-block;
  transition: transform 160ms ease-out; }
.account-log[open] > summary::before { transform: rotate(90deg); }
.account-log > summary span { color: var(--border-strong); }
.account-log > summary:hover { color: var(--ink); }
.account-log .tbl { margin-top: var(--sp-2); }
/* минус на счету — не тревога: зачёт и возврат это обычный ход дела, а красный
   в системе значит просрочку и отказ. Поэтому уходящее просто тише приходящего */
.account-log .tbl td.num.is-out { color: var(--muted); }

/* Подпись рядом с названием поля: «доступно 5 000 ₸» — это данные, а не пояснение,
   поэтому стоит на виду, а не за знаком вопроса. */
.field-aside { margin-left: 6px; font-size: 11.5px; font-weight: 400; font-style: normal;
  color: var(--muted); font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .account-log > summary::before { transition: none; }
}

/* ============================================================
   Полоса фильтров сделок (05.09.2026)
   Срезы слева — это состояние работы (просрочено, ничьи, без срока);
   выборы справа — это вопрос к данным (кто ведёт, откуда, за какой срок).
   Разделены чертой, чтобы глаз не читал их одним списком.
   ============================================================ */
.filterbar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: thin; }
.filterbar > * { flex-shrink: 0; }

.fb-div {
  width: 1px; height: 18px;
  background: var(--border);
  margin: 0 var(--sp-2);
}

.fb-sel {
  font-family: inherit; font-size: 12.5px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 4px 8px; max-width: 190px;
  background: var(--bg); color: var(--ink);
  outline: none;
  transition: border-color 150ms ease-out, background 150ms ease-out, color 150ms ease-out;
}
.fb-sel:hover { border-color: var(--border-strong); }

/* выбранный фильтр видно, не вчитываясь: тихая брендовая заливка вместо белого поля */
.fb-sel.is-set {
  border-color: var(--primary-tint-strong);
  background: var(--primary-tint);
  color: var(--primary-hover);
  font-weight: 500;
}
.fb-sel:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-tint);
}

.fb-reset {
  font-size: 12px; color: var(--muted);
  padding: 4px 8px; border-radius: var(--r-sm);
  transition: color 150ms ease-out, background 150ms ease-out;
}
.fb-reset:hover { color: var(--ink); background: var(--surface-sunken); }

/* На узком экране подсказка уходит первой: она объясняет срез, а фильтры им управляют */
@media (max-width: 1400px) {
  .filterbar .filter-note { display: none; }
}

/* Итоги месяца в полосе фильтров экрана «Деньги» -----------------------------
   Чисел здесь стало четыре (пришло · ушло · не доплатили · авансы на руках),
   и на ноутбуке строка упиралась в правый край: часть суммы уезжала за экран.
   Полоса теперь переносит итоги на вторую строку и подрастает сама, а не режет
   их молча — число, которого не видно, хуже, чем полоса на десять пикселей выше. */
.filterbar-money { height: auto; min-height: 44px; flex-wrap: wrap;
  padding-top: 5px; padding-bottom: 5px; row-gap: var(--sp-1); }
/* распорка тут мешает: с переносом она забирает всю свободную ширину первой
   строки и сама сталкивает итоги вниз. Итоги прижимает вправо отступ */
.filterbar-money .filter-spacer { display: none; }
.filterbar-money .filter-note { margin-left: auto; }

/* Срез, вкладка воронки и «Сбросить» — органы управления, а не ссылки в тексте:
   подчёркивание у них читалось как «здесь ссылка» и спорило с формой таблетки. */
.chip, .funnel-tab, .fb-reset { text-decoration: none; }

/* Чем оплачивается занятие (форма записи).
   Строка под выбором пациента: курс с остатком занятий или личный счёт. Красной она
   становится, только когда платить нечем, — иначе сигнал горел бы всегда. */
.cover-note {
  margin: calc(var(--sp-2) * -1) 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted); font-size: 13px;
}
.cover-note-bad { background: var(--warning-tint); color: oklch(0.42 0.12 75); }

/* ============================================================
   Прайс: услуги и цены (настройки → справочники)
   ------------------------------------------------------------
   Услуги разложены по видам, и каждый вид — своя таблица. Без общих ширин
   колонки в соседних панелях встают по-разному, и «Цена» гуляет по экрану
   от группы к группе: глазу приходится искать её заново в каждой таблице.
   ============================================================ */
.tbl-price { table-layout: fixed; }
.tbl-price th:nth-child(1), .tbl-price td:nth-child(1) { width: 30%; }
.tbl-price th:nth-child(2), .tbl-price td:nth-child(2) { width: 38%; }
.tbl-price th:nth-child(3), .tbl-price td:nth-child(3) { width: 13%; }
.tbl-price th:nth-child(4), .tbl-price td:nth-child(4) { width: 9%; }
.tbl-price th:nth-child(5), .tbl-price td:nth-child(5) { width: 10%; }
.tbl-price th.num, .tbl-price td.num { text-align: right; }
.tbl-price td:last-child { text-align: right; }

/* ============================================================
   Строки состояния в форме записи (деньги и график)
   ------------------------------------------------------------
   Две строки отвечают на два вопроса: чем пациент заплатит и работает ли
   кто-то в это время. Раньше ответ приходил вразнобой — жёлтая плашка сверху,
   кнопка отдельной строкой, красная подпись под полем и галочка в самом низу
   окна. Четыре места про одно и то же читаются как «что-то не так», а что
   делать — непонятно (Паша, 05.09.2026).

   Теперь строка одна на вопрос: слева то, что происходит, справа — действие,
   которым это решается, а подтверждение (галочка) стоит сразу под ней.
   Цвет — только смысл: тихо-серый (справка), янтарный (нужно решение),
   красный (пока нельзя).
   ============================================================ */
.state-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  background: var(--surface-sunken); color: var(--muted);
  font-size: 13px; line-height: 1.45;
}
.state-row .state-text { flex: 1 1 auto; min-width: 0; }
.state-row .btn { flex: 0 0 auto; }
/* кнопка внутри строки живёт на её фоне: белая заливка спорила бы с цветом смысла */
.state-row .btn-ghost { background: var(--bg); }
.state-row.is-warn { background: var(--warning-tint); color: oklch(0.42 0.12 75); }
.state-row.is-stop { background: var(--danger-tint); color: var(--danger); }

/* Подтверждение стоит вплотную к своей строке — это ответ на неё, а не отдельная
   настройка формы. Отступ сверху маленький, слева выровнено по тексту строки. */
.state-check { flex-direction: row; align-items: center; gap: var(--sp-2);
  margin: 2px 0 var(--sp-2); padding-left: var(--sp-3); font-size: 13px; }
.state-check input { width: 16px; height: 16px; flex: none; }

/* В окне записи то же подтверждение стоит в сетке — справа от часов, на одной
   линии с ними: его нажимают, глядя в список времени, который оно и открывает. */
/* Часы и подтверждение «вне графика» — одна ячейка сетки: галочка открывает
   закрытые часы, поэтому стоит рядом с ними, а не отдельной строкой внизу,
   где её не связывают со списком времени (Паша, 20.09.2026). */
.field-pair { display: flex; align-items: flex-end; gap: var(--sp-3); }
.field-pair > .field, .field-pair > .lc-field { flex: 1 1 auto; min-width: 0; }
.field-pair > .state-check { flex: 0 0 auto; padding-left: 0; margin: 0;
  border-bottom: none; cursor: pointer; white-space: nowrap; }
/* В окне записи часы стоят слева, подтверждение — соседней ячейкой справа,
   на одной линии с ними: пара в одной ячейке сплющивала список времени. */
.lc-grid > .state-check { align-self: end; padding-left: 0; margin: 0;
  padding-bottom: calc(var(--sp-2) + 4px); border-bottom: none; cursor: pointer; }
.field-pair > .field-check.state-check { padding-bottom: 8px; }
.field-pair > .state-check > span { font-size: 13px; color: var(--ink); }

/* Тихая текстовая кнопка в подвале окна: второй, редкий путь того же действия
   («курс ещё не выбрали — принять авансом»). Оформлять её как кнопку нельзя —
   три кнопки в ряд заставляют выбирать там, где выбор один. */
.btn-link { margin-left: auto; background: none; border: 0; padding: 0 2px;
  color: var(--muted); font: inherit; font-size: 12.5px; text-decoration: underline;
  text-underline-offset: 2px; cursor: pointer; }
.btn-link:hover { color: var(--ink); }

/* --- ссылка на смену пароля в карточке сотрудника ---------------------------- */
.pass-link-row { display: flex; gap: var(--sp-2); align-items: center; }
.pass-link-row input { flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 12.5px; }
.pass-link-note { margin: var(--sp-3) 0 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.login-forgot { display: block; margin-top: var(--sp-3); text-align: center; font-size: 13px;
  color: var(--muted); }
.login-forgot:hover { color: var(--text); }

/* Переходы в шапке окна сделки.
   Внизу окна помещаются три кнопки, а их было пять: главная — «Записать
   на консультацию» — уезжала за край (Паша, 08.09.2026). Переходы «написать»,
   «карточка пациента», «открыть целиком» — это не действия, а уход отсюда туда,
   и стоят они рядом с именем. */
.lc-links { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 6px; }
.lc-links a {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 13px; color: var(--muted); text-decoration: none;
}
.lc-links a:hover { color: var(--ink); text-decoration: underline; }
.lc-links .icon { opacity: .8; }

/* Доплата по начатой покупке в окне приёма: человек внёс часть заранее,
   остальное несёт на приёме. Стоит выше формы новой покупки — это первое,
   что надо сделать, и только если не подходит, заводится другая покупка. */
.settle-box {
  border: 1px solid var(--border); border-radius: 10px;
  padding: 12px 14px; margin-bottom: 14px;
  display: flex; flex-wrap: wrap; gap: 12px; align-items: end;
}
.settle-line { flex: 1 1 100%; font-weight: 600; }
.settle-box .field { flex: 1 1 200px; margin: 0; }

/* Срок задачи: день и час — один вопрос, одна ячейка сетки.
   Разнесённые по разным строкам «Срок» и «Во сколько» читаются как два разных
   дела, хотя человек назначает одно: «связаться завтра в 11». Час стоит рядом
   с датой и уже её — он уточняет день, а не спорит с ним. Пустой час означает
   «в течение дня»: поле необязательное, и настаивать на нём нечего. */
.due-pair { display: flex; gap: var(--sp-2); align-items: center; }
.due-pair > input[type="date"] { flex: 1 1 auto; min-width: 0; }
/* час занимает ровно столько, сколько занимает «11:30»: место в строке нужно
   дате, и она не должна обрезаться на середине года */
.due-pair > input[type="time"] { flex: 0 0 auto; width: 74px; padding-right: 6px; }
.due-pair > input[type="time"]::-webkit-calendar-picker-indicator { display: none; }
.due-pair > input[type="date"]::-webkit-calendar-picker-indicator { margin-left: 0; }
.due-pair > input {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 9px 11px; outline: none; box-sizing: border-box; }
.due-pair > input:focus {
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.due-pair > input:disabled { background: var(--surface-sunken); color: var(--muted); }

/* Пара «подпись — поле» в полосе фильтров: даты в реестре операций. */
.field-inline { display: inline-flex; align-items: center; gap: 6px; }
.field-inline > span { color: var(--muted); font-size: 13px; }

/* ============================================================
   Полоса фильтров реестра операций (13.09.2026)
   ------------------------------------------------------------
   Полоса собиралась из голых `<select>` и голых `input[type=date]`: рядом
   с органами управления соседних экранов они выглядели чужими — другой рост,
   другой шрифт, другие рамки, а выбранное значение ничем не отличалось
   от невыбранного. Здесь она говорит тем же языком, что доска сделок и касса.
   ============================================================ */

/* Период — один ответ на один вопрос «за какие дни», поэтому обе даты живут
   в одной рамке. Отдельными полями со словами «с» и «по» они занимали треть
   полосы и читались как два независимых фильтра. */
.fb-range {
  display: inline-flex; align-items: center; gap: 2px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); padding: 3px 7px;
  transition: border-color 150ms ease-out;
}
.fb-range:hover { border-color: var(--border-strong); }
.fb-range:focus-within {
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint);
}
.fb-range input[type="date"] {
  font-family: inherit; font-size: 12.5px; line-height: 18px; color: var(--ink);
  border: 0; background: none; outline: none; padding: 0;
  font-variant-numeric: tabular-nums;
}
.fb-range .fb-range-dash { color: var(--muted); font-size: 12.5px; }
/* значок календаря нужен как подсказка, но в полосе их два подряд —
   поэтому он тихий и просыпается под курсором */
.fb-range input[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0.4; padding: 0; margin: 0 0 0 3px; cursor: pointer;
  transition: opacity 150ms ease-out;
}
.fb-range input[type="date"]:hover::-webkit-calendar-picker-indicator,
.fb-range input[type="date"]:focus::-webkit-calendar-picker-indicator { opacity: 0.85; }

/* Пациент в полосе — тот же поиск, что в окнах денег, но ростом с соседние
   списки: карточек больше тысячи, выпадающим списком тут не обойтись. */
.fb-picker { width: 168px; }
.fb-picker .picker-search {
  border-color: var(--border); padding: 0 8px; border-radius: var(--r-sm);
}
.fb-picker .picker-search:hover { border-color: var(--border-strong); }
.fb-picker .picker-search input { font-size: 12.5px; padding: 4px 0; line-height: 18px; }
.fb-picker .picker-search input::placeholder { color: var(--muted); }
/* выбранный пациент выглядит как выбранный фильтр рядом — той же тихой заливкой */
.fb-picker .picker-chosen {
  padding: 3px 4px 3px 8px; font-size: 12.5px;
  border-color: var(--primary-tint-strong); color: var(--primary-hover);
}
.fb-picker .picker-chosen b {
  font-weight: 500; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fb-picker .picker-clear { font-size: 16px; }
/* подсказки поиска шире самого поля: в них фамилия и телефон */
.fb-picker .picker-results { width: 264px; right: auto; }

/* Enter в поле даты обязан отправлять полосу и без мыши, но кнопка на экране
   лишняя: выбор срабатывает сам. Поэтому она есть в разметке и не видна. */
.fb-go {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* Итог полосы не режем: подсказка под фильтрами объясняет, что за срез виден,
   и на ноутбуке она нужна ровно так же, как на большом экране (полоса
   переносит её на вторую строку — за это отвечает .filterbar-money). */
.filterbar-money .filter-note { display: block; }
/* поиск пациента раскрывается вниз, поэтому полоса не должна его обрезать;
   переносящейся полосе горизонтальная прокрутка и не нужна */
.filterbar-money { overflow: visible; }

@media (prefers-reduced-motion: reduce) {
  .fb-range,
  .fb-range input[type="date"]::-webkit-calendar-picker-indicator { transition: none; }
}

/* Форма из одной кнопки в шапке: отмена покупки идёт запросом, а не ссылкой. */
.inline-form { display: inline; }

/* Вкладки внутри раздела: касса · по месяцам · операции. */
.tabs { display: inline-flex; gap: 2px; margin-left: 16px; }
.tabs .tab {
  padding: 6px 12px; border-radius: 8px; font-size: 14px;
  color: var(--muted); text-decoration: none;
}
.tabs .tab:hover { background: var(--surface-sunken); color: var(--ink); }
.tabs .tab.active { background: var(--primary-tint); color: var(--ink); font-weight: 600; }

/* ============================================================
   Окно записи · блок «Кто придёт»
   Пять положений, из которых показывается ровно одно: выбранный человек,
   выбор из нескольких на одном номере, поиск, новая карточка, человек из сделки.
   ============================================================ */

.book-row {
  display: flex; align-items: center; gap: var(--sp-2);
  flex-wrap: wrap; margin-top: var(--sp-2);
}
.book-row .btn-link { margin-left: auto; }
.book-title { font-size: 13px; }

/* выбор из нескольких: на один номер записана вся семья */
.book-list {
  margin-top: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden;
}
.book-item {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; padding: var(--sp-2) var(--sp-3);
  background: none; border: 0; text-align: left; font: inherit; color: var(--ink);
}
.book-item + .book-item { border-top: 1px solid var(--border); }
.book-item:hover, .book-item:focus-visible { background: var(--primary-tint); outline: none; }
.book-who b { display: block; font-size: 13.5px; font-weight: 500; }
.book-who em { font-style: normal; color: var(--muted); font-size: 11.5px; }
.book-when { margin-left: auto; color: var(--muted); font-size: 11.5px; white-space: nowrap; }
.book-new { color: var(--primary); font-weight: 600; font-size: 12.5px; }

/* похожая карточка: не запрет, а подсказка с готовым действием */
.book-twin {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-3);
  background: var(--warning-tint); border: 1px solid var(--warning);
  border-radius: var(--r-md); font-size: 12.5px;
}
.book-twin .btn-link { margin-left: auto; color: var(--primary); font-weight: 600; }

/* строка состояния бланка: кем он заполнен — найденным человеком или руками */
.book-state { font-size: 12px; color: var(--muted); }
.book-state.is-on { color: var(--ink); font-weight: 500; }
.lc-field input[readonly] { color: var(--muted); border-bottom-style: dashed; }

/* Вложения в переписке (20.09.2026) --------------------------------------------
   Файл в сообщении — строка со скрепкой, а не карточка: в ленте переписки он
   стоит рядом с текстом того же сообщения и не должен перетягивать взгляд.
   Пока файл лежит только у шлюза, ссылки нет — и об этом сказано прямо. */
.msg-file { display: flex; align-items: center; gap: 6px; font-size: 13px; margin-top: 4px; }
.msg-file .icon { color: var(--muted); }
.msg-file a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Состояние нашего сообщения («ждёт отправки», «не дошло»). Раньше подпись
   помечалась классом neg, которого для строки не существовало, — и предупреждение
   было того же цвета, что и всё остальное. */
.msg-meta .neg { color: var(--danger); }

/* Доработки по обратной связи (23.09.2026) --------------------------------------
   Очередь того, что команда просит доделать. Строка раскрывается в задание, оценки
   правятся прямо в ней. Не карточки-плитки: это список, который читают сверху вниз. */
 /* Итог по отобранному — у правого края полосы, как требует DESIGN.md.
   Распорка .filter-spacer тут не годится: полоса не переносит строки и прокручивается
   вбок, поэтому распорка съедает всю ширину и выталкивает подпись за экран.
   И общее правило «на экране уже 1400px итог прячем» здесь вредно: в этой полосе
   кроме итога ничего нет — спрятав его, мы оставили бы пустую белую полосу. */
.filterbar .filter-note.fbk-totals { display: block; margin-left: auto; }
.fbk-lede { max-width: 72ch; color: var(--muted); font-size: 13px; margin-bottom: var(--sp-4); }
.fbk-list { display: flex; flex-direction: column; gap: 6px; }

.fbk-item {
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden;
}
.fbk-item.is-done { opacity: .6; }
.fbk-item > details > summary { list-style: none; cursor: pointer; }
.fbk-item > details > summary::-webkit-details-marker { display: none; }
.fbk-item > details[open] { background: var(--surface); }

.fbk-row {
  display: grid; grid-template-columns: 42px 1fr auto; gap: var(--sp-3);
  align-items: center; padding: 11px var(--sp-3);
}
.fbk-row:hover { background: var(--surface-sunken); }
.fbk-score {
  font-size: 16px; font-weight: 600; text-align: center; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.fbk-item.is-block .fbk-score { color: var(--danger); }
.fbk-title { min-width: 0; font-size: 14px; font-weight: 500; }
/* Номер задачи — чтобы её можно было назвать словами: «сделай I-03» */
.fbk-code { color: var(--muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.fbk-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 3px;
  font-size: 12px; font-weight: 400; color: var(--muted); }
.fbk-meta b { font-weight: 500; color: var(--muted); }
.fbk-item.is-block .fbk-meta b { color: var(--danger); }
.fbk-state { font-size: 12px; color: var(--muted); white-space: nowrap; }
.fbk-state-have { color: var(--success); }
.fbk-state-part { color: var(--warning); }

.fbk-body { padding: var(--sp-2) var(--sp-3) var(--sp-4) 66px; border-top: 1px solid var(--border); }
.fbk-body h3 { font-size: 12.5px; font-weight: 500; color: var(--muted); margin: var(--sp-3) 0 4px; }
.fbk-body p { max-width: 72ch; font-size: 13.5px; }
.fbk-body blockquote {
  max-width: 72ch; font-size: 13.5px; color: var(--muted);
  border-left: 1px solid var(--border); padding-left: var(--sp-3);
}

/* План проверки от исполнителя: читается сверху вниз, поэтому строки не склеиваем */
.fbk-steps { white-space: pre-wrap; font: inherit; font-size: 13.5px; max-width: 72ch;
  background: var(--surface-sunken); border-radius: var(--r-sm); padding: var(--sp-3); }

/* Исходник замечания: запись экрана или снимок от сотрудника. Видео не грузится,
   пока его не попросили (preload="none"): в списке из двух десятков задач иначе
   уходит вся связь, а смотрят одну-две записи. */
.fbk-video { display: block; width: 100%; max-width: 560px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: #000; margin-top: var(--sp-2); }
.fbk-shot { display: block; width: 100%; max-width: 560px; border-radius: var(--r-md);
  border: 1px solid var(--border); margin-top: var(--sp-2); }
.fbk-links { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-4);
  margin-top: var(--sp-2); font-size: 13px; }
.fbk-links a { color: var(--primary); }
.fbk-text summary { cursor: pointer; color: var(--muted); font-size: 13px; }
.fbk-text pre { white-space: pre-wrap; font: inherit; font-size: 13px; color: var(--muted);
  max-width: 72ch; margin-top: var(--sp-2); }

.fbk-marks {
  display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center;
  margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border);
}
.fbk-knob { display: flex; align-items: center; gap: 4px; font-size: 12.5px; color: var(--muted); }
.fbk-mark {
  width: 28px; height: 28px; margin-left: 2px; font: inherit; font-size: 12.5px;
  color: var(--muted); background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-sm); cursor: pointer;
}
.fbk-mark:hover { color: var(--ink); }
.fbk-mark.on { color: var(--on-primary); background: var(--primary); border-color: var(--primary); font-weight: 600; }
.fbk-statuses { gap: 4px; }
.fbk-status {
  font: inherit; font-size: 12.5px; color: var(--muted); background: var(--bg);
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px; cursor: pointer;
}
.fbk-status:hover { color: var(--ink); }
.fbk-status.on { color: var(--on-primary); background: var(--primary); border-color: var(--primary); font-weight: 600; }

@media (max-width: 760px) {
  .fbk-row { grid-template-columns: 34px 1fr; }
  .fbk-state { grid-column: 2; }
  .fbk-body { padding-left: var(--sp-3); }
}

/* --- Действие в шапке панели (I-03, 24.09.2026) ----------------------------
   Шапка панели раскидывает содержимое по краям. Кнопка, поставленная третьей,
   вставала бы посередине, оттесняя подпись к правому краю, — поэтому свободное
   место забирает она, а заголовок и подпись остаются рядом, как и были. */
.panel-head > .btn { margin-left: auto; align-self: center; }

/* --- Окно с двумя состояниями: карточка ↔ правка (24.09.2026) --------------
   «Изменить» не открывает второе окно поверх первого: меняется содержимое той же
   рамки. Движение говорит, что это переключение внутри одного окна, а не новое
   окно поверх старого. Видимость от анимации не зависит — если она не проиграется
   (снимок экрана, свёрнутая вкладка), содержимое всё равно на месте. */
#quickBody > * { animation: quick-swap 160ms cubic-bezier(0.22, 1, 0.36, 1); }

@keyframes quick-swap {
  from { opacity: 0.4; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  #quickBody > * { animation: none; }
}

/* Подпись под именем в режиме правки — того же роста, что строка состояния
   в просмотре: шапка не должна подпрыгивать при переключении. */
.lc-sub .role-tag { vertical-align: middle; }

/* Состояния записи на приём: подтверждение обзвона и виды отмены ---------------
   R-02 (замечание Ксении, 21.09.2026). Три состояния до приёма вместо двух:
   «Записан» — обзвона ещё не было, «Подтверждено» — дозвонились, «Не подтверждено» —
   звонили и подтверждения не получили.

   Цвет отвечает на вопрос «на что смотреть», а не «как это записано в базе»:
   подтверждённых накануне большинство, поэтому они тихие, а заметен тот, к кому
   ещё надо вернуться, и приём, который сорвался поздно. */
.status-planned { background: oklch(0.945 0 0); color: oklch(0.45 0 0); }
.status-confirmed { background: var(--success-tint); color: oklch(0.42 0.12 150); }
.status-not_confirmed { background: var(--warning-tint); color: oklch(0.48 0.11 75); }
.status-came { background: var(--success-tint); color: oklch(0.42 0.12 150); }
.status-no_show { background: var(--surface-sunken); color: var(--muted); }
.status-cancelled { background: var(--surface-sunken); color: var(--muted); }
.status-late_cancel { background: var(--danger-tint); color: var(--danger); }
.status-center_cancel { background: var(--warning-tint); color: oklch(0.48 0.11 75); }

/* значки в сетке недели: подтверждение тихое, вопрос — заметный */
.mark-ok { background: var(--surface-sunken); color: oklch(0.42 0.12 150); }
.mark-ask { background: oklch(0.95 0.06 75); color: oklch(0.42 0.12 75); }

/* Выбор одного из нескольких: что случилось с приёмом, каким способом заплатили.
   Строками, а не выпадающим списком: вариантов три, и все они должны быть видны
   сразу — закрытый список прячет именно тот, о котором человек не подумал. */
.pickone { display: flex; flex-direction: column; }
.pickone label { display: flex; align-items: center; gap: var(--sp-2);
  padding: 11px 2px; border-bottom: 1px solid var(--border); cursor: pointer; }
.pickone label:last-child { border-bottom: 0; }
.pickone input { margin: 0; accent-color: var(--primary); }
.pickone .name { font-size: 13.5px; font-weight: 500; }
.pickone .why { margin-left: auto; font-size: 12px; color: var(--muted); text-align: right; }

/* Кто проводит деньги — отдельной строкой под фактом об оплате ------------------
   I-10, 24.09.2026. Менеджер видит, чем закрыт приём, но кнопок оплаты у его
   роли нет и не должно быть. Подпись объясняет почему, и стоять она обязана
   своей строкой: приклеенная к сумме, она читается как продолжение числа
   («на счету 2 000 ₸ оплату проводит администратор»). */
.money-by { display: block; margin-top: 2px; font-size: 11.5px; font-style: normal;
  color: var(--muted); }

/* Ответственный взрослый заводится тут же --------------------------------------
   R-07, 24.09.2026. Родителя не бывает в базе раньше ребёнка: их приводят вместе,
   и уход на отдельную страницу означал, что набранное про ребёнка ждёт в другой
   вкладке. Поэтому заведение живёт внутри поля поиска. */

/* Строка «завести» — последняя в подсказках и единственная, когда не нашлось
   никого. Стоит там же, где человек уже смотрит, и не занимает места в форме,
   пока не нужна. Липнет к низу: список прокручивается, выход остаётся на виду. */
.picker-add { display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  text-align: left; background: var(--bg); border: 0; border-top: 1px solid var(--border);
  padding: 10px 11px; cursor: pointer; font-family: inherit; font-size: 13px;
  color: var(--primary); font-weight: 500; position: sticky; bottom: 0; }
.picker-results > .picker-add:first-child { border-top: 0; }
.picker-add:hover { background: var(--primary-tint); }
.picker-add .icon { color: var(--primary); flex: none; }
.picker-add span { color: var(--muted); font-weight: 400; }

/* Панель заведения — в потоке формы, а не поверх неё: так видно, что это часть
   карточки ребёнка, и ничего под ней не прячется. Появляется движением: там,
   где анимация не проигралась, панель просто стоит на месте открытой. */
.picker-new { border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-sunken); padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-3);
  animation: picker-new-in 0.18s cubic-bezier(0.22, 1, 0.36, 1); }
@keyframes picker-new-in { from { transform: translateY(-6px); } }

.picker-new-head { display: flex; align-items: center; gap: var(--sp-2);
  font-size: 12.5px; font-weight: 600; color: var(--ink); }
.picker-new-head .icon { color: var(--muted); }
.picker-new-head .picker-clear { margin-left: auto; }

.picker-new-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.picker-new-grid .field-wide { grid-column: span 2; }
.picker-new .field > input { width: 100%; box-sizing: border-box; background: var(--bg); }

.picker-new-foot { display: flex; align-items: center; gap: var(--sp-2); }
.picker-new-foot .btn { padding: 6px 12px; font-size: 12.5px; }

/* Номер уже записан у другого человека — это не ошибка ввода, а находка: почти
   всегда это и есть тот самый родитель, заведённый раньше с другим написанием
   фамилии. Поэтому не красная ругань, а предложение выбрать его. */
.picker-dupe { display: flex; align-items: center; gap: var(--sp-3);
  background: var(--warning-tint); border-radius: var(--r-sm); padding: 9px 11px;
  font-size: 12.5px; color: oklch(0.42 0.09 75); }
.picker-dupe > div { flex: 1; min-width: 0; }
.picker-dupe b { display: block; font-weight: 500; color: var(--ink); font-size: 13px; }
.picker-dupe .btn { flex: none; background: var(--bg); }

/* Рядом с именем выбранного теперь стоит метка («новая карточка»), и длинное имя
   должно уступать ей место, а не переносить строку и ломать высоту поля. */
.picker-chosen b { min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }

/* Погашенная кнопка. Окна гасят кнопки на время отправки и рассчитывают, что это
   видно («одно нажатие — одно дело», dialogs.js), — но стиля для этого в системе
   не было вовсе, и погашенная кнопка выглядела точно так же, как живая. */
.btn:disabled { opacity: 0.5; pointer-events: none; }

/* ============================================================
   Кого нет в расписании (R-04)

   Отсутствие терапевта живёт в сетке приёмов двумя видами, и это не вкусовщина,
   а разные вопросы. Часть дня — плашка в своём часу: она отвечает, почему в этот
   час пусто и почему сюда нельзя записать. Целый день и дольше — строка под датой:
   плашка в каждом часу превращает десятидневный отпуск в столбец сверху донизу
   и закрывает собой занятия, ради которых в расписание и смотрят (выбор Ризы
   Рустамовны, 25.09.2026).

   Плашка намеренно не похожа на карточку приёма: пунктир вместо рамки и тихий
   цвет. Это не занятие, и считать её занятием нельзя ни глазом, ни отчётом.
   ============================================================ */

.offchip { display: block; padding: 5px 7px 6px; border: 1px dashed oklch(0.88 0.04 75);
  border-radius: var(--r-sm); background: oklch(0.985 0.018 75); font-size: 11px;
  color: oklch(0.53 0.075 75); }
.offchip b { display: block; color: oklch(0.42 0.07 75); font-weight: 500; font-size: 12.5px;
  margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Почему янтарный, а не красный и не зелёный. Красный в системе занят поломкой учёта
   (приём прошёл, отметки нет) — закрытое время не поломка и красться в один ряд с ней
   не должно. Зелёный означает «пришёл, всё хорошо». Янтарный — «особый режим, сюда
   нельзя записать», ровно то, на что администратор смотрит. Заливка тихая: плашек
   в неделе бывает десяток, и насыщенный цвет превратил бы сетку в светофор. */

/* Строка «кого нет» стоит между шапкой дней и часами и прокручивается вместе
   с сеткой: она про эту неделю, а не про экран. Пустая клетка остаётся клеткой —
   иначе строка разъезжается по дням. */
.dayoff { background: var(--surface); border-bottom: 1px solid var(--border);
  padding: 4px 10px 7px; display: flex; flex-direction: column; gap: 1px;
  font-size: 11px; line-height: 1.4; color: var(--muted); }
.dayoff-item { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: oklch(0.53 0.075 75); }
.dayoff-item b { color: oklch(0.42 0.07 75); font-weight: 500; }
/* тот же язык, что у плашки в часах: один и тот же выходной не должен выглядеть
   двумя разными способами в зависимости от того, целый он день или нет */
.dayoff:has(.dayoff-item) { background: oklch(0.985 0.018 75); }
.dayoff-rail { position: sticky; left: 0; z-index: 1; background: var(--surface);
  border-bottom: 1px solid var(--border); padding: 4px 8px 0 0; text-align: right;
  font-size: 11px; color: var(--muted); }

/* ============================================================
   Справочник видов приёма (настройки, задача P-01)
   ------------------------------------------------------------
   Ширины заданы жёстко: панелей на экране три — по одной на полку, — и без
   этого каждая таблица считает ширину по своему содержимому. Колонки съезжают
   от панели к панели, и один и тот же справочник читается как три разных.
   ============================================================ */
.tbl-dict { table-layout: fixed; }
.tbl-dict th:nth-child(1), .tbl-dict td:nth-child(1) { width: 42%; }
.tbl-dict th:nth-child(2), .tbl-dict td:nth-child(2) { width: 20%; }
.tbl-dict th:nth-child(3), .tbl-dict td:nth-child(3) { width: 14%; }
.tbl-dict th:nth-child(4), .tbl-dict td:nth-child(4) { width: 10%; }
.tbl-dict th:nth-child(5), .tbl-dict td:nth-child(5) { width: 14%; }
.tbl-dict th.num, .tbl-dict td.num { text-align: right; }
.tbl-dict td:last-child { text-align: right; }

/* --- Связь: что уходит пациентам (I-07) -------------------------------------- */
.out-summary { display: flex; align-items: center; gap: 20px; padding: 0 20px 14px; }
.out-summary form { margin-left: auto; }
.out-empty { padding: 0 20px 18px; }
.out-label { padding: 18px 20px 6px; font-size: 12px; color: var(--muted); }

/* Часы отсутствия в графике недели. Красится только эта строка: рабочие часы дня
   никуда не делись, и красить их — значит сказать «смотри сюда» про то,
   что не изменилось. */
.hours-tbl .hours-off { color: var(--danger); }

/* Отказ в справочнике стоит внутри панели, между заголовком и таблицей:
   общее сообщение системы нарисовано как успех, и отказ в нём читается «готово». */
.dict-refusal { margin: 0 20px 14px; }

/* Что добавляем в этот час — приём или отсутствие (R-04, решение Паши 25.09.2026).
   Переключатель стоит первым вопросом окна, а сетка остаётся с одной кнопкой:
   вторая кнопка в каждой из девяноста ячеек шумела бы постоянно ради действия,
   которое делают раз в день. Органы управления берём готовые — это те же chip,
   что в полосе фильтров, а не свой третий вид переключателя. */
.event-tabs { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.event-tabs .chip { cursor: pointer; font-size: 12.5px; padding: 6px 12px; }
.event-tabs .chip:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Какой час закрываешь — видно в заголовке окна: в сетке сотня одинаковых ячеек. */
.modal-head .modal-when { font-size: 12.5px; font-weight: 400; color: var(--muted); }

/* ── Счета: предупреждение о двойнике ────────────────────────────────
   Два счёта на одно и то же администратор проведёт дважды, и в кассе
   окажется вдвое больше. Поэтому уже выставленное показывается прямо
   в окне заведения, а рядом стоит «Заменить» — одно нажатие вместо
   похода в список. */
.invoice-dup {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 12px; padding: 10px 14px;
  background: var(--warning-tint);
  border: 1px solid var(--warning);
  border-radius: var(--r-sm);
  font-size: 13px;
}
.invoice-dup span { flex: 1; min-width: 220px; }

/* ── Окно приёма: что с записью делали ──────────────────────────────
   Раньше след переноса оставался только в примечании, написанном руками, —
   и разовая пометка «перенесли, клиентка попросила» висела постоянным
   примечанием к приёму (Паша, 26.09.2026). Три последние правки стоят
   тихим блоком под примечанием: смотреть в них нужно редко, но искать
   их в другом экране не должно быть нужно вовсе. */
.peek-log { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.peek-log-head { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); margin-bottom: 8px; }
.peek-log-row { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 12.5px;
  line-height: 1.5; padding: 3px 0; }
.peek-log-when { color: var(--muted); white-space: nowrap; }
.peek-log-what { color: var(--ink); flex: 1; min-width: 180px; }

/* ── Пара полей: ошибка под одним не двигает второе (R-04) ───────────
   «Часы с» и «до» стоят парой, и пара выравнивалась по низу. Стоило
   под правым полем появиться красной строке «Конец должен быть позже
   начала», как левое поле уезжало вниз, а его ширину забирал текст
   ошибки — подпись «Часы с» оказывалась ниже подписи «до», а само
   поле сплющивалось (приёмка 26.09.2026). Поля делят ширину поровну
   независимо от содержимого, а выравниваются по верху: сообщение
   растёт вниз, в пустоту, и соседа не трогает. Галочка «вне графика»
   остаётся у нижней линии поля — она про строку времени рядом. */
.field-pair > .field:not(.field-check) {
  flex: 1 1 0; align-self: stretch; }

/* ============================================================
   Аналитика (раздел из нескольких отчётов, 27.09.2026)
   ------------------------------------------------------------
   Раздел собран так, чтобы новый отчёт добавлялся файлом: общее здесь —
   вкладки, полоса периода и плотность таблиц, а не вёрстка каждой страницы.
   Ничего нового по виду: те же панели, таблицы и полоски, что в «Контроле»
   и «Деньгах по месяцам», — иначе раздел выглядел бы сделанным отдельно.
   ============================================================ */

/* Вкладки раздела обязаны стоять ЗА названием экрана — так написано в правиле
   верхней панели, но `order` у них не был задан, и при значении по умолчанию (0)
   они вставали перед названием: первым, что читал глаз, была вкладка, а не раздел.
   Видно на «Деньгах по месяцам» и на любом экране с `.tabs`. */
.topbar .tabs { order: 2; }

/* Полоса периода переносится, а не режет срезы: на ноутбуке пять срезов,
   две даты и подпись в одну строку не встают, и «Этот год» уезжал за край. */
.filterbar-an { height: auto; min-height: 44px; flex-wrap: wrap; overflow: visible;
  padding-top: 5px; padding-bottom: 5px; row-gap: var(--sp-1); }
.filterbar-an .filter-spacer { display: none; }
.filterbar-an .filter-note { margin-left: auto; display: block; }

/* Отчёты плотнее остальных экранов: в таблице менеджеров одиннадцать колонок.
   1080px под неё мало — числа сжимаются до нечитаемых. */
.an-pad { max-width: 1320px; }

/* Переключатель разреза живёт в шапке панели, рядом с подписью: он относится
   к этой таблице, а не к экрану, и на полосе фильтров ему не место. */
.panel-tools { display: flex; align-items: center; gap: var(--sp-3); }

/* Широкая таблица прокручивается внутри своей панели, а не режется молча. */
.tbl-scroll { overflow-x: auto; margin: 0 calc(var(--sp-5) * -1); padding: 0 var(--sp-5); }
.tbl-scroll > .tbl { min-width: 880px; }

/* Двухуровневая шапка: консультации и курс — две группы колонок. Без группировки
   одиннадцать одинаковых заголовков читаются сплошным списком, и «Продано»
   невозможно отнести ни к тому, ни к другому. */
.tbl-group thead th { white-space: nowrap; }
.tbl-group thead tr:first-child th { border-bottom: 0; padding-bottom: 2px; }
.tbl-group thead tr:first-child th.grp {
  text-align: center; color: var(--ink); font-weight: 600;
  border-left: 1px solid var(--border); border-right: 1px solid var(--border);
}
.tbl-group thead tr:last-child th { top: 26px; }
.tbl-group tbody tr.row-total td { font-weight: 600; background: var(--surface-sunken); }
.tbl-group td.grp-start { border-left: 1px solid var(--border); }
.tbl-group td.grp-end { border-right: 1px solid var(--border); }
.tbl-group thead tr:last-child th.grp-start { border-left: 1px solid var(--border); }
.tbl-group thead tr:last-child th.grp-end { border-right: 1px solid var(--border); }

/* Шаги воронки. Не плитки с иконками: у каждого шага число, деньги, доля
   от первого шага и конверсия от соседа слева — то есть четыре разных ответа,
   а не украшение. Стрелка между шагами показывает, куда течёт поток. */
.an-steps { list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--sp-3); }
.an-step { display: flex; flex-direction: column; gap: 6px; position: relative;
  padding: var(--sp-3) var(--sp-3) var(--sp-3) 0; }
.an-step + .an-step { padding-left: var(--sp-4); border-left: 1px solid var(--border); }
.an-step-name { font-size: 12.5px; color: var(--muted); }
.an-step-val { font-size: 26px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; line-height: 1.1; }
.an-step-money { font-size: 13px; font-variant-numeric: tabular-nums; }
.an-step-bar { height: 6px; border-radius: 999px; background: var(--surface-sunken); overflow: hidden; }
.an-step-bar span { display: block; height: 100%; border-radius: 999px; background: var(--primary); }
.an-step-conv { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.an-step-conv b { color: var(--ink); font-weight: 600; }
/* потерянные по дороге — тихо, но видно: это и есть вопрос к отделу продаж */
.an-step-drop { font-size: 12px; color: var(--danger); font-variant-numeric: tabular-nums; }

@media (max-width: 760px) {
  .an-step + .an-step { padding-left: 0; border-left: 0; border-top: 1px solid var(--border); }
}

/* ── Строка о связи в записи (I-07, кусок 4) ─────────────────────────
   «подтверждение отправлено · напоминание за сутки ушло · пациент
   подтвердил в 19:42» — ответ на единственный вопрос администратора
   перед обзвоном: звонить этому человеку или он уже ответил сам.

   Строка стоит в том же списке фактов, что зал и оплата, а не отдельной
   плашкой: это такой же факт о записи, и отдельный блок с заголовком
   был бы третьим блоком в окне, где и так есть примечание и «что меняли».
   Единственная вольность — строка занимает всю ширину: четыре фразы,
   прижатые к правому краю узкой колонки, читаются лестницей.

   Ответ человека выделен насыщенностью, а не цветом: в строке он главный,
   но красный в этом окне зарезервирован за «приём прошёл, отметки нет» —
   единственным настоящим сигналом. Неудача отправки берёт тот же янтарный,
   которым здесь уже сказано «приём не оплачен»: новый цвет в окно не входит,
   а «не в порядке, займись» читается сразу. */
.peek-facts > .comms-fact { flex-direction: column; align-items: stretch; gap: 3px; }
.peek-facts > .comms-fact dd { text-align: left; font-weight: 400; }
.facts > .comms-fact { grid-column: 1 / -1; }
.comms-fact dd { line-height: 1.5; }
.comms-part + .comms-part::before { content: " · "; color: var(--muted); }
.comms-part.is-answer { font-weight: 600; }
.comms-line.is-bad { color: oklch(0.42 0.12 75); }

/* Очередь будущих отправок — тихим рядом под случившимся. Три фразы «уйдёт»
   стоят у каждой записи и одинаковы у всех: набранные наравне, они съедают
   единственную важную — ту, по которой решают, звонить человеку или нет.
   Если не ушло ещё ничего, тихий ряд остаётся единственным и говорит
   обычным голосом: прятать вполоборота единственную фразу незачем. */
.comms-ahead { display: block; margin-top: 2px; font-size: 11.5px; color: var(--muted); }
.comms-ahead:empty { display: none; }
.comms-line.only-ahead .comms-ahead { margin-top: 0; font-size: inherit; color: inherit; }

/* «отправлено» без шлюза — правда только внутри системы, и молчать об этом
   нельзя: администратор решит, что человек предупреждён. Тихо и мелко —
   это оговорка к строке, а не второй сигнал; в день подключения шлюза
   она исчезнет сама, по самим сообщениям. */
.comms-demo { display: block; margin-top: 2px; font-size: 11.5px; color: var(--muted); }

/* Продажа курса менеджером: кто проводит деньги -------------------------------
   У менеджера в окне продажи нет полей кассы, и кнопка называется «счёт».
   Строка слева объясняет, почему кнопки приёма оплаты тут нет, — она стоит
   ровно там, где её ищут глазами, а не отдельным предупреждением сверху
   (правило «у одного вопроса — одно место на экране»). */
.modal-foot .foot-note { margin-right: auto; align-self: center;
  font-size: 12.5px; color: var(--muted); }
.form-actions .foot-note { margin-left: auto; align-self: center;
  font-size: 12.5px; color: var(--muted); }

/* Работа от лица сотрудника — техдоступ разработчика -------------------------
   Выбор спрятан в свой же кружок с инициалами внизу меню: нажал на себя — выбрал,
   чьими глазами смотреть. Отдельная кнопка рядом отнимала место у имени, и оно
   обрывалось на «Паве…». Список говорит тем же языком всплывашек, что меню
   на карточке сделки, — третий язык всплывающих панелей в системе не нужен. */
.avatar-switch { border: 0; font-family: inherit; cursor: pointer;
  transition: box-shadow 150ms ease-out; }
.avatar-switch:hover { box-shadow: 0 0 0 2px var(--primary); }
.avatar-switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.switch-pop { inset: auto auto 56px 12px; width: 236px; max-height: 62dvh; overflow-y: auto; }
.switch-pop::backdrop { background: transparent; }
.switch-note { font-size: 11.5px; line-height: 1.35; color: var(--muted);
  padding: 6px 10px 8px; margin-bottom: 4px; border-bottom: 1px solid var(--border); }

/* Пока работа идёт под чужим именем — это видно на каждом экране. Иначе легко
   наработать от чужого лица и не заметить: интерфейс-то настоящий. */
.sidebar-asif { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin: 0 var(--sp-3) var(--sp-3); padding: var(--sp-2) var(--sp-3);
  background: var(--warning-tint); border: 1px solid oklch(0.85 0.06 75);
  border-radius: var(--r-sm); font-size: 12px; color: oklch(0.42 0.09 75); }
.sidebar-asif > .icon { color: oklch(0.55 0.13 75); flex: none; }
.sidebar-asif b { display: block; font-weight: 600; color: oklch(0.32 0.07 75); }
.sidebar-asif form { flex: 1 0 100%; }
.sidebar-asif button { width: 100%; padding: 5px 8px; border-radius: var(--r-sm);
  border: 1px solid oklch(0.85 0.06 75); background: var(--bg);
  font: inherit; font-size: 12px; font-weight: 500; color: oklch(0.38 0.08 75);
  cursor: pointer; transition: background 150ms ease-out; }
.sidebar-asif button:hover { background: oklch(0.985 0.02 75); }
.sidebar-asif button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Свёрнутое меню: остаётся знак и кнопка возврата — предупреждение без выхода
   из него было бы ловушкой */
@media (max-width: 900px) {
  .sidebar-asif { justify-content: center; margin: 0 6px var(--sp-2); padding: var(--sp-2); }
  .sidebar-asif > div { display: none; }
  .switch-pop { inset: auto auto 56px 8px; }
}

/* ============================================================
   Расшифровка цифры (аналитика, 27.09.2026)
   ------------------------------------------------------------
   Цифра без расшифровки не сдаётся: любое число раздела открывается и показывает
   те самые записи, из которых сложилось. Значит **каждое число — орган управления**,
   и это должно быть видно, не превращая отчёт в синюю простыню ссылок.

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

.fig {
  color: inherit; text-decoration: none;
  border-bottom: 1px dashed var(--border-strong);
  transition: color 150ms ease-out, border-color 150ms ease-out;
  cursor: pointer;
}
.fig:hover, .fig:focus-visible { color: var(--primary-hover); border-bottom-color: var(--primary); }
.fig:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 2px; }
/* в крупной цифре сводки пунктир на всю ширину числа выглядит подчёркиванием строки —
   там он тоньше и ближе */
.kpi-val .fig { border-bottom-width: 1px; padding-bottom: 2px; }
/* ноль и прочерк не открываются: за ними нет записей, и пунктир обещал бы несуществующее */
.fig-none { color: var(--muted); }

/* Окно расшифровки */
.drill { display: flex; flex-direction: column; gap: var(--sp-4); }
.drill-group { display: flex; flex-direction: column; gap: var(--sp-2); }
.drill-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); }
.drill-title { font-size: 13px; font-weight: 600; }
.drill-sum { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.drill-tbl { font-size: 12.5px; }
.drill-tbl thead th { position: static; }      /* внутри окна липкая шапка не нужна */
.drill-tbl tbody td { padding: 6px var(--sp-3); }
.drill-empty { font-size: 13px; color: var(--muted); padding: var(--sp-3);
  background: var(--surface-sunken); border-radius: var(--r-sm); }

/* «Откуда эта цифра» — не украшение, а ответ на вопрос «почему столько».
   Стоит последним: сначала человек смотрит записи, потом читает правило. */
.drill-why {
  background: var(--surface-sunken); border-radius: var(--r-sm);
  padding: var(--sp-3); font-size: 12.5px; line-height: 1.5;
}
.drill-why b { font-weight: 600; }
.drill-why p { margin: 4px 0 0; color: var(--muted); }
.drill-why .drill-where { color: var(--muted); }

/* Та же расшифровка страницей: без JavaScript и в новой вкладке. */
.drill-page .modal-head { margin-bottom: var(--sp-3); }
.drill-page .modal-head h2 { margin: 0; font-size: 16px; font-weight: 600; }
.drill-page .modal-close { display: none; }
.drill-page .modal-body { padding: 0; }

@media (prefers-reduced-motion: reduce) {
  .fig { transition: none; }
}

/* Окно расшифровки шире обычного: в нём таблица на пять колонок, а не форма.
   В 560 пикселях имя пациента переносится на две строки, и список из двадцати
   операций превращается в сорок строк — читать его невозможно. Ширину объявляет
   само содержимое, а не экран: так же, как это делает окно приёма. */
.modal:has(.drill) { width: min(920px, calc(100vw - 32px)); }

/* Список длиной в сто строк уносит подпись «откуда эта цифра» на три экрана вниз —
   то есть ровно тот ответ, ради которого окно и открывали. Поэтому у списка своя
   прокрутка, а подпись остаётся на виду. */
.drill-scroll { max-height: 46dvh; overflow-y: auto; border-radius: var(--r-sm); }
.drill-scroll .tbl thead th { position: sticky; top: 0; z-index: 1; }

/* ============================================================
   Цвет вида приёма в сетке расписания (R-09, 27.09.2026)
   ------------------------------------------------------------
   Просьба Ксении Долниковской и Ирады Ибрагимовой: «разные приёмы — разным
   цветом, чтобы разобраться, только взглянув в расписание». До этого вид приёма
   жил в сетке одной серой строчкой в карточке, и чтобы отделить консультацию
   от занятия, её приходилось читать — сорок раз на экран.

   Цвет берётся у вида приёма (`AppointmentType.tone`) и приходит переменной
   `--apt-tone`. Сама сетка решает, насколько громко его показать, и решает тихо:
   заливка — одиннадцать процентов тона, то есть почти белый с оттенком. Иначе
   неделя из сорока карточек превращается в мозаику, и на что смотреть — непонятно.

   Цветом отвечает на вопрос «что это за приём» только фон и подпись вида.
   Состояние записи — отдельный разговор и отдельные знаки: красная рамка «прошёл,
   отметки нет», галочка «пришёл», зачёркнутое имя. Поэтому все состояния ниже
   восстанавливают свою рамку поверх цветной — иначе тон закрасил бы сигнал,
   ради которого в сетку и смотрят.
   ============================================================ */
.appt.has-tone {
  background: color-mix(in oklab, var(--apt-tone) 11%, var(--bg));
  border-color: color-mix(in oklab, var(--apt-tone) 26%, var(--border));
}
/* название вида — тем же тоном: цвет не должен держаться на одной заливке.
   Тот, кто цвета различает плохо, читает слово, и оно же связывает карточку
   с расшифровкой над сеткой. Контраст подписи на своей заливке ≥4.6:1 */
.appt.has-tone .appt-type { color: color-mix(in oklab, var(--apt-tone) 85%, var(--ink));
  font-weight: 500; }

.appt.has-tone:hover { border-color: color-mix(in oklab, var(--apt-tone) 55%, var(--border)); }
.appt.has-tone:focus-visible { border-color: var(--primary); }

/* Приём прошёл и отмечен: тон остаётся, но тише — эта карточка уже история,
   а сетка ниже по часам ещё живая */
.appt.has-tone.is-done { background: color-mix(in oklab, var(--apt-tone) 7%, var(--surface)); }

/* Отменённый и не пришедший цвет теряет совсем: вида приёма там больше нет,
   есть пустой слот. Зачёркнутое имя и серый фон говорят именно это */
.appt.has-tone.is-off { background: var(--surface); border-color: var(--border); }
.appt.has-tone.is-off .appt-type { color: var(--muted); font-weight: 400; }

/* Сигналы состояния сильнее цвета вида — рамку держат они */
.appt.has-tone.is-alert { border-color: oklch(0.82 0.09 25); }
.appt.has-tone.is-new { border-color: var(--primary); }

/* Расшифровка цветов — в полосе фильтров, слева от счётчика приёмов.
   Показывает только те виды, что на этой неделе есть, и заодно раскрывает
   сокращения карточек: в колонке «Индивид.», здесь — «Индивидуальное занятие».

   Полоса расписания из-за неё переносится на вторую строку, а не режет хвост:
   по умолчанию она прокручивается вбок, и на ноутбуке расшифровка выталкивала
   за край счётчик приёмов — то есть отвечала на один вопрос, унося ответ на другой. */
.filterbar-sched { height: auto; min-height: 44px; flex-wrap: wrap;
  padding-top: 5px; padding-bottom: 5px; row-gap: var(--sp-1); }
/* при переносе распорка забирает всю свободную ширину первой строки и сама
   сталкивает расшифровку вниз — вправо её прижимает отступ (как на экране денег) */
.filterbar-sched .filter-spacer { display: none; }
/* расшифровка и счётчик приёмов переезжают вниз вместе и вместе стоят справа:
   порознь счётчик уходил на вторую строку один и оказывался под фильтрами слева */
.filter-tail { display: flex; align-items: center; margin-left: auto; }

.apt-legend { display: flex; align-items: center; gap: var(--sp-3);
  margin-right: var(--sp-3); font-size: 11.5px; }
.apt-legend-item { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
  color: color-mix(in oklab, var(--apt-tone) 85%, var(--ink)); }
.apt-legend-item i { width: 15px; height: 11px; border-radius: 3px; flex: none;
  background: color-mix(in oklab, var(--apt-tone) 16%, var(--bg));
  border: 1px solid color-mix(in oklab, var(--apt-tone) 45%, var(--border)); }

/* Узкий экран: полоса фильтров не переносится, а прокручивается вбок, и расшифровка
   уводила бы за край сам выбор специалиста и зала. Вид приёма при этом подписан
   в каждой карточке словом — цвет на телефоне остаётся подсказкой, а не шифром */
@media (max-width: 900px) {
  .apt-legend { display: none; }
}

/* ── Раздел «Связь» на странице карточки приёма (I-07, вариант Б) ────
   План касаний: что система обещала сделать по этой записи и где она сейчас.
   Не лента сообщений — администратор накануне приёма спрашивает не «что было»,
   а «что человеку уже сказали и что ему ещё скажут», и в плане это видно одним
   движением глаза. Четыре касания стоят всегда на одном месте: «за сутки»
   ищется там же, где вчера, сколько бы сообщений ни было.

   В окне приёма всё это по-прежнему одна строка: там место дорогое,
   и окно не должно расти (слово Паши, 27.09.2026). */

/* фраза-итог: единственное, ради чего раздел открывают */
.sv-sum { padding: 2px var(--sp-5) 14px; font-size: 14px; line-height: 1.45; }
.sv-sum.is-bad { color: oklch(0.42 0.12 75); }

.plan { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  border-top: 1px solid var(--border); }
.plan-step { display: block; padding: 11px var(--sp-5) 13px;
  border-right: 1px solid var(--border); min-width: 0; }
/* последнее касание в ряду: между касаниями черта нужна, у края панели — нет.
   Считаем «последний» по соседям, а не по типу элемента: у касания без текста
   нет переключателя, и порядковые правила на смешанном списке врут */
.plan-step:not(:has(~ .plan-step)) { border-right: 0; }
.plan-name { display: block; font-size: 12.5px; color: var(--muted); }
.plan-state { display: block; margin-top: 2px; font-size: 13.5px;
  font-variant-numeric: tabular-nums; }
.plan-state.wait, .plan-state.none { color: var(--muted); }
.plan-state.bad { color: oklch(0.42 0.12 75); }
/* тонкая черта под касанием — то же, чем в отчётах показана доля шага воронки:
   состояние читается и боковым зрением, а не только словами */
.plan-tick { display: block; height: 3px; border-radius: 999px;
  background: var(--border); margin-top: 9px; }
.plan-tick.gone { background: var(--primary); }
.plan-tick.bad { background: oklch(0.42 0.12 75); }

/* Текст сообщения открывается отметкой, без JavaScript: у касания есть свой
   скрытый переключатель, а сам текст встаёт под планом во всю ширину —
   в колонке шириной в четверть его пришлось бы читать лесенкой. */
.plan-toggle { position: absolute; width: 1px; height: 1px; opacity: 0;
  pointer-events: none; }
label.plan-step { cursor: pointer; transition: background 140ms ease; }
label.plan-step:hover { background: var(--surface-sunken); }
.plan-toggle:checked + .plan-step { background: var(--surface-sunken); }
.plan-toggle:focus-visible + .plan-step { outline: 2px solid var(--primary);
  outline-offset: -2px; }
.plan-text { display: none; grid-column: 1 / -1; padding: 12px var(--sp-5) 14px;
  border-top: 1px solid var(--border); background: var(--surface-sunken);
  font-size: 13px; color: var(--muted); }
.plan-text .who { display: block; margin-bottom: 4px; font-size: 12.5px;
  color: var(--muted); }
.plan-text .body { display: block; max-width: 72ch; }
/* какой текст какому касанию — по порядку. Пар столько же, сколько касаний
   может быть у записи: подтверждение и до четырёх напоминаний */
#sv-t1:checked ~ #sv-x1, #sv-t2:checked ~ #sv-x2, #sv-t3:checked ~ #sv-x3,
#sv-t4:checked ~ #sv-x4, #sv-t5:checked ~ #sv-x5 { display: block; }

/* что случилось сверх плана: ответ человека, перенос, снятое отменой */
.sv-aside { border-top: 1px solid var(--border); padding: 10px 0 4px; }
.sv-aside-head { padding: 0 var(--sp-5) 4px; font-size: 12px; color: var(--muted); }
.sv-row { display: grid; grid-template-columns: 96px 1fr auto; gap: 4px 16px;
  align-items: baseline; padding: 5px var(--sp-5); font-size: 13.5px; }
.sv-when { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.sv-what { color: var(--ink); }
/* ответ человека — единственное здесь, что написано не нами */
.sv-row.is-answer .sv-what { font-weight: 600; }
.sv-state { color: var(--muted); text-align: right; }

.sv-foot { display: flex; gap: var(--sp-4); align-items: baseline; flex-wrap: wrap; }
.sv-foot a { color: var(--primary); text-decoration: none; }
.sv-foot a:hover { text-decoration: underline; }
.sv-foot-note { margin-left: auto; color: var(--muted); }

@media (max-width: 760px) {
  .plan { grid-template-columns: 1fr; }
  .plan-step { border-right: 0; border-bottom: 1px solid var(--border);
    padding: 9px var(--sp-5) 11px; }
  .plan-step:not(:has(~ .plan-step)) { border-bottom: 0; }
  .plan-tick { display: none; }
  .sv-row { grid-template-columns: 1fr auto; }
  .sv-when { grid-column: 1 / -1; order: -1; font-size: 12.5px; }
}

/* === Настройки → Автоматика: что уходит пациенту само (27.09.2026) ===========
   Экран читается как список сообщений, а не как форма: в каждой строке видно
   включено оно или нет, когда уходит и что в нём написано. Поэтому строки, а не
   сетка полей в два столбца: у сообщения есть текст, и текст — главное в строке. */
.auto-list { display: flex; flex-direction: column; }
.auto-row { display: grid; grid-template-columns: 1fr auto; gap: 4px var(--sp-4);
  align-items: center; padding: 12px 0; border-top: 1px solid var(--border); }
.auto-row:first-child { border-top: 0; padding-top: 2px; }
.auto-head { display: flex; align-items: center; gap: var(--sp-2); cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--ink); }
.auto-head input { width: 16px; height: 16px; }
.auto-when { display: flex; align-items: center; gap: var(--sp-2);
  justify-self: end; font-size: 13px; color: var(--muted); }
.auto-when input {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 7px 9px; width: 72px; text-align: right; outline: none;
  font-variant-numeric: tabular-nums; }
.auto-when input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.auto-when select {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 7px 9px; outline: none; max-width: 260px; }
.auto-when select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.auto-fixed { font-size: 13px; color: var(--muted); }
/* сам текст сообщения — то, ради чего экран и открывают */
.auto-text { grid-column: 1 / -1; margin: 2px 0 0; max-width: 72ch;
  font-size: 13.5px; line-height: 1.5; color: var(--ink); }
.auto-err { grid-column: 1 / -1; }
/* выключенное сообщение остаётся читаемым: его текст никуда не исчезает, он просто
   не уходит. Гасить до невидимости нельзя — руководитель включает обратно по тексту */
.auto-row.is-off .auto-title, .auto-row.is-off .auto-text { color: var(--muted); }
.auto-nosample { margin: var(--sp-3) 0 0; }
.auto-quiet { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  font-size: 14px; color: var(--ink); }
.auto-quiet select {
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 7px 9px; outline: none; font-variant-numeric: tabular-nums; }
.auto-quiet select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.auto-check { padding: 7px 0; font-size: 14px; }
.auto-alert { margin-bottom: var(--sp-3); padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--danger-tint); color: var(--danger); font-size: 13px; }

@media (max-width: 760px) {
  .auto-row { grid-template-columns: 1fr; }
  .auto-when { justify-self: start; }
}

/* ============================================================
   Время выбирается списком (P-10, 27.09.2026)
   ------------------------------------------------------------
   Часы перестали набираться минутами: в интервалах графика и в часах
   отсутствия стоит тот же список получасовок, что и в записи на приём.
   Своего вида у него нет — это обычное поле формы (`.field > select`),
   иначе одно и то же время выглядело бы в двух окнах по-разному.
   Здесь только ширина: список узкий («09:00» и не больше), поэтому пара
   делит место поровну и не разъезжается на узком экране. Дополняет блок
   «Интервалы дня» выше, свойства не пересекаются. */
.ival .field { flex: 1 1 0; min-width: 96px; }
.ival .field > select { width: 100%; box-sizing: border-box; }

@media (max-width: 760px) {
  /* На телефоне пара списков занимает строку целиком, а «убрать интервал»
     уходит под неё: лучше так, чем обрезанное время в самом списке. */
  .ival { flex-wrap: wrap; }
  .ival-drop { margin-left: auto; }
}

/* ============================================================
   Время списком: срок задачи и рабочий день студии (P-10, второй кусок)
   ------------------------------------------------------------
   Продолжение блока выше: тот же общий список получасовок встал в срок задачи
   и в часы рабочего дня студии и зала.

   Часы рабочего дня правки вида не потребовали — пара «с — до» устроена там
   так же, как в окне «Не работает» (`.field-pair`), а список внутри подписи
   растягивается сам.

   А вот ячейка срока («Срок» — день и час одной строкой) знала только поле
   с минутами: `.due-pair > input[type=time]`. Список приехал бы в неё голым
   `<select>` — другой рост, другой шрифт и другая рамка рядом с датой. Здесь
   он говорит тем же языком, что дата слева от него, и занимает ровно столько
   места, сколько занимает «11:30»: ширина в строке нужна дате, и обрезаться
   на середине года она не должна. */
.due-pair > select {
  flex: 0 0 auto; width: auto; min-width: 82px;
  font-family: inherit; font-size: 14px; color: var(--ink); background: var(--bg);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 9px 8px 9px 11px; outline: none; box-sizing: border-box; }
.due-pair > select:focus {
  border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.due-pair > select:disabled { background: var(--surface-sunken); color: var(--muted); }

@media (max-width: 760px) {
  /* На телефоне дате нужно всё, что есть: срок переносится на две строки,
     и час встаёт под датой целиком, а не сплющивается до трёх символов. */
  .due-pair { flex-wrap: wrap; }
  .due-pair > input[type="date"] { flex: 1 1 100%; }
  .due-pair > select { flex: 1 1 100%; width: 100%; }
}

/* ── P-16 · Неявки на консультацию на карточке сделки ──────────────────────
   «не пришёл 2 раза» — тёплым, а не красным: это сведения для решения
   менеджера (перезаписать ещё раз или закрыть), а не тревога. */
.tag.noshow { background: var(--warning-tint); color: oklch(0.45 0.11 65); }

/* ── P-14 · Задачи отдела ──────────────────────────────────────────────────
   Строка «закрыта … · закрыл(а) коллега вместо хозяина» в окне задачи. */
.task-closed-by { margin-bottom: var(--sp-3); font-size: 13px; color: var(--muted); }

/* Ошибка в деньгах — сразу при вводе (P-09, 27.09.2026) -------------------- */
/* Поле, в котором сейчас написана невозможная сумма: человек видит это в момент
   ввода, а не после нажатия. Рамка и подпись под полем, без всплывающих окон. */
.field.is-wrong input,
.field.is-wrong select { border-color: var(--danger); }

/* ── Меню прокручивается, низ сайдбара не теряется (P-21, 27.09.2026) ──
   Сайдбар — колонка ровно в высоту окна, и меню в ней росло свободно: `.nav`
   тянулся под своё содержимое и выталкивал вниз всё, что стоит под ним.
   На невысоком окне у руководителя (полное меню плюс раздел «Руководителю»
   плюс «Настройки») за край уезжали и подвал с именем, и плашка «Вы работаете
   как …» вместе с кнопкой «Вернуться к себе». Колесо мыши при этом ничего
   не двигало: прокручивать было нечему — `.app` просто обрезал лишнее.

   Плохо это не тем, что некрасиво: кнопка «Вернуться к себе» — единственный
   выход из работы под чужим именем. Потерять её значит продолжать работать
   чужими руками, не зная об этом.

   Поэтому: прокручивается **список пунктов**, а всё, что ниже, — не сжимается
   и не уезжает никогда. Предупреждение о чужой роли и подвал важнее любого
   пункта меню: до пункта можно докрутить, до выхода из чужой роли — нет. */

.nav {
  /* `min-height: 0` обязателен: без него flex-элемент не даёт себя сжать,
     и `overflow` не включается — блок по-прежнему растёт наружу */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* прокрутка меню не должна утягивать за собой страницу под ним */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
/* полоса прокрутки в меню тихая: она появляется редко и не должна спорить
   с самим списком */
.nav::-webkit-scrollbar { width: 6px; }
.nav::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
.nav::-webkit-scrollbar-track { background: transparent; }

/* низ сайдбара стоит на месте при любой высоте окна */
.sidebar-asif,
.sidebar-foot { flex-shrink: 0; }

/* На телефоне «высота окна» (100vh) — это высота без панелей браузера: нижняя
   панель Chrome/Safari лежит поверх страницы, и подвал с кружком смены сотрудника
   прятался под ней (Паша, 30.09.2026: «не вижу переключения на телефоне»).
   `dvh` — видимая высота, с вычетом панелей; старым браузерам остаётся `vh`. */
.app { grid-template-rows: 100dvh; }
.main { height: 100dvh; }

/* Узкое меню (60px): кружок и «Выйти» стояли в строку и не помещались — кружок
   смены сотрудника уезжал за левый край, а видно было только «→ Вы…» (Паша с
   телефона, 30.09.2026). Здесь они встают столбиком: кружок сверху, выход — значком. */
@media (max-width: 900px) {
  .sidebar-foot { flex-direction: column; gap: var(--sp-2); padding: var(--sp-2) 0; }
  .sidebar-exit-form { margin-left: 0; }
  .sidebar-exit span { display: none; }
}

/* ── Сообщение, которое ещё не ушло (эмуляция без шлюза, P-15) ───────
   Сообщения автоматики ложатся в переписку в момент постановки в очередь,
   и состояние у них честное: «ждёт отправки», пока канал не подключён.
   Выделено не цветом тревоги, а насыщенностью: это не поломка, а факт,
   мимо которого нельзя пройти, решив, что человек всё прочитал. */
.msg-wait { color: var(--ink); font-weight: 500; }

/* ── I-14: запланированное сообщение системы — в ленте сразу, но не как ушедшее ──
   Пунктирная рамка и приглушённый текст: видно, что человек его ещё не получил,
   без пояснительных надписей. Подпись вместо времени — «уйдёт 29.09 в 12:00». */
.msg.is-out.is-planned { background: transparent; border: 1px dashed var(--border-strong, var(--muted)); }
.msg.is-planned .msg-text { color: var(--muted); }

/* ── Проверочная учётка в списке «работать от лица» (P-21-бис, 27.09.2026) ──
   «Руководитель Проверочный» стоял в списке между Ксенией и Гульнур и глазом
   от них не отличался: Паша искал «test.head» и не нашёл, потому что список
   показывает имена, а не логины. Теперь у таких строк тихая подпись с самим
   логином — по нему их и ищут, — а стоят они в конце своей роли.

   Подпись именно тихая: это не тревога и не ошибка, а пометка «здесь можно
   нажимать смело». Красным она кричала бы на четырёх строках из одиннадцати. */

.menu-tag {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  background: var(--surface-sunken);
  border-radius: var(--r-sm);
  padding: 2px 6px;
  white-space: nowrap;
  flex: none;
}
.menu-item:hover .menu-tag { background: var(--surface); }

/* ── Что система напомнит дальше: одна тихая фраза под перепиской ────
   До 27.09.2026 здесь стоял список сроков на десять пунктов, слитых
   в серый абзац: «подтверждение в 07:00 · напоминание за час в 07:00 · …».
   Паша прочитал это как «придятину» — и был прав: переписка перестала
   быть перепиской и стала журналом.

   Теперь одна фраза и ясная граница: сообщения — пузырями справа,
   обещание системы — строкой по центру, без пузыря. Разницу между
   «уже написали» и «ещё напишем» видно, не читая. */
.chat-planned { align-self: center; max-width: 100%; margin: var(--sp-4) 0 var(--sp-2);
  padding-top: var(--sp-3); border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--muted); text-align: center; line-height: 1.5; }

/* Окно выбора «работать от лица» вмещает список целиком, пока хватает высоты:
   раньше оно упиралось в 62% экрана, а последней строкой стоял как раз
   проверочный руководитель — за нижним краем. Паша открыл список и не нашёл
   его вовсе (27.09.2026). Подпись «тест · логин» при этом обрезалась правым
   краем: окно было уже, чем строка с именем и пометкой. */
/* высота — вся, что есть, минус сам подвал и поля: жёсткий потолок в 640 точек
   обрезал список ровно на последней строке даже там, где экрана хватало */
.switch-pop { width: 280px; max-height: calc(100dvh - 96px); }
/* имя ужимается многоточием, пометка — никогда: по ней учётку и ищут */
.menu-item { min-width: 0; }
.menu-item > .menu-tag { flex: none; }
.menu-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ── Отмена платежа видна всегда (правка Паши, 28.09.2026) ──────────────
   Отмена стояла тихой подчёркнутой ссылкой серого цвета у правого края:
   формально она была на экране всегда, но читалась как подпись, а не как
   действие, — Паша смотрел кассу и говорил, что отмены нет вовсе. Это ровно
   та болезнь, с которой задача и началась: администратор не нашла возврат.

   Общее правило Паши: **важное действие видно всегда, а не по наведению
   и не вполсилы.** Поэтому отмена — обычная кнопка, как и остальные
   действия системы. Она не кричит красным: отмена — обычная работа стойки,
   а не тревога; красными в системе отмечены просрочка и отказ. */

.act-void { white-space: nowrap; }
/* столбец действия не растягивается под кнопку и не отнимает место у «за что» */
.tbl td:has(> .act-void) { width: 1%; padding-left: var(--sp-2); }

/* ── Работа под чужим именем видна сверху (28.09.2026) ──────────────────
   Пометка стояла в подвале меню — внизу слева, куда человек не смотрит,
   когда работает с таблицей справа. Паша полчаса искал в кассе кнопку
   отмены платежа: её там и не должно было быть, потому что он смотрел
   систему под именем администратора без права на возврат.

   Под чужим именем пропадают разделы и действия — это объяснение должно
   стоять там же, где человек ищет пропажу, то есть над рабочей областью.
   Полоса не красная: это не поломка, а режим работы; красным в системе
   отмечены просрочка и отказ. */

.asif-band {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px var(--sp-5);
  background: oklch(0.975 0.035 75);
  border-bottom: 1px solid oklch(0.9 0.06 75);
  color: oklch(0.36 0.07 75);
  font-size: 13px;
  flex: none;
}
.asif-band > .icon { color: oklch(0.55 0.13 75); flex: none; }
.asif-band b { font-weight: 600; }
.asif-band span { color: oklch(0.47 0.05 75); }
.asif-band form { margin-left: auto; flex: none; }
.asif-band button {
  padding: 5px 12px; border-radius: var(--r-sm);
  border: 1px solid oklch(0.85 0.07 75); background: var(--bg);
  color: oklch(0.36 0.07 75); font: inherit; font-size: 12.5px; font-weight: 600;
  cursor: pointer;
}
.asif-band button:hover { background: oklch(0.985 0.02 75); }
.asif-band button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* .main — колонка: полоса сверху, экран под ней занимает остальное */
.main { display: flex; flex-direction: column; min-height: 0; }
@media (max-width: 900px) {
  .asif-band { padding: 8px var(--sp-3); }
  .asif-band span { display: none; }
}

/* ── Счёт из записи: предоплата или вся стоимость (P-08, 28.09.2026) ───────────
   Два положения одним рядом, как переключатель: выбор виден сразу, без списка.
   На телефоне остаётся в одну строку — у менеджера это главный экран работы. */
.field.pay-kind { display: flex; flex-direction: row; gap: 0; padding: 3px; border: 1px solid var(--border-strong);
  border-radius: 10px; background: var(--surface-sunken); }
.pay-kind-opt { flex: 1 1 0; position: relative; display: flex; align-items: center;
  justify-content: center; min-height: 38px; padding: 0 var(--sp-2); border-radius: 7px;
  cursor: pointer; font-size: 14px; font-weight: 500; color: var(--muted);
  text-align: center; }
.pay-kind-opt input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.pay-kind-opt:has(input:checked) { background: var(--bg); color: var(--ink);
  box-shadow: 0 1px 2px oklch(0.24 0.015 235 / 0.12); }
.pay-kind-opt:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 1px; }
.modal-body > .money-sum:empty { display: none; }
.modal-body > .money-sum { margin-top: var(--sp-3); }

/* ============================================================
   Диалоги: переписка не растягивает страницу (Паша, 28.09.2026)
   Колонка переписки тянулась по высоте всех сообщений, страница становилась
   длинной, и после ответа поле ввода с последними сообщениями уезжали за край
   экрана — выглядело так, будто ответ «пропал в никуда». Теперь листается только
   лента сообщений, поле ввода стоит внизу всегда.
   ============================================================ */
.inbox { flex: 1; height: auto; min-height: 0; grid-template-rows: minmax(0, 1fr); }
.inbox-list, .inbox-chat { min-height: 0; }
.inbox-chat { overflow: hidden; }
.chat-body { min-height: 0; }

/* Галочки доставки как в WhatsApp (Паша, 28.09.2026) */
.ticks { display: inline-flex; vertical-align: -1px; margin-left: 3px; color: var(--muted); }
.ticks.is-read { color: oklch(0.62 0.15 240); }

/* ============================================================
   Связь · номера WhatsApp: подключение по QR и настройки номера (29.09.2026)
   ============================================================ */
.line-add { display: flex; gap: var(--sp-2); align-items: center; }
.line-add input { width: 260px; border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 5px 10px; font: inherit; font-size: 13px; }
.line-add input:focus, .line-edit input:focus, .line-edit textarea:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.line { border-top: 1px solid var(--border); padding: var(--sp-4) 0; scroll-margin-top: 80px; }
.line:first-of-type { border-top: 0; padding-top: 0; }
.line-main { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.line-who { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 180px; }
.line-who b { font-size: 14px; font-weight: 600; }
.line-who .muted-cell { font-size: 12.5px; font-variant-numeric: tabular-nums; }
.line-actions { display: flex; gap: var(--sp-2); align-items: center; }
.line-state { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 500;
  padding: 3px 10px; border-radius: 999px; background: var(--surface-sunken); color: var(--muted);
  white-space: nowrap; }
.line-state::before { content: ""; width: 7px; height: 7px; border-radius: 999px; background: currentColor; }
.line-state.is-on { background: var(--success-tint); color: var(--success); }
.line-state.is-qr, .line-state.is-wait { background: var(--warning-tint); color: oklch(0.48 0.11 75); }
.line-state.is-down { background: var(--danger-tint); color: var(--danger); }
.line-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-2) var(--sp-5);
  margin: var(--sp-3) 0 0; }
.line-facts div { display: flex; flex-direction: column; gap: 4px; }
.line-facts dt { font-size: 12px; color: var(--muted); }
.line-facts dd { margin: 0; font-size: 13px; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.line-qr { display: grid; grid-template-columns: 220px 1fr; gap: var(--sp-2) var(--sp-5); align-items: start;
  margin-top: var(--sp-4); padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); }
.line-qr img { grid-row: span 2; width: 220px; height: 220px; background: var(--bg); border-radius: var(--r-sm);
  border: 1px solid var(--border); }
.line-qr ol { margin: 0; padding-left: 18px; font-size: 13.5px; line-height: 1.7; }
.line-qr-note { margin: 0; font-size: 13px; font-weight: 500; }
.line-edit { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-4);
  padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); }
.line-field { display: flex; flex-direction: column; gap: 6px; border: 0; padding: 0; margin: 0; font-size: 13px; }
.line-field > span, .line-field legend { font-size: 12px; color: var(--muted); padding: 0; }
.line-field legend label { color: var(--ink); font-size: 13px; display: inline-flex; gap: 6px; align-items: center; }
.line-field input[type=text], .line-field textarea { border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 8px 10px; font: inherit; font-size: 13.5px; background: var(--bg); max-width: 520px; }
.line-field textarea:disabled { background: var(--surface-sunken); color: var(--muted); }
.line-people { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.line-person { display: inline-flex; gap: 6px; align-items: center; }
.line-edit-actions { display: flex; gap: var(--sp-2); }
@media (max-width: 700px) {
  .line-qr { grid-template-columns: 1fr; }
  .line-add input { width: 100%; }
  .line-add { width: 100%; }
}
.line-qr:has(img[hidden]) { grid-template-columns: 1fr; }
/* номер отключился — сообщения не приходят: самый заметный сигнал на экране */
.badge-danger { background: var(--danger-tint); color: var(--danger); padding: 3px 10px;
  border-radius: 999px; font-size: 12px; font-weight: 500; text-decoration: none; }
.badge-danger:hover { background: oklch(0.93 0.05 25); }
.line-qr-more, .line-code { grid-column: 2; display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; font-size: 12.5px; }
.line-code input { width: 170px; border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: 5px 9px; font: inherit; font-size: 13px; }
.line-code-out { font-size: 18px; letter-spacing: 0.12em; font-variant-numeric: tabular-nums; }
.line-code-help { grid-column: 2; margin: 0; font-size: 12.5px; }
@media (max-width: 700px) { .line-qr-more, .line-code, .line-code-help { grid-column: 1; } }

/* Диалоги: написать первым (29.09.2026) */
.new-talk { position: relative; }
.new-talk summary { list-style: none; cursor: pointer; }
.new-talk summary::-webkit-details-marker { display: none; }
.new-talk-form { position: absolute; right: 0; top: calc(100% + 6px); z-index: 20; width: 300px;
  display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4);
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: 0 8px 24px oklch(0.24 0.015 235 / 0.12); }
.new-talk-form label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); }
.new-talk-form input, .new-talk-form select { border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  padding: 8px 10px; font: inherit; font-size: 13.5px; color: var(--ink); background: var(--bg); }

/* Диалоги: кто это — фото из WhatsApp или инициалы (Паша, 29.09.2026) */
.ava { position: relative; width: 40px; height: 40px; border-radius: 999px; overflow: hidden;
  flex-shrink: 0; display: grid; place-items: center;
  background: var(--primary-tint-strong); color: var(--primary-hover); }
.ava b { font-size: 15px; font-weight: 600; }
.ava img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ava-lg { width: 44px; height: 44px; }
.inbox-list .dlg { display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 10px; row-gap: 2px; }
.inbox-list .dlg > .ava { grid-row: 1 / span 3; align-self: center; }
.inbox-list .dlg > :not(.ava) { grid-column: 2; }
.chat-head { justify-content: flex-start; }
.chat-head .chat-who { flex: 1; min-width: 0; }

/* Диалоги: файлы в переписке — скрепка, лоток до отправки, перетаскивание, пузыри (P-29, 29.09.2026) */
.chat-send[data-attach] { flex-direction: column; gap: var(--sp-2); }
.chat-send-row { display: flex; gap: var(--sp-2); align-items: stretch; }
.chat-send-row input[type=text] { flex: 1; min-width: 0; border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); padding: 10px 12px; font-family: inherit; font-size: 14px; outline: none; }
.chat-send-row input[type=text]:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-tint); }
.chat-clip { position: relative; cursor: pointer; gap: 6px; }
.chat-clip input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.chat-clip:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
.attach-tray { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.attach-tray[hidden] { display: none; }
.attach-chip { display: flex; align-items: center; gap: 10px; max-width: 280px;
  padding: 6px 6px 6px 6px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); animation: attach-in 180ms cubic-bezier(0.25, 1, 0.5, 1); }
.attach-thumb { flex: none; width: 44px; height: 44px; border-radius: var(--r-sm); object-fit: cover;
  display: grid; place-items: center; background: var(--primary-tint); color: var(--primary);
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em; }
.attach-info { display: flex; flex-direction: column; min-width: 0; }
.attach-name { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-size { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.attach-drop { flex: none; width: 28px; height: 28px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--muted); font-size: 18px; line-height: 1; cursor: pointer; }
.attach-drop:hover { background: var(--surface-sunken); color: var(--ink); }
.attach-drop:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.attach-err { margin: 0; font-size: 12.5px; color: var(--danger); }
.attach-err[hidden] { display: none; }
@keyframes attach-in { from { transform: translateY(4px); } to { transform: none; } }

/* перетаскивание: вся переписка становится местом, куда бросить файл */
.inbox-chat { position: relative; }
.drop-veil { position: absolute; inset: 8px; z-index: 5; display: grid; place-items: center;
  border: 2px dashed var(--primary); border-radius: var(--r-lg);
  background: oklch(0.965 0.02 195 / 0.94); pointer-events: none; }
.drop-veil[hidden] { display: none; }
.drop-veil-box { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--primary); text-align: center; }
.drop-veil-box .icon { width: 28px; height: 28px; }
.drop-veil-box b { font-size: 16px; font-weight: 600; color: var(--ink); }
.drop-veil-box span { font-size: 12.5px; color: var(--muted); }

/* файл в пузыре: фото картинкой, документ строкой */
.msg-photo { display: block; margin: -3px -6px 6px; border-radius: var(--r-sm); overflow: hidden; line-height: 0; }
.msg-photo img { display: block; max-width: 100%; width: 280px; max-height: 320px; object-fit: cover; background: var(--surface-sunken); }
.msg-photo:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.msg-audio { display: block; width: 260px; max-width: 100%; height: 36px; margin-bottom: 4px; }
.msg-video { display: block; width: 280px; max-width: 100%; border-radius: var(--r-sm); margin-bottom: 6px; }
.msg-doc { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 10px;
  align-items: center; min-width: 200px; max-width: 300px; padding: 6px 10px 6px 6px; margin-bottom: 6px;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
  color: var(--ink); text-decoration: none; }
a.msg-doc:hover { border-color: var(--primary); }
a.msg-doc:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.msg-doc-ext { grid-row: 1 / 3; width: 40px; height: 40px; border-radius: var(--r-sm); display: grid; place-items: center;
  background: var(--primary-tint); color: var(--primary); font-size: 11px; font-weight: 600; }
.msg-doc-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-doc-size { font-size: 11.5px; color: var(--muted); }
.msg-doc.is-missing .msg-doc-ext { background: var(--surface-sunken); color: var(--muted); }
.msg > .msg-doc:last-child, .msg > .msg-photo:last-child { margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) { .attach-chip { animation: none; } }

/* ============================================================
   Медкарта терапевта (P-41, 30.09.2026) — templates/medcard/
   Сводка сверху, лента осмотров, картотека снимков, динамика.
   ============================================================ */
:root {
  /* цвета отделов на графиках — проверенная палитра (различимы при
     нарушениях цветовосприятия); отдел держит свой цвет на обоих графиках */
  --mc-s1: #2a78d6;   /* шейный / шейно-грудная */
  --mc-s2: #eb6834;   /* грудной */
  --mc-s3: #1baf7a;   /* грудопоясничный */
  --mc-s4: #eda100;   /* поясничный */
}

.mc-summary { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr) minmax(0, 1.25fr);
  gap: var(--sp-5); align-items: start; padding: var(--sp-5); }
.mc-sum-name { font-size: 19px; font-weight: 600; letter-spacing: -0.015em; text-wrap: balance; }
.mc-sum-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: 2px; font-size: 13px; color: var(--muted); }
.mc-sum-dx { margin: var(--sp-3) 0 0; font-size: 14px; line-height: 1.5; max-width: 60ch; text-wrap: pretty; }
.mc-empty, .mc-measure-empty { color: var(--muted); }
.mc-sum-facts { margin: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.mc-sum-facts dt { font-size: 12px; color: var(--muted); }
.mc-sum-facts dd { margin: 1px 0 0; font-weight: 500; }
.mc-sum-measures { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4);
  padding-left: var(--sp-5); border-left: 1px solid var(--border); }
.mc-measure-title { font-size: 12px; color: var(--muted); }
.mc-measure-value { margin-top: 2px; font-variant-numeric: tabular-nums; }
.mc-measure-value b { font-size: 23px; font-weight: 600; letter-spacing: -0.02em; }
.mc-measure-value span { font-size: 13px; color: var(--muted); }
.mc-measure-when { font-size: 12px; color: var(--muted); }
.mc-measure-empty { margin-top: 4px; font-size: 13px; }
.mc-trend { margin-top: var(--sp-2); font-size: 12.5px; color: var(--muted); font-weight: 500; }
.mc-trend.is-better { color: oklch(0.45 0.12 150); }
.mc-trend.is-worse { color: var(--danger); }

/* лента осмотров: таблица с группой «сколиометрия», сдвиг к прошлому — под цифрой */
.mc-table-wrap { overflow-x: auto; margin: 0 calc(-1 * var(--sp-2)); padding: 0 var(--sp-2); }
.mc-exams { min-width: 640px; }
.mc-exams thead th { position: static; }
.mc-exams th.mc-th-group { text-align: center; border-bottom: 0; padding-bottom: 0; }
.mc-exams th.mc-th-sub { font-weight: 500; font-size: 11.5px; padding-top: 2px; }
.mc-exams .mc-num { text-align: right; }
.mc-exams td { vertical-align: top; }
.mc-exams td a { color: var(--ink); font-weight: 500; text-decoration: none; }
.mc-who { display: block; font-size: 12px; color: var(--muted); font-weight: 400; }
.mc-delta { display: block; font-size: 11.5px; color: var(--muted); }
.mc-delta.is-better { color: oklch(0.45 0.12 150); }
.mc-delta.is-worse { color: var(--danger); }
.mc-dash { color: var(--border-strong); }
.mc-exams tr.mc-note-row td { border-top: 0; padding-top: 0; color: var(--muted); font-size: 12.5px; }
.mc-exams tbody tr:has(+ .mc-note-row) td { border-bottom: 0; }
.mc-head-actions { display: inline-flex; gap: var(--sp-2); }

/* картотека снимков */
.mc-xrays { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: var(--sp-3); }
.mc-xray { display: grid; grid-template-columns: 88px 1fr; gap: var(--sp-3); padding: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-md); color: var(--ink); text-decoration: none;
  transition: border-color 150ms ease-out, background 150ms ease-out; }
.mc-xray:hover { border-color: var(--border-strong); background: var(--surface); }
.mc-xray img, .mc-xray .mc-file { width: 88px; height: 110px; object-fit: cover; border-radius: var(--r-sm);
  background: var(--surface-sunken); }
.mc-xray-text { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; font-size: 13px; min-width: 0; }
.mc-xray-note { font-size: 12px; color: var(--muted); line-height: 1.4; }
.mc-cobb { display: inline-flex; gap: 4px; align-items: baseline; font-size: 12.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.mc-cobb b { color: var(--ink); font-weight: 600; }
.mc-cobb.is-empty { font-style: normal; }
.mc-strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--sp-2); }
.mc-shot { display: flex; flex-direction: column; gap: 4px; color: var(--ink); text-decoration: none; font-size: 12px; line-height: 1.3; }
.mc-shot img, .mc-shot .mc-file { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--r-sm);
  background: var(--surface-sunken); border: 1px solid var(--border); transition: border-color 150ms ease-out; }
.mc-shot:hover img { border-color: var(--primary); }
.mc-shot span { color: var(--muted); }
.mc-file { display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600;
  color: var(--muted); }

/* динамика */
.mc-charts { display: grid; grid-template-columns: 1fr; gap: var(--sp-5); }
.mc-chart { margin: 0; }
.mc-chart figcaption { font-size: 13px; font-weight: 600; margin-bottom: var(--sp-2); }
.mc-chart svg { width: 100%; height: auto; display: block; overflow: visible; }
.mc-grid { stroke: var(--border); stroke-width: 1; }
.mc-axis { font-size: 11px; fill: var(--muted); font-variant-numeric: tabular-nums; }
.mc-series path { fill: none; stroke: var(--c); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.mc-series circle { fill: var(--c); stroke: var(--bg); stroke-width: 2; }
.mc-series circle:hover { r: 6; }
.mc-leader { stroke: var(--border-strong); stroke-width: 1; }
.mc-end { font-size: 11.5px; fill: var(--ink); font-variant-numeric: tabular-nums; }
.mc-legend { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  font-size: 12px; color: var(--muted); }
.mc-legend li { display: inline-flex; align-items: center; gap: 6px; }
.mc-legend li::before { content: ""; width: 14px; height: 2px; border-radius: 2px; background: var(--c); }

/* анамнез в правой колонке */
.mc-h3 { margin: var(--sp-4) 0 2px; font-size: 12px; font-weight: 600; color: var(--muted); }
.mc-para { margin: 0; font-size: 13px; line-height: 1.5; text-wrap: pretty; }
.mc-anamnesis .mc-para:first-of-type { margin-top: var(--sp-2); }
.mc-foot { margin: var(--sp-4) 0 0; font-size: 12px; color: var(--muted); }

/* формы медкарты */
.mc-form { max-width: 680px; }
.mc-form-who { font-size: 13px; color: var(--muted); margin-bottom: var(--sp-4); }
.mc-form-h { margin: var(--sp-5) 0 var(--sp-3); font-size: 14px; font-weight: 600; }
.mc-form-who + .mc-form-h, .form-error + .mc-form-h { margin-top: 0; }
.mc-pair { display: flex; gap: var(--sp-2); }
.mc-pair select:first-child { flex: 1; min-width: 0; }
.mc-pair select:last-child { width: 72px; }
.mc-pair select { font: inherit; padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg); }
.mc-checks, .mc-kind { border: 0; padding: 0; margin: 0; min-width: 0; }
.mc-checks legend, .mc-kind legend { font-weight: 500; font-size: 13px; margin-bottom: 5px; padding: 0; }
.mc-check-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.mc-chip { cursor: pointer; gap: 6px; }
.mc-chip input { margin: 0; accent-color: var(--primary); }
.mc-chip:has(input:checked) { background: var(--primary-tint); border-color: var(--primary-tint-strong); color: var(--primary-hover); }
.mc-chip:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--primary-tint); }
.mc-atr-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); }
.mc-atr-grid .field > input { width: 100%; box-sizing: border-box; font-variant-numeric: tabular-nums; }
.mc-prev { font-size: 12px; color: var(--muted); font-style: normal; font-variant-numeric: tabular-nums; }
.mc-gap { margin-top: var(--sp-5); }
.mc-danger-zone { max-width: 680px; }

/* загрузка */
.mc-kind { margin-bottom: var(--sp-4); }
.mc-drop { position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: var(--sp-6) var(--sp-4); margin-bottom: var(--sp-4); text-align: center;
  border: 1px dashed var(--border-strong); border-radius: var(--r-md); background: var(--surface); cursor: pointer;
  transition: border-color 150ms ease-out, background 150ms ease-out; }
.mc-drop:hover, .mc-drop:focus-within { border-color: var(--primary); background: var(--primary-tint); }
.mc-drop input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.mc-drop-main { font-size: 15px; font-weight: 600; color: var(--primary-hover); }
.mc-drop-sub { font-size: 13px; color: var(--ink); }
.mc-drop-limit { font-size: 12px; color: var(--muted); }
.mc-queue { list-style: none; margin: 0 0 var(--sp-4); padding: 0; border: 1px solid var(--border); border-radius: var(--r-md); }
.mc-queue li { display: flex; justify-content: space-between; gap: var(--sp-3); padding: 7px var(--sp-3); font-size: 13px;
  border-bottom: 1px solid var(--border); }
.mc-queue li:last-child { border-bottom: 0; }
.mc-q-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mc-q-state { flex: none; color: var(--muted); }
.mc-queue li.is-going .mc-q-state { color: var(--primary-hover); }
.mc-queue li.is-done .mc-q-state { color: oklch(0.45 0.12 150); }
.mc-queue li.is-failed .mc-q-state { color: var(--danger); white-space: normal; text-align: right; }

/* разбор загруженного */
.mc-sort-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.mc-sort-item { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
.mc-sort-img img, .mc-sort-img .mc-file { width: 150px; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--r-sm);
  background: var(--surface-sunken); border: 1px solid var(--border); }
.mc-sort-name { font-size: 12px; color: var(--muted); margin-bottom: var(--sp-3); overflow-wrap: anywhere; }
.mc-cobb-set { border: 0; padding: 0; margin: 0; min-width: 0; }
.mc-cobb-set legend { font-weight: 500; font-size: 13px; margin-bottom: 5px; padding: 0; }
.mc-sort .form-actions { position: sticky; bottom: 0; background: var(--bg); padding: var(--sp-3) 0; }

/* снимок крупно */
.mc-pic-page { max-width: 1180px; display: grid; grid-template-columns: minmax(0, 1fr) 340px; align-items: start; }
.mc-pic-page .mc-danger-zone { grid-column: 2; }
.mc-pic-view { display: flex; flex-direction: column; gap: var(--sp-2); grid-row: span 2; }
.mc-pic-view img { max-width: 100%; height: auto; max-height: calc(100dvh - 180px); object-fit: contain;
  border-radius: var(--r-md); background: var(--surface-sunken); display: block; margin: 0 auto; }
.mc-pic-tools { display: flex; gap: var(--sp-2); justify-content: center; }
.mc-pic-tools form { margin: 0; }
.mc-pic-cobbs { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-4); }
.mc-pic-form .form-grid { grid-template-columns: 1fr; }
.mc-pic-form .form-grid .field-wide { grid-column: auto; }
.mc-pic-form .mc-atr-grid { grid-template-columns: 1fr 1fr; }
.mc-pdf { display: inline-flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--ink); }
.mc-pdf .mc-file { width: 48px; height: 60px; background: var(--surface-sunken); border-radius: var(--r-sm); }

/* было — стало */
.mc-compare-page { max-width: 1280px; }
.mc-compare-pick .fb-sel { max-width: 280px; }
.mc-vs { color: var(--muted); }
.mc-compare { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
.mc-compare-side { margin: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.mc-compare-side img { width: 100%; height: calc(100dvh - 220px); min-height: 280px; object-fit: contain;
  background: var(--surface-sunken); border-radius: var(--r-md); display: block; }
.mc-compare-side figcaption { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); font-size: 13px; align-items: baseline; }

/* кто видит медкарты */
.mc-access { max-width: 860px; }
.mc-act { text-align: right; }
.mc-act form { margin: 0; }
.mc-grant { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center; margin-top: var(--sp-4); }
.mc-grant .fb-sel { max-width: 340px; padding: 6px 10px; font-size: 13px; }
.mc-xray-line { font-weight: 500; }

@media (max-width: 900px) {
  .mc-summary { grid-template-columns: 1fr; gap: var(--sp-4); padding: var(--sp-4); }
  .mc-sum-facts { flex-direction: row; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); }
  .mc-sum-measures { padding-left: 0; border-left: 0; padding-top: var(--sp-4); border-top: 1px solid var(--border); }
  .mc-pic-page { grid-template-columns: 1fr; }
  .mc-pic-page .mc-danger-zone { grid-column: auto; }
  .mc-pic-view { grid-row: auto; }
}
@media (max-width: 600px) {
  .mc-atr-grid { grid-template-columns: 1fr 1fr; }
  .mc-sort-item { grid-template-columns: 96px minmax(0, 1fr); gap: var(--sp-3); }
  .mc-sort-img img, .mc-sort-img .mc-file { width: 96px; }
  .mc-compare { grid-template-columns: 1fr; }
  .mc-compare-side img { height: auto; max-height: 70dvh; }
  .mc-sum-measures { grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
}
@media (prefers-reduced-motion: reduce) {
  .mc-xray, .mc-shot img, .mc-drop { transition: none; }
}
/* медкарта: подпись к заголовку панели стоит у заголовка, действия — справа */
.mc-page .panel-head > h2 + .panel-note { margin-right: auto; }
/* восемь поз у сетки — две ровные строки по четыре, на широком экране одна строка */
.mc-page .mc-strip { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.mc-page #pictures { container-type: inline-size; }
@container (min-width: 480px) {
  .mc-page .mc-strip { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 6px; }
  .mc-page .mc-shot span { font-size: 11px; }
}
.mc-pic-page { grid-template-rows: auto 1fr; }
.mc-xray-line a { color: var(--primary); text-decoration: none; font-weight: 400; }
.mc-xray-line a:hover { text-decoration: underline; }
.mc-denied { max-width: 560px; }
.mc-denied h1 { margin: 0 0 var(--sp-2); font-size: 19px; font-weight: 600; }
.mc-denied p { margin: 0 0 var(--sp-4); line-height: 1.55; text-wrap: pretty; }
.mc-denied-xray { color: var(--muted); }
/* верхняя панель карточки с вкладками «Карточка / Медкарта» на телефоне:
   вкладки важнее названия (имя человека и так крупно на экране), второстепенная
   кнопка уходит — она же есть в разделе «Снимки» */
@media (max-width: 600px) {
  .mc-top { gap: var(--sp-2); padding: 0 var(--sp-3); overflow-x: auto; }
  .mc-top .page-title, .mc-top .mc-top-extra { display: none; }
  .mc-top .tabs { margin-left: 0; }
  .mc-page .panel-head > .panel-note { display: none; }
}
@media (max-width: 600px) { .mc-top .btn-back { max-width: 44vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-shrink: 1; } }

/* ── Медкарта: результат для родителя и контрольный замер (P-41, ответы Гульнур) ── */
.mc-result-page { max-width: 920px; }
.mc-result { background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-6) var(--sp-6) var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-6); }
.mc-result-brand { font-size: 12px; color: var(--primary-hover); font-weight: 600; }
.mc-result-head h1 { margin: var(--sp-2) 0 var(--sp-1); font-size: 28px; font-weight: 600; letter-spacing: -0.02em; }
.mc-result-who { margin: 0; font-size: 17px; font-weight: 500; }
.mc-result-dates { margin: var(--sp-1) 0 0; color: var(--muted); font-size: 14px; }
.mc-result-dates b { color: var(--ink); font-weight: 500; }
.mc-result-block h2 { margin: 0; font-size: 19px; font-weight: 600; }
.mc-result-hint { margin: 2px 0 var(--sp-3); color: var(--muted); font-size: 14px; }
.mc-rrows { display: flex; flex-direction: column; }
.mc-rrow { display: grid; grid-template-columns: minmax(0, 1fr) auto 190px; gap: var(--sp-4); align-items: center;
  padding: var(--sp-3) 0; border-top: 1px solid var(--border); }
.mc-rlabel { font-size: 15px; }
.mc-rvals { display: flex; align-items: baseline; gap: var(--sp-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mc-rwas { font-size: 17px; color: var(--muted); }
.mc-rarrow { color: var(--muted); }
.mc-rnow { font-size: 23px; font-weight: 600; }
.mc-rword { font-size: 15px; font-weight: 600; text-align: right; }
.mc-rword.is-better { color: oklch(0.45 0.12 150); }
.mc-rword.is-worse { color: var(--danger); }
.mc-rword.is-same { color: var(--muted); font-weight: 500; }
.mc-pairs { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr)); gap: var(--sp-5); }
.mc-ppair { margin: 0; break-inside: avoid; display: block; }
.mc-ppair figcaption { font-size: 15px; font-weight: 500; margin-bottom: var(--sp-2); }
.mc-pair-imgs { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
.mc-pair-imgs img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--r-sm);
  background: var(--surface-sunken); display: block; }
.mc-pair-imgs span { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); text-align: center; }
.mc-result-foot { font-size: 13px; color: var(--muted); border-top: 1px solid var(--border); padding-top: var(--sp-3); }
.mc-control-late { color: var(--danger); font-weight: 600; }
.mc-control-note { display: block; font-size: 12px; color: var(--muted); font-weight: 400; }
.mc-sum-actions { grid-column: 1 / -1; display: flex; flex-wrap: wrap; gap: var(--sp-2); padding-top: var(--sp-3);
  border-top: 1px solid var(--border); }
@media (max-width: 600px) {
  .mc-result { padding: var(--sp-4); gap: var(--sp-5); }
  .mc-result-head h1 { font-size: 23px; }
  .mc-rrow { grid-template-columns: 1fr auto; }
  .mc-rword { grid-column: 1 / -1; text-align: left; }
}
@media print {
  @page { margin: 14mm; }
  body:has(.mc-result) .sidebar, body:has(.mc-result) .mc-noprint { display: none !important; }
  body:has(.mc-result), body:has(.mc-result) .app, body:has(.mc-result) .main,
  body:has(.mc-result) .screen-scroll { display: block !important; height: auto !important;
    overflow: visible !important; background: #fff !important; }
  body:has(.mc-result) .screen-pad { padding: 0; max-width: none; }
  .mc-result { border: 0; padding: 0; }
  .mc-result-block { break-inside: avoid-page; }
  .mc-pairs { grid-template-columns: 1fr 1fr; }
}
.panel-note a { color: var(--primary); text-decoration: none; }
.panel-note a:hover { text-decoration: underline; }

/* Доработки: разделы группы «Аудит перед запуском» — заголовок как у панели,
   счётчик открытого рядом серым: видно, сколько блокеров ещё держат запуск. */
.fbk-group { margin: var(--sp-5) 0 var(--sp-3); font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.fbk-group:first-of-type { margin-top: 0; }
.fbk-group span { margin-left: var(--sp-2); font-size: 13px; font-weight: 400; color: var(--muted); }
.fbk-rating { font-variant-numeric: tabular-nums; }
/* Доработки на телефоне: вкладок девять — полоса листается пальцем, а не уезжает
   за край; кнопки важности и статуса переносятся строкой ниже (тестер, 30.09.2026) */
.fbk-topbar .funnel-tabs { min-width: 0; overflow-x: auto; scrollbar-width: none; }
.fbk-topbar .funnel-tabs::-webkit-scrollbar { display: none; }
.fbk-knob { flex-wrap: wrap; }
.fbk-why { max-width: 72ch; }
/* кнопка возврата на страницах отказа — на месте «Назад», но с постоянным адресом (P-41) */
.topbar .btn.mc-back { order: 0; }
/* шапка страниц медкарты и отказов на телефоне: название сжимается многоточием,
   а не вылезает за правый край (P-41, находка тестировщика на 390px) */
@media (max-width: 600px) {
  .mc-bar { gap: var(--sp-2); padding: 0 var(--sp-3); min-width: 0; }
  .mc-bar .page-title { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }
  .mc-bar .mc-back { flex: 0 1 auto; max-width: 45vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ── Связь · номера WhatsApp: кнопки переносятся, а не уезжают за край телефона (30.09.2026) ── */
.line-actions { flex-wrap: wrap; }
.line-actions form { margin: 0; }
@media (max-width: 700px) {
  /* заголовок и поле названия не делят одну строку: поле сжималось в пустой квадрат */
  .lines .panel-head { flex-wrap: wrap; }
  .line-add input { flex: 1; min-width: 0; }
}

/* ── Телефон 390px: шапка и карточки не шире экрана (P-41, независимый тестер 30.09) ──
   На узком экране шапка не помещалась: кнопка «назад», название, вкладки и действия
   стояли в ряд без права сжаться, и вся рабочая область уезжала вбок. Правило общее
   для всех экранов: название и «назад» сжимаются многоточием, поиск — до поля,
   действия и вкладки держат размер, но становятся компактнее. */
@media (max-width: 600px) {
  .topbar { gap: var(--sp-2); padding: 0 var(--sp-3); min-width: 0; }
  .topbar .page-title { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
  .topbar .btn-back, .topbar .mc-back { flex: 0 1 auto; min-width: 0; max-width: 34vw;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
  .topbar .topbar-spacer { flex: 1 1 0; min-width: 0; }
  .topbar .btn:not(.btn-back):not(.mc-back) { flex: none; padding: 6px 10px; font-size: 12.5px; }
  .topbar .search { flex: 1 1 60px; min-width: 0; }
  .topbar .tabs { margin-left: 0; flex: none; }
  .topbar .tabs .tab { padding: 5px 8px; font-size: 13px; }
  .pcard-actions { flex-wrap: wrap; }
  .pcard-head { min-width: 0; }
  .panel-head { flex-wrap: wrap; }
  .task-row { grid-template-columns: 1fr; gap: var(--sp-1); padding: var(--sp-3); }
  .task-who { grid-column: auto; }
}
@media (max-width: 600px) {
  /* курс в карточке: название, полоса и состояние — столбиком, а не в ряд шире экрана */
  .course-row { flex-wrap: wrap; gap: var(--sp-2); }
  .course-row .progress { width: 100%; }
  .course-state { min-width: 0; text-align: left; }
  /* шапка с вкладками «Карточка / Медкарта»: в первой строке «назад» и действие,
     вкладки — второй строкой; в одну строку на 390px они не помещаются */
  .topbar.mc-top { height: auto; min-height: 57px; flex-wrap: wrap; padding: var(--sp-2) var(--sp-3); row-gap: var(--sp-2); }
  .topbar.mc-top .tabs { order: 10; width: 100%; }
  .topbar.mc-top .mc-back, .topbar.mc-top .btn-back { max-width: 55vw; }
}
@media (max-width: 600px) {
  .mc-head-actions { flex-wrap: wrap; justify-content: flex-end; }
}
@media (max-width: 600px) {
  /* «назад» короче своего предела не сжимается — сжимается название экрана («← Гла…» не читается) */
  .topbar .btn-back, .topbar .mc-back { flex: 0 0 auto; }
}
@media (max-width: 600px) {
  /* личный счёт пациента у администратора: сумма и кнопки переносом, а не шире карточки */
  .account-strip { flex-wrap: wrap; }
}

/* ── Диалоги · вкладки номеров: отключённый и «только смотрим» подписаны прямо на вкладке (30.09.2026) ── */
.funnel-tab .tab-note { color: var(--muted); font-weight: 400; }

/* ── Тестовая копия (P-33): жёлтая полоса сверху и что ждёт переноса на рабочую (01.10.2026) ──
   Полоса занимает свою высоту, а рабочая область ужимается на неё же: иначе у экрана
   на всю высоту окна появлялась бы вторая прокрутка. */
body.is-sandbox { --sandbox-h: 36px; }
body.is-sandbox .app { grid-template-rows: calc(100dvh - var(--sandbox-h)); }
body.is-sandbox .main { height: calc(100dvh - var(--sandbox-h)); }
body.is-sandbox .login-wrap { min-height: calc(100dvh - var(--sandbox-h)); }
.sandbox-bar {
  position: relative; z-index: 30;
  display: flex; align-items: center; gap: var(--sp-3);
  height: var(--sandbox-h); padding: 0 var(--sp-4);
  background: oklch(0.88 0.12 85); color: oklch(0.30 0.07 70);
  border-bottom: 1px solid oklch(0.80 0.12 80);
  font-size: 13px; white-space: nowrap;
}
.sandbox-name { font-weight: 700; letter-spacing: 0.01em; }
.sandbox-note { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.sandbox-clean { margin-left: auto; }
.sandbox-pending { margin-left: auto; position: relative; }
.sandbox-pending summary {
  cursor: pointer; list-style: none; padding: 3px 10px; border-radius: 999px;
  background: oklch(0.96 0.05 85); color: inherit;
}
.sandbox-pending summary::-webkit-details-marker { display: none; }
.sandbox-pending summary::after { content: " ▾"; }
.sandbox-pending[open] summary::after { content: " ▴"; }
.sandbox-pending summary:focus-visible { outline: 2px solid oklch(0.30 0.07 70); outline-offset: 2px; }
.sandbox-list {
  position: absolute; right: 0; top: calc(100% + 6px);
  width: min(440px, calc(100vw - 32px)); max-height: 60vh; overflow: auto;
  margin: 0; padding: var(--sp-2) 0; list-style: none;
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  box-shadow: 0 8px 24px oklch(0.24 0.015 235 / 0.14);
  white-space: normal;
}
.sandbox-list li { padding: 6px var(--sp-3); line-height: 1.4; }
.sandbox-list a { display: block; margin: -6px calc(-1 * var(--sp-3)); padding: 6px var(--sp-3);
  color: inherit; text-decoration: none; }
.sandbox-list a:hover { background: var(--surface-sunken); }
.sandbox-loose { color: var(--muted); font-size: 12px; }
.sandbox-list li + li { border-top: 1px solid var(--border); }
.sandbox-link { color: inherit; font-weight: 600; text-decoration: none; }
.sandbox-link:hover { text-decoration: underline; }
.sandbox-short { display: none; }
@media (max-width: 760px) {
  .sandbox-bar { gap: var(--sp-2); padding: 0 var(--sp-3); }
  .sandbox-note, .sandbox-long { display: none; }
  .sandbox-short { display: inline; }
  /* на телефоне кнопка списка стоит посередине полосы: список от её края уходил за
     левый край экрана — ставим его на всю ширину под полосой */
  .sandbox-pending { position: static; }
  .sandbox-list { position: fixed; left: var(--sp-3); right: var(--sp-3); width: auto;
    top: calc(var(--sandbox-h) + 6px); }
}

/* ── Деньги · подтверждение проведённого счёта (P-66) ───────────────────────
   Строка над списком счетов, а не всплывашка: не гаснет сама */
.notice-done { margin-bottom: var(--sp-4); border-color: oklch(0.86 0.07 160);
  background: oklch(0.975 0.025 160); }
.notice-done .icon { color: var(--success); }

/* ── Журнал правок (01.10.2026): таблица листается вбок внутри панели, страница — нет ── */
.jrn-wrap { overflow-x: auto; }
.jrn-wrap .tbl { min-width: 520px; }
.jrn-wrap + .fbk-group { margin-top: var(--sp-5); }
