/* Оформление окна. Пока каркас: вход и заглушка экрана переписки. */
:root {
  --fon: #f5f6f8;
  --karta: #ffffff;
  --tekst: #1c1f23;
  --tihiy: #6b7280;
  --gran: #d8dbe0;
  --glavniy: #1f7a4d;
  color-scheme: light;

  /* Палитра стадий и ярлыков (задача 8): восемь имён — ТЕ ЖЕ, что заданы
     кодом на сервере (COLORS, app/src/api/stages.ts). Разойдись имена — цвет,
     о котором не знает окно, нарисуется никак, и человек решит, что цвет не
     сохранился; тест (client_settings_statuses_test.ts) сличает оба списка,
     тем же приёмом, что importmap_test.ts сличает версии библиотек. Значения
     выбраны так, чтобы тёмный текст (--tekst) оставался читаемым на каждом —
     палитра существует именно затем, чтобы никто не выбрал жёлтый на белом. */
  --cvet-slate: #cbd5e1;
  --cvet-sky: #7dd3fc;
  --cvet-green: #86efac;
  --cvet-amber: #fcd34d;
  --cvet-red: #fca5a5;
  --cvet-violet: #c4b5fd;
  --cvet-teal: #5eead4;
  --cvet-pink: #f9a8d4;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.45 system-ui, "Segoe UI", Roboto, sans-serif;
  color: var(--tekst);
  background: var(--fon);
}

.waiting { padding: 24px; color: var(--tihiy); }

.login {
  max-width: 320px;
  margin: 12vh auto;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--karta);
  border: 1px solid var(--gran);
  border-radius: 10px;
}

.login h1 { margin: 0 0 4px; font-size: 20px; }

.login label { display: flex; flex-direction: column; gap: 4px; color: var(--tihiy); }

.login input {
  padding: 9px 10px;
  font-size: 16px;
  color: var(--tekst);
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.login button {
  padding: 10px;
  font-size: 15px;
  color: #fff;
  background: var(--glavniy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.login button[disabled] { opacity: .6; cursor: default; }

.login button.link {
  padding: 0;
  color: var(--tihiy);
  background: none;
  text-decoration: underline;
}

.note { margin: 0; color: var(--tihiy); }

/* Корень окна после входа (задача 4): столбец высотой во весь экран, где
   верхней строкой — переключатель места (когда он вообще есть — см.
   .place-bar), а под ним — то самое место, переписка или настройки. Высоту
   100vh теперь держит этот корень, а не .chat-shell сама по себе: два места
   в одном окне не могут оба претендовать на весь экран порознь. */
.app-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  /* На телефоне 100vh — высота БЕЗ панели адреса и клавиатуры, и нижняя
     строка окна (поле ответа) уезжала под них. dvh — видимая сейчас высота;
     браузер без dvh возьмёт строку выше. */
  height: 100dvh;
}

.place-bar {
  flex: none;
  display: flex;
  justify-content: flex-end;
  padding: 6px 12px;
  border-bottom: 1px solid var(--gran);
  background: var(--karta);
}

.place-switch {
  padding: 6px 12px;
  font-size: 13px;
  color: var(--glavniy);
  background: none;
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  cursor: pointer;
}

/* Окно переписки: полоса о потерянной связи сверху (когда есть), под ней —
   рабочая часть. Столбец, а не строка: полоса обязана занимать свою высоту, а
   не накрывать собой имя оператора и вкладки — проверено глазами, накрывала.
   Высоту не задаёт сама (было 100vh до задачи 4) — теперь .chat-shell это
   второй ряд .app-shell и получает то, что осталось после .place-bar. */
.chat-shell {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.chat-screen {
  display: flex;
  /* Высоту берём остатком от .chat-shell, а не 100vh: иначе полоса о
     потерянной связи выталкивала бы нижний край окна за экран. */
  flex: 1;
  min-height: 0;
}

.sidebar {
  width: 320px;
  flex: none;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--gran);
  background: var(--karta);
}

.sidebar header {
  padding: 12px 16px;
  font-weight: 600;
  border-bottom: 1px solid var(--gran);
}

.conversation {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.dialog-list { display: flex; flex-direction: column; min-height: 0; flex: 1; }

.dialog-tabs { display: flex; border-bottom: 1px solid var(--gran); }

.dialog-tabs button {
  flex: 1;
  padding: 10px 6px;
  font-size: 13px;
  color: var(--tihiy);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
}

.dialog-tabs button.active {
  color: var(--tekst);
  border-bottom-color: var(--glavniy);
  font-weight: 600;
}

.dialog-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
}

.dialog-row {
  padding: 10px 16px;
  border-bottom: 1px solid var(--gran);
  cursor: pointer;
}

.dialog-row.selected { background: var(--fon); }
.dialog-row.needs-reply .dialog-name { font-weight: 600; }

.dialog-row-top,
.dialog-row-bottom {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.dialog-waited { color: var(--glavniy); font-size: 13px; }

.dialog-row-bottom { margin-top: 2px; font-size: 13px; color: var(--tihiy); }

.dialog-unanswered {
  min-width: 18px;
  padding: 0 5px;
  text-align: center;
  color: #fff;
  background: var(--glavniy);
  border-radius: 9px;
  font-size: 12px;
}

/* Стадия и ярлыки в строке списка (задача 9) — кружком цвета И ИМЕНЕМ
   (принятое решение 3 брифа): строка ниже .dialog-row-bottom, а не внутри
   неё, чтобы не тесниться с именем собеседника и временем ожидания — они
   здесь главное, стадия и ярлыки вспомогательны. Кружок использует те же
   .cvet-dot переменные, что и раздел «Статусы» (style.css выше), второй
   палитры не заводит. */
.dialog-row-status {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
  font-size: 12px;
  color: var(--tihiy);
}

.dialog-row-stage, .dialog-row-label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
}

.message-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-height: 0;
  padding: 16px;
  overflow-y: auto;
}

.message-list-empty { margin: auto; color: var(--tihiy); }

.load-older {
  align-self: center;
  /* margin: 0 — не косметика. Надпись «Загружаем…» это <p>, у которого от
     браузера свои отступы сверху и снизу, а кнопка — <button> без них. Пока
     отступы были разные, замена кнопки на надпись меняла высоту ленты НАД
     тем, что читает оператор, и его место уезжало на два десятка точек в
     момент нажатия «загрузить ещё» — замерено живьём (задача 13). Одинаковая
     коробка у обоих состояний убирает смещение в источнике, не поправкой
     прокрутки задним числом. */
  margin: 0;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--tihiy);
  background: var(--karta);
  border: 1px solid var(--gran);
  border-radius: 14px;
  cursor: pointer;
}

/* Рамки нет, но её место остаётся за прозрачной рамкой той же толщины —
   иначе коробка снова станет на две точки ниже кнопки. */
.load-older.loading {
  border-color: transparent;
  background: none;
  cursor: default;
}

.msg {
  max-width: 60%;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--karta);
  border: 1px solid var(--gran);
}

.msg.in { align-self: flex-start; }

.msg.out {
  align-self: flex-end;
  background: #eaf5ee;
  border-color: #cfe8d8;
}

.msg-text { margin: 0; white-space: pre-wrap; }

/* Статус своего сообщения (очередь исходящих). Отправленное — тихо, как
   галочка; в очереди — заметно, но спокойно; отложенное и не отправленное —
   тоном беды, с причиной и кнопкой: это ждёт решения оператора. */
.msg-status { margin-top: 4px; font-size: 12px; color: var(--tihiy); }
.msg-status-note { margin: 2px 0 0; white-space: pre-wrap; }
.msg-status.held { color: #8a5300; }
.msg-status.failed { color: #b3261e; }
.msg-retry {
  margin-top: 4px;
  font: inherit;
  padding: 2px 10px;
  border: 1px solid currentColor;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.msg-image { display: block; max-width: 100%; max-height: 240px; border-radius: 6px; }

.msg-attachment-gone { color: var(--tihiy); font-style: italic; }
.msg-attachment-gone p { margin: 0; }

/* Предпросмотр без полного файла: показан, но приглушён — это не готовая
   картинка, которую можно открыть, а всё, что от неё осталось. Подпись рядом
   говорит это словами (attachmentNote). */
.msg-image.partial { margin-bottom: 4px; opacity: 0.7; }

.msg-file { color: var(--glavniy); }

.composer {
  flex: none;
  padding: 12px 16px;
  border-top: 1px solid var(--gran);
  background: var(--karta);
}

.composer-error { color: #b3261e; margin: 0 0 8px; }

/*
 * Слова вместо поля ответа клиенту (находка 2 итогового ревью). Занимают то же
 * место и с той же рамкой, что и сам composer: иначе низ переписки на смене
 * диалога прыгал бы, а объяснение читалось бы как случайный текст в ленте, а
 * не как то, что стоит НА МЕСТЕ поля ввода.
 */
.composer-closed {
  flex: none;
  padding: 12px 16px;
  border-top: 1px solid var(--gran);
  background: var(--karta);
}

.composer-file {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  color: var(--tihiy);
  font-size: 13px;
}

.composer-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.composer-attach { flex: none; }

.composer-text {
  flex: 1;
  min-height: 38px;
  max-height: 140px;
  padding: 9px 10px;
  font: inherit;
  color: var(--tekst);
  border: 1px solid var(--gran);
  border-radius: 6px;
  resize: vertical;
}

.composer-send {
  flex: none;
  padding: 10px 16px;
  font-size: 15px;
  color: #fff;
  background: var(--glavniy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.composer-send:disabled { background: var(--gran); cursor: default; }

.dialog-header {
  flex: none;
  padding: 10px 16px;
  border-bottom: 1px solid var(--gran);
  background: var(--karta);
}

.dialog-header-row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.dialog-header-name { font-weight: 600; }

.dialog-header-holder { flex: 1; color: var(--tihiy); font-size: 13px; }

.dialog-assign {
  flex: none;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--glavniy);
  background: var(--karta);
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  cursor: pointer;
}

.dialog-assign:disabled { color: var(--tihiy); border-color: var(--gran); cursor: default; }

.dialog-header-error { margin: 8px 0 0; color: #b3261e; }
/* Отказ загрузки переписки — над лентой, тем же красным, что и отказ заголовка. */
.messages-error { margin: 8px 12px 0; color: #b3261e; }

.dialog-back {
  flex: none;
  padding: 6px 10px;
  font-size: 13px;
  color: var(--tihiy);
  background: none;
  border: 0;
  cursor: pointer;
  /* На широком экране список и переписка видны рядом, и уходить «назад»
     некуда: кнопка появляется только в узком виде (см. @media ниже). */
  display: none;
}

.sidebar-note { padding: 16px; }

/* Полоса про канал НЕ В ПОРЯДКЕ — над списком диалогов, а не вместо него:
   список остаётся настоящим и рабочим (обсуждение с коллегами доступно и
   при phone_unavailable), и надпись про канал стирать его не должна (задача
   3 плана «установка, которая встаёт сама…»). Тем же мягким тоном, что и
   .refs-error ниже, а не красным .stream-down: это не отказ связи самого
   окна, а факт о состоянии канала, который уже назван словами — не поломка
   окна, а поломка (или ожидаемое состояние) установки. */
.channel-status-note {
  margin: 0;
  padding: 10px 16px;
  color: #8a5300;
  background: #fff4e5;
  border-bottom: 1px solid #f5d9ac;
}

/* Узкий экран (телефон): список и переписка показываются ПО ОЧЕРЕДИ —
   решение по окну, раздел 2. До этой правки боковая панель оставалась
   шириной в 320 точек и при ширине окна 375 на переписку оставалось около
   55 — окном нельзя было пользоваться вовсе. Порог 720 точек: это ширина,
   ниже которой две панели рядом перестают быть двумя панелями. */
@media (max-width: 720px) {
  .sidebar { width: 100%; border-right: 0; }
  .chat-screen.dialog-open .sidebar { display: none; }
  .chat-screen:not(.dialog-open) .conversation { display: none; }
  .dialog-back { display: inline-block; }
  .dialog-header-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Поле ввода на узком экране: строка переносится, поле занимает всю
     ширину, кнопка отправки остаётся доступной, а не уезжает за край. */
  .composer { padding: 8px 10px; }
  .composer-row { flex-wrap: wrap; align-items: center; }
  /* Поле — первой строкой (order), выбор файла и «Отправить» — второй, рядом.
     Без order они встают тремя строками и съедают треть экрана телефона. */
  .composer-text { order: -1; flex: 1 1 100%; min-width: 0; }
  .composer-attach { flex: 1 1 auto; min-width: 0; }
  .composer-send { flex: 0 0 auto; margin-left: auto; }
}

/* Полоса о потерянной связи с сервером — первой строкой .chat-shell, над
   всем окном: она нужна и тому, кто смотрит на список, и тому, кто читает
   диалог, а на узком экране из этих двух половин видна ровно одна. */
.stream-down {
  flex: none;
  margin: 0;
  padding: 8px 12px;
  text-align: center;
  background: #fdecea;
  color: #b3261e;
  border-bottom: 1px solid #f2b8b5;
}

/* Отказ экранных справочников (стадии, ярлыки, состояние блоков) — тем же
   местом и той же формой, что и полоса о потерянной связи выше: он тоже про
   окно целиком, а не про открытый диалог, и виден ещё до того, как диалог
   выбран (находка 4 итогового ревью). Цвет мягче красного: справочник не
   прочитан — это не поломка связи, работать в окне можно, но подсказки
   ярлыков и выбор стадии неполны. */
.refs-error {
  flex: none;
  margin: 0;
  padding: 8px 12px;
  text-align: center;
  background: #fff4e5;
  color: #8a5300;
  border-bottom: 1px solid #f5d9ac;
}

/* Каркас настроек (задача 4): та же двухпанельная форма, что и у переписки
   (список слева, содержимое справа) — не ради единообразия само по себе, а
   потому что оператор уже знает эту форму по .chat-screen, и второй язык
   разметки для второго места читался бы как другое приложение. */
.settings-shell {
  display: flex;
  flex: 1;
  min-height: 0;
}

.settings-nav {
  width: 240px;
  flex: none;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--gran);
  background: var(--karta);
}

.settings-back {
  padding: 12px 16px;
  text-align: left;
  font-size: 13px;
  color: var(--tihiy);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--gran);
  cursor: pointer;
}

.settings-sections { list-style: none; margin: 0; padding: 0; }

.settings-section {
  display: block;
  width: 100%;
  padding: 10px 16px;
  text-align: left;
  font: inherit;
  color: var(--tekst);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--gran);
  cursor: pointer;
}

.settings-section.active { color: var(--glavniy); font-weight: 600; }

.settings-content { flex: 1; min-height: 0; padding: 16px; overflow-y: auto; }

@media (max-width: 720px) {
  .settings-shell { flex-direction: column; }
  .settings-nav { width: 100%; border-right: 0; border-bottom: 1px solid var(--gran); }
}

/* Раздел «Сотрудники» (задача 5): форма заведения, таблица работающих и
   отдельная таблица выключенных. Цвет строки — вспомогательный намёк
   (человек, не различающий его, читает слово «выключен» в самой строке),
   а не единственный признак — отсюда .disabled на строке, не на цвет-only
   маркер. */
.employees h2 { margin: 0 0 12px; font-size: 16px; }
.employees h3 { margin: 20px 0 8px; font-size: 14px; color: var(--tihiy); }

.employee-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.employee-form input,
.employee-form select {
  padding: 8px 10px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.employee-form button {
  padding: 8px 14px;
  color: #fff;
  background: var(--glavniy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.employee-form button:disabled { background: var(--gran); cursor: default; }

.employees-error { color: #b3261e; }

.employees-table { width: 100%; border-collapse: collapse; font-size: 14px; }

/* Длинное нераздельное слово не должно уводить карточку за правый край —
   ровно то же правило и по той же причине, что у .role-name в разделе ролей
   (итоговое ревью, находка 12). В карточке сотрудника лежит в том числе имя
   роли, то самое значение, которое рядом уже признали опасным: оно приходит
   от клиента, и «Старшийменеджерпоработесключевымиклиентами» одним словом
   законно. На узком экране (правила ниже, 720 точек) карточка от такого
   слова уезжала за край вместе со кнопкой «Выключить». */
.employees-table td {
  padding: 8px 6px;
  border-bottom: 1px solid var(--gran);
  overflow-wrap: anywhere;
  word-break: break-word;
}

.employee-row.disabled td { color: var(--tihiy); }

.employee-toggle {
  padding: 5px 10px;
  font-size: 13px;
  color: var(--glavniy);
  background: var(--karta);
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  cursor: pointer;
}

.employee-toggle:disabled { color: var(--tihiy); border-color: var(--gran); cursor: default; }

/* Замена кнопки «Выключить» у владельца и у себя (находка живой проверки
   захода 2, дефект 4): не кнопка, а короткое объяснение — чтобы не выглядело
   нажимаемым и не обещало действие, которое сервер отказывает всегда. */
.employee-toggle-blocked {
  display: inline-block;
  font-size: 12px;
  color: var(--tihiy);
  max-width: 220px;
}

/* Строка вместо мёртвой формы заведения (дефект 3): тот же приглушённый вид,
   что и у прочих объяснений (.note), без рамки формы вокруг. */
.employees-note { margin: 8px 0; }

/* Подтверждение на выключение (не window.confirm — окно на своём экране, а
   не системный диалог): кнопка, отрезающая доступ, не должна срабатывать с
   одного промаха мышью. У включения такого блока нет — оно ничего не
   отнимает и подтверждения не просит. */
.employee-confirm {
  margin-top: 12px;
  padding: 12px;
  background: #fdecea;
  border: 1px solid #f2b8b5;
  border-radius: 6px;
}

.employee-confirm p { margin: 0 0 8px; }

.employee-confirm button {
  padding: 6px 12px;
  margin-right: 8px;
  border-radius: 6px;
  cursor: pointer;
}

/* Круг правок ревью: на 375 точках .employees-table (503 точки при
   правилах выше) уходила за правый край, а прокрутка ничем себя не
   обозначала — единственный рычаг отключения доступа оказывался не виден
   с телефона. Порог тот же, что уже используется для переписки и для
   .settings-shell выше (720 точек) — второго порога не заводим: два
   разных однажды разойдутся, и окно будет ломаться в промежутке между
   ними. Ниже порога строка таблицы становится карточкой: каждая ячейка —
   своя строка внутри карточки, подпись берётся из data-label (ставит
   settings_employees.js), горизонтальной прокрутки не остаётся вовсе. */
@media (max-width: 720px) {
  .employees-table,
  .employees-table tbody { display: block; width: 100%; }

  .employees-table tr.employee-row {
    display: block;
    margin-bottom: 10px;
    padding: 10px 12px;
    border: 1px solid var(--gran);
    border-radius: 6px;
  }

  .employees-table td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 4px 0;
    border-bottom: 0;
    text-align: right;
  }

  .employees-table td[data-label]:not([data-label=""])::before {
    content: attr(data-label);
    flex: none;
    font-weight: 600;
    color: var(--tihiy);
    text-align: left;
  }

  .employees-table td[data-label=""] { justify-content: flex-end; }
}

/* Раздел «Роли» (задача 6): список ролей с галочками прав и выбором
   области видимости. Роль владельца сервер защищает структурно и отдаёт
   со всеми правами истинными — здесь это не перерисовывается иначе, тем же
   принципом, что и у .employee-row.disabled: цвет/бейдж — подсказка, слово
   («владелец») — источник смысла; кнопок правки у неё нет вовсе, а не
   спрятаны disabled. */
.roles h2 { margin: 0 0 12px; font-size: 16px; }

.role-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 16px;
  padding: 12px;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.role-form input[name=name] {
  padding: 8px 10px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.role-form select {
  padding: 8px 10px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
  align-self: flex-start;
}

.role-form button {
  padding: 8px 14px;
  color: #fff;
  background: var(--glavniy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.role-form button:disabled { background: var(--gran); cursor: default; }

.roles-error { color: #b3261e; }

.role-rights { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }

.role-rights label {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 13px;
}

.role-rights input { margin-top: 2px; flex: none; }

/* Две подписи у галочки (итоговое ревью, находка 11): имя права — тем же
   словом, каким отказывает сервер, — и под ним перечень охраняемого. Перечень
   приглушён и мельче: он отвечает на второй вопрос («что перестанет
   работать»), а глазами по списку ищут первое. */
.role-right-text { display: flex; flex-direction: column; gap: 2px; }
.role-right-name { font-weight: 600; }

.role-right-methods {
  font-size: 12px;
  color: var(--tihiy);
  overflow-wrap: anywhere;
}

/* Круг правок ревью-2: пока висит вопрос, снятие ДРУГОЙ галочки заблокировано
   (см. RightsFields в settings_roles.js) — подпись гаснет тем же приёмом,
   что и .employee-row.disabled, чтобы недоступность было видно, а не
   выглядела поломкой. */
.role-rights label.locked { color: var(--tihiy); }

.roles-table { width: 100%; border-collapse: collapse; font-size: 14px; }

.roles-table td {
  padding: 10px 6px;
  border-bottom: 1px solid var(--gran);
  vertical-align: top;
}

/* Длинное имя роли одним словом не должно выпихивать карточку за край —
   остаточная мелочь задачи 5 (там за край уходила целая таблица целиком;
   здесь тем же самым рискует одно длинное слово в имени). */
.role-name {
  overflow-wrap: anywhere;
  word-break: break-word;
}

.role-owner-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 12px;
  color: var(--tihiy);
  border: 1px solid var(--gran);
  border-radius: 10px;
}

/* Круг правок ревью, находка 2: имя роли — поле правки, а не текст. */
.role-name-input {
  width: 100%;
  padding: 6px 8px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

/* Круг правок ревью, находка 3: подтверждение снятия права и удаления роли
   — тот же приём, что у .employee-confirm, тот же смысл (отнимающее
   подтверждается). */
.role-confirm {
  margin-top: 12px;
  padding: 12px;
  background: #fdecea;
  border: 1px solid #f2b8b5;
  border-radius: 6px;
}

.role-confirm p { margin: 0 0 8px; }

.role-confirm button {
  padding: 6px 12px;
  margin-right: 8px;
  border-radius: 6px;
  cursor: pointer;
}

.role-row td[data-label=""] button {
  padding: 5px 10px;
  font-size: 13px;
  color: #b3261e;
  background: var(--karta);
  border: 1px solid #b3261e;
  border-radius: 6px;
  cursor: pointer;
}

.role-row td[data-label=""] button:disabled { color: var(--tihiy); border-color: var(--gran); cursor: default; }

/* Тот же порог, что у .employees-table и .settings-shell (720 точек) —
   второй порог не заводим, см. комментарий там. Ниже порога строка
   становится карточкой, но, в отличие от .employees-table, подпись и
   значение идут одно ПОД другим, не в строку: содержимое ячеек здесь
   многострочное (список из четырёх галочек, длинное имя с бейджем
   «владелец»), и укладка в одну строку с подписью слева обрезала бы его. */
@media (max-width: 720px) {
  .roles-table,
  .roles-table tbody { display: block; width: 100%; }

  .role-row {
    display: block;
    margin-bottom: 10px;
    padding: 10px 12px;
    border: 1px solid var(--gran);
    border-radius: 6px;
  }

  .roles-table td {
    display: block;
    padding: 6px 0;
    border-bottom: 0;
  }

  .roles-table td[data-label]:not([data-label=""])::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 2px;
    font-weight: 600;
    font-size: 12px;
    color: var(--tihiy);
  }

  .role-row td[data-label=""] { text-align: right; }
}

/* Обсуждение с коллегами (заход 3): подоконок справа от переписки. Вид у него
   намеренно другой — фон и подпись, — потому что перепутать поле обсуждения с
   полем ответа клиенту дорого: отозвать отправленное в WhatsApp нельзя.

   КРУГ ПРАВОК 1 (находка 2). --fon-vtoroy в файле нет и не было; взятый
   раньше --fon оказался тем же фоном, что уже виден за перепиской — ни
   .conversation, ни .chat-screen, ни .chat-shell своего фона не задают, и всё
   показывает var(--fon) от body. Различие держалось на одной рамке, а этого
   мало. Теперь у панели фон --karta (белый, как у .sidebar и .composer) —
   он и стоит рядом с сохранившим свой (не заданный явно, серый var(--fon) от
   body) фоном .conversation. Разница читается на глаз БЕЗ рамки, а рамка при
   этом остаётся. Новых переменных не заведено — обе уже были в файле. */
.discussion {
  display: flex;
  flex-direction: column;
  width: 320px;
  border-left: 1px solid var(--gran);
  background: var(--karta);
}
.discussion-head { padding: 10px 12px; border-bottom: 1px solid var(--gran); }
.discussion-title { font-weight: 600; margin-right: 8px; }
.discussion-hint { color: var(--tihiy); font-size: 12px; }
.discussion-empty { padding: 12px; }
.discussion-list { flex: 1; overflow-y: auto; margin: 0; padding: 10px 12px; list-style: none; }
.discussion-list li { margin-bottom: 10px; }
.discussion-author { display: block; font-size: 12px; color: var(--tihiy); }
.discussion-text { white-space: pre-wrap; word-break: break-word; }
.discussion-form { padding: 10px 12px; border-top: 1px solid var(--gran); }
/* Само поле — не только область вокруг него — обязано отличаться от
   .composer-text: у поля ответа клиенту фон белый (унаследован от белого
   .composer), у поля обсуждения — серый var(--fon), тот же оттенок, что
   обычно виден за перепиской. Одной рамки для этого мало, находка 2 это и
   говорит. */
.discussion-input {
  width: 100%;
  min-height: 56px;
  box-sizing: border-box;
  background: var(--fon);
}
.discussion-send { margin-top: 8px; width: 100%; }

/* Пара кнопок «Клиент / Обсуждение» нужна только на узком экране: на широком
   обе части видны сразу. */
.pane-tabs { display: none; }

@media (max-width: 720px) {
  .pane-tabs { display: flex; gap: 8px; padding: 8px 10px; }
  .pane-tabs button { flex: 1; }
  /* По умолчанию на узком экране открыта переписка с клиентом. */
  .chat-screen.dialog-open .discussion { display: none; }
  .chat-screen.dialog-open.discussion-open .conversation { display: none; }
  .chat-screen.dialog-open.discussion-open .discussion {
    display: flex;
    width: 100%;
    border-left: 0;
  }
}

/* Кто в разговоре (заход 3). Блок стоит между заголовком и лентой: он про
   диалог целиком, а не про отдельное сообщение. */
.participants { padding: 8px 12px; border-bottom: 1px solid var(--gran); }
.participants h3 { margin: 0 0 6px; font-size: 13px; color: var(--tihiy); }
.participants-list { margin: 0 0 8px; padding: 0; list-style: none; }
.participants-list li { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; }
.participant-name { font-weight: 600; }
.participant-kind, .participant-by { font-size: 12px; color: var(--tihiy); }
.assign-form, .invite-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; }
.invite-warning { flex-basis: 100%; margin: 0; }

@media (max-width: 720px) {
  /* Длинные подписи видов участия не должны уводить блок за край экрана —
     находка ревью прошлой ветки о карточке, уехавшей за границу. */
  .assign-form, .invite-form { flex-direction: column; align-items: stretch; }
  .participants select, .participants button { width: 100%; }
}

/* Стадия и ярлыки диалога — на самой переписке (задача 9). Тот же приём, что
   у .participants рядом: блок между заголовком и лентой, про диалог целиком. */
.dialog-status {
  padding: 8px 12px;
  border-bottom: 1px solid var(--gran);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.dialog-status-error, .dialog-status-note { margin: 0; font-size: 13px; }
.dialog-status-error { color: #b3261e; }
.dialog-status-note { color: var(--tihiy); }

.status-part { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.status-title { font-size: 13px; color: var(--tihiy); }
.status-current { display: inline-flex; align-items: center; gap: 6px; }
.status-current.status-empty { color: var(--tihiy); }

.status-label-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.status-label-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 8px;
  background: var(--fon);
  border: 1px solid var(--gran);
  border-radius: 12px;
  font-size: 13px;
}

.status-empty { color: var(--tihiy); }

.label-add { position: relative; display: flex; flex-direction: column; gap: 4px; }

.label-query {
  padding: 6px 8px;
  font: inherit;
  color: var(--tekst);
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.label-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.label-suggestion {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  font: inherit;
  color: var(--tekst);
  background: var(--karta);
  border: 1px solid var(--gran);
  border-radius: 12px;
  cursor: pointer;
}

.label-create {
  align-self: flex-start;
  padding: 6px 10px;
  font-size: 13px;
  color: var(--glavniy);
  background: var(--karta);
  border: 1px solid var(--gran);
  border-radius: 6px;
  cursor: pointer;
}

@media (max-width: 720px) {
  /* Тот же приём, что у .participants выше: длинные подписи и списки
     подсказок не должны уводить блок за край узкого экрана. */
  .status-part { flex-direction: column; align-items: stretch; }
  .status-stage-select, .label-query, .label-create { width: 100%; }
}

/* Раздел «Возможности» (задача 8): видно только владельцу (settings.js,
   sectionsFor) — список переключателей, каждый со словами о том, что
   появится и что исчезнет. Приём подтверждения здесь не нужен: включение
   ничего не отнимает у того, кто его нажал (он и так владелец), а выключение
   лишь ПРЯЧЕТ уже существующую разметку (features.ts), не удаляет её. */
.features h2 { margin: 0 0 8px; font-size: 16px; }

.feature-intro { margin: 0 0 16px; }

.feature-error { color: #b3261e; }

.feature-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }

.feature-row {
  padding: 12px;
  border: 1px solid var(--gran);
  border-radius: 6px;
  background: var(--karta);
}

.feature-row-head { display: flex; align-items: center; gap: 10px; }

.feature-toggle { display: flex; align-items: center; gap: 8px; flex: 1; }

.feature-name { font-weight: 600; }

.feature-state { font-size: 12px; color: var(--tihiy); }

.feature-about { margin: 8px 0 0; font-size: 13px; color: var(--tihiy); }

/* Раздел «Ключи для программ» (settings_keys.js): видно только владельцу.
   Выданный ключ стоит отдельной рамкой и переносится по знакам — 48 знаков
   без пробелов иначе вылезли бы за край на телефоне. */
.keys h2 { margin: 0 0 8px; font-size: 16px; }
.keys-intro { margin: 0 0 16px; }
.keys > button, .key-form { margin: 0 0 16px; }
.key-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; }
.key-form label { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 200px; }
.key-issued {
  margin: 0 0 16px;
  padding: 12px;
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  background: var(--karta);
}
.key-issued-title { margin: 0 0 8px; font-weight: 600; }
.key-full { display: block; margin: 0 0 8px; padding: 8px; word-break: break-all; user-select: all; }
.key-issued-warning { margin: 0 0 8px; color: #b3261e; }
.key-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.key-row { padding: 12px; border: 1px solid var(--gran); border-radius: 6px; background: var(--karta); }
.key-row.revoked { opacity: 0.6; }
.key-row-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.key-name { font-weight: 600; flex: 1; }
.key-hint { font-size: 12px; color: var(--tihiy); }
.key-state { font-size: 12px; color: var(--tihiy); }
.key-meta { margin: 8px 0 0; font-size: 13px; color: var(--tihiy); }
.key-confirm { margin: 8px 0 0; }
.key-confirm p { margin: 0 0 8px; }

/* Раздел «Статусы» (задача 8): две части — стадии и ярлыки, каждая видна,
   только если её блок включён (settings_statuses.js). Пустая часть не молчит
   — .statuses-off говорит словами, что выключено и где включатель, тем же
   приглушённым видом, что и прочие объяснения (.note). */
.statuses h2 { margin: 0 0 12px; font-size: 16px; }
.statuses h3 { margin: 20px 0 8px; font-size: 14px; color: var(--tihiy); }
.stages-block:first-of-type h3 { margin-top: 0; }

.statuses-off { margin: 8px 0 20px; }

.stages-error, .labels-error { color: #b3261e; }

.labels-intro { margin: 0 0 12px; }

/* Кружок цвета — намёк, не единственный признак: рядом всегда стоит слово
   (имя стадии/ярлыка, а вид стадии — отдельным словом), тем же принципом,
   что и .employee-row.disabled (цвет — подсказка тому, кто его различает). */
.cvet-dot {
  display: inline-block;
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--gran);
  background: var(--cvet-slate);
}
.cvet-dot[data-color=slate] { background: var(--cvet-slate); }
.cvet-dot[data-color=sky] { background: var(--cvet-sky); }
.cvet-dot[data-color=green] { background: var(--cvet-green); }
.cvet-dot[data-color=amber] { background: var(--cvet-amber); }
.cvet-dot[data-color=red] { background: var(--cvet-red); }
.cvet-dot[data-color=violet] { background: var(--cvet-violet); }
.cvet-dot[data-color=teal] { background: var(--cvet-teal); }
.cvet-dot[data-color=pink] { background: var(--cvet-pink); }

.stage-form, .stage-edit-form, .label-edit-form, .label-merge-pick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding: 12px;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.stage-form input, .stage-edit-form input, .label-edit-form input {
  padding: 8px 10px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.stage-form select, .stage-edit-form select, .label-edit-form select, .label-merge-pick select {
  padding: 8px 10px;
  font: inherit;
  border: 1px solid var(--gran);
  border-radius: 6px;
}

.stage-form button,
.stage-edit-form button,
.label-edit-form button,
.label-merge-pick button {
  padding: 8px 14px;
  color: #fff;
  background: var(--glavniy);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.stage-form button:disabled,
.stage-edit-form button:disabled,
.label-edit-form button:disabled,
.label-merge-pick button:disabled { background: var(--gran); cursor: default; }

.stage-list, .label-list { list-style: none; margin: 0; padding: 0; }

.stage-row, .label-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--gran);
}

.stage-row-view, .label-row-view {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.stage-name, .label-name { font-weight: 600; overflow-wrap: anywhere; word-break: break-word; }

.stage-kind { font-size: 13px; color: var(--tihiy); }

.stage-row-actions, .label-row-actions {
  display: flex;
  gap: 6px;
  margin-left: auto;
}

.stage-row-actions button, .label-row-actions button {
  padding: 5px 10px;
  font-size: 13px;
  color: var(--glavniy);
  background: var(--karta);
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  cursor: pointer;
}

.stage-row-actions button[data-action=delete], .label-row-actions button[data-action=delete] {
  color: #b3261e;
  border-color: #b3261e;
}

.stage-row-actions button:disabled, .label-row-actions button:disabled {
  color: var(--tihiy);
  border-color: var(--gran);
  cursor: default;
}

.label-merge-confirm {
  margin-top: 8px;
  padding: 12px;
  background: #fdecea;
  border: 1px solid #f2b8b5;
  border-radius: 6px;
}

.label-merge-confirm p { margin: 0 0 8px; }

.label-merge-confirm button { padding: 6px 12px; margin-right: 8px; border-radius: 6px; cursor: pointer; }

/* Подтверждение удаления — тот же приём, что .role-confirm/.employee-confirm:
   отнимающее действие спрашивает и называет ИМЯ (принятое решение 4 брифа). */
.stage-confirm, .label-confirm {
  margin-top: 12px;
  padding: 12px;
  background: #fdecea;
  border: 1px solid #f2b8b5;
  border-radius: 6px;
}

.stage-confirm p, .label-confirm p { margin: 0 0 8px; }

.stage-confirm button, .label-confirm button {
  padding: 6px 12px;
  margin-right: 8px;
  border-radius: 6px;
  cursor: pointer;
}

/* Тот же порог 720 точек, что и у остальных разделов настроек — второй порог
   не заводим (см. комментарий у .employees-table). Ниже него строка и форма
   переходят в столбец, чтобы не уезжать за правый край. */
@media (max-width: 720px) {
  .stage-row-view, .label-row-view { align-items: flex-start; }
  .stage-row-actions, .label-row-actions { margin-left: 0; flex-wrap: wrap; }
  .stage-form, .stage-edit-form, .label-edit-form, .label-merge-pick {
    flex-direction: column;
    align-items: stretch;
  }
}

/* Страница «нет связи» (client/offline.html): её показывает service worker,
   когда телефон не достаёт до сервера. Та же карточка, что у входа. */
.offline {
  max-width: 360px;
  margin: 12vh auto;
  padding: 24px;
  background: var(--karta);
  border: 1px solid var(--gran);
  border-radius: 10px;
}
.offline h1 { margin: 0 0 8px; font-size: 20px; }
.offline p { margin: 0 0 16px; color: var(--tihiy); }
.offline-retry {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border-radius: 6px;
  background: var(--glavniy);
  color: #fff;
  text-decoration: none;
}

/* Раздел «Уведомления» (settings_notifications.js) — у каждого сотрудника.
   Смотрится в основном с телефона, поэтому кнопки и галочки крупные. */
.push-settings h2 { margin: 0 0 8px; font-size: 16px; }
.push-settings h3 { margin: 20px 0 8px; font-size: 14px; color: var(--tihiy); }
.push-intro { margin: 0 0 8px; }
.push-state { margin: 0 0 8px; }
.push-here-block { margin: 0 0 12px; }
.push-settings button { min-height: 44px; padding: 0 14px; }
.push-primary {
  border: 0;
  border-radius: 6px;
  background: var(--glavniy);
  color: #fff;
  font: inherit;
}
.push-primary:disabled { background: var(--gran); }
.push-note { margin: 8px 0 0; }
.push-ios {
  padding: 12px;
  border: 1px solid var(--glavniy);
  border-radius: 6px;
  background: var(--karta);
}
.push-ios p { margin: 0 0 8px; }
.push-ios ol { margin: 0 0 8px; padding-left: 20px; }
.push-devices { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.push-device { padding: 12px; border: 1px solid var(--gran); border-radius: 6px; background: var(--karta); }
.push-device-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.push-device-name { flex: 1; font-weight: 600; }
.push-here { font-size: 12px; font-weight: 400; color: var(--glavniy); }
.push-device-meta { margin: 8px 0 0; font-size: 13px; color: var(--tihiy); }
.push-prefs { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.push-check { display: flex; gap: 10px; align-items: flex-start; min-height: 44px; }
.push-check input { width: 22px; height: 22px; margin: 2px 0 0; flex: none; }
.push-check small { display: block; }
.push-quiet { display: flex; flex-wrap: wrap; gap: 12px; }
.push-quiet input { min-height: 44px; font: inherit; }

/* ТЕЛЕФОН (замысел телефона, решение 8; проверено снимками на 375 px,
   .superpowers/snimki-z10). Администраторы салона отвечают в основном с
   телефона, поэтому:
   - всё, что нажимают пальцем, не ниже 44 px (рекомендация Apple и Google:
     мельче — промахиваются и попадают в соседнюю кнопку);
   - «Кто в разговоре» и статус свёрнуты под кнопку .dialog-more (chat.js),
     иначе на ленту переписки оставалась полоска над полем ввода;
   - поле ответа не закрывается клавиатурой: .app-shell держит 100dvh, а
     viewport в index.html — interactive-widget=resizes-content (Chrome на
     Android уменьшает окно под клавиатуру, а не накрывает его). */
.dialog-more { display: none; }
@media (max-width: 720px) {
  button, select, textarea,
  input:not([type=checkbox]):not([type=radio]):not([type=hidden]) {
    min-height: 44px;
  }
  input[type=checkbox], input[type=radio] { width: 22px; height: 22px; }
  /* Галочку нажимают вместе с подписью: целью пальца служит вся строка. */
  label:has(> input[type=checkbox]) { min-height: 44px; align-items: center; }
  /* У галочек уведомлений под подписью пояснение в две строки — галочка
     остаётся напротив первой строки, а не посередине абзаца. */
  label.push-check { align-items: flex-start; }
  .place-switch { padding: 0 16px; font-size: 15px; }
  .dialog-back { min-height: 44px; }
  .dialog-more {
    display: block;
    width: 100%;
    padding: 0 12px;
    border: 0;
    border-bottom: 1px solid var(--gran);
    background: var(--karta);
    color: var(--glavniy);
    font: inherit;
    text-align: left;
  }
  .conversation:not(.details-open) .participants,
  .conversation:not(.details-open) .dialog-status { display: none; }
  /* Поле выбора файла — сама кнопка «Выберите файл»; подпись о выбранном
     файле браузер рисует рядом, в той же строке. */
  .composer-attach { font-size: 14px; }
}
