/* iv-cowork — оформление. Тема светлая/тёмная: системная по умолчанию,
   переключатель ставит data-theme на <html>. */

/* Атрибут `hidden` прячет по-настоящему, чем бы класс ни красился.

   Браузерное `[hidden] { display: none }` живёт в UA-стиле и слабее ЛЮБОГО
   авторского `display`, поэтому элемент с `display: flex` в классе остаётся
   на экране, честно имея `hidden = true`. Ловушка ловилась уже трижды
   поштучно (`.quote-pop[hidden]`, `.files-panel[hidden]`), и на третий раз
   она уехала на бой: строка над вложениями и красная галочка «отправить как
   есть» висели в пустом диалоге, обещая ровно обратное документации
   (`docs/05-vlozheniya.md` — в наблюдении галочки не показываем вовсе).
   Найдено браузерным обходом 23.08.2026; проверка — в `qa/browser/smoke.sh`.

   Правило общее и с `!important` намеренно: поштучные заплатки уже показали,
   что следующий класс с `display` заведут, не вспомнив про эту строку. */
[hidden] { display: none !important; }

:root {
    --bg: #f6f7fb;
    --bg-panel: #ffffff;
    --bg-soft: #eef0f7;
    --bg-hover: #e6e9f4;
    --text: #1c1f26;
    --text-dim: #6b7280;
    --border: #e0e3ee;
    --accent: #4f6ef7;
    /* Второй цвет графиков: среднее рядом с медианой. Тёплый, чтобы пара
       различалась и в чёрно-белой печати, а не только цветом. */
    --accent-2: #e07b39;
    /* Третий цвет графиков: линия «диалогов» рядом с активными и сообщениями
       на графике вовлечения — трём линиям нужны три различимых цвета. */
    --accent-3: #8a63d2;
    --accent-soft: #eaeeff;
    --danger: #d64545;
    --warn: #d98324;
    --ok: #2f9e63;
    --bubble-user: #4f6ef7;
    /* Текст на акценте и фон шапки — переменные завёл BACKLOG 398 ДЕМОЦВЕТ
       (docs/67, «Цвета инсталляции»): значения здесь — прежний вид сервиса,
       палитра профиля перекрывает их блоком в <head> после этого файла.
       Пустая шапка у профиля значит «как было» — фон панели. */
    --on-accent: #ffffff;
    --bubble-user-text: var(--on-accent);
    --topbar-bg: var(--bg-panel);
    --bubble-bot: #ffffff;
    --radius: 12px;
    --shadow: 0 1px 2px rgba(20, 25, 45, .06), 0 8px 24px rgba(20, 25, 45, .06);
    --sidebar-w: 290px;
}

html[data-theme="dark"], html[data-theme="auto"] {
    color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
    html[data-theme="auto"] {
        --bg: #14161c;
        --bg-panel: #1b1e26;
        --bg-soft: #22262f;
        --bg-hover: #2a2f3a;
        --text: #e9ebf2;
        --text-dim: #99a0b0;
        --border: #2a2f3a;
        --accent: #6c8cff;
        --accent-2: #ffa25c;
        --accent-3: #b298e8;
        --accent-soft: #232a44;
        --bubble-user: #4560d8;
        --bubble-bot: #1f232c;
        --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .25);
    }
}

html[data-theme="dark"] {
    --bg: #14161c;
    --bg-panel: #1b1e26;
    --bg-soft: #22262f;
    --bg-hover: #2a2f3a;
    --text: #e9ebf2;
    --text-dim: #99a0b0;
    --border: #2a2f3a;
    --accent: #6c8cff;
    --accent-soft: #232a44;
    --bubble-user: #4560d8;
    --bubble-bot: #1f232c;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .25);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    background: var(--bg);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }
.hidden { display: none !important; }


/* --- Навигация шапки ----------------------------------------------------
   Единственная навигация сервиса. Раньше её было три (кнопка «О сервисе»,
   низ колонки диалогов, окно профиля) — три места, куда надо не забыть
   добавить следующий экран, и три ответа на «где искать». */
.topnav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: 4px;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
}

.topnav-item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 11px;
    border-radius: 9px;
    color: var(--text-dim);
    text-decoration: none;
    font-size: 13.5px;
    white-space: nowrap;
    transition: background .12s, color .12s;
}

.topnav-item:hover { background: var(--bg-soft); color: var(--text); }
.topnav-item.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.topnav-icon { font-size: 14px; line-height: 1; }

.topbar-right { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* Узкий экран: подписи прячутся, значки остаются — навигация должна
   пережить телефон, а не исчезнуть на нём. Поэтому же она не сжимается
   (`flex: 0 0 auto`): логотип со слоганом и длинное ФИО вдвоём съедали всю
   ширину, и на 375 px от навигации оставалось ровно ноль пикселей. */
@media (max-width: 860px) {
    .topnav-text { display: none; }
    .topnav-item { padding: 7px 9px; }
    .topnav-icon { font-size: 16px; }
    .topnav { flex: 0 0 auto; margin-left: 0; }
}

/* Телефон: слоган уходит (он про сервис, а не про навигацию), имя
   сокращается до первого слова силами многоточия. */
@media (max-width: 620px) {
    .topbar { gap: 8px; padding: 0 10px; }
    .logo-slogan { display: none; }
    .logo-text { font-size: 14px; }
    .user-chip { max-width: 20vw; }
}

/* --- Общая рамка страницы ----------------------------------------------
   Одна на статистику, права, документацию и профиль: это соседние экраны
   одного сервиса, и разъезжаться им незачем. */
.page-wrap { max-width: 1040px; margin: 0 auto; padding: 22px 18px 60px; }
.page-head { margin-bottom: 18px; }
.page-head h1 { font-size: 22px; margin: 0 0 4px; }
.page-sub { color: var(--text-dim); font-size: 13px; }
.page-lead { color: var(--text-dim); font-size: 13.5px; line-height: 1.6; max-width: 760px; margin: 0 0 18px; }
.page-foot { margin-top: 32px; }

/* --- Панель: заголовок, пояснение, содержимое --------------------------- */
.panel {
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px 18px;
}

.panel-head h2 { font-size: 16px; margin: 0 0 4px; }
.panel-hint { color: var(--text-dim); font-size: 12.5px; line-height: 1.55; margin: 0 0 14px; max-width: 720px; }
.count-chip { color: var(--text-dim); font-size: 12px; font-weight: 400; }

/* --- Шапка ------------------------------------------------------------- */
.topbar {
    height: 52px;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 14px;
    background: var(--topbar-bg);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 20;
}

.logo {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-weight: 650;
    font-size: 16px;
    letter-spacing: -.01em;
    color: var(--text);
    text-decoration: none;
}

.topbar-right { display: flex; align-items: center; gap: 12px; }
.link-quiet { color: var(--text-dim); text-decoration: none; font-size: 13px; }
.link-quiet:hover { color: var(--accent); }

.icon-btn {
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-dim);
    border-radius: 8px;
    width: 32px;
    height: 32px;
    cursor: pointer;
    font-size: 15px;
    line-height: 1;
}
.icon-btn:hover { background: var(--bg-hover); color: var(--text); }

/* --- Информер «Мои задачи» --------------------------------------------- */
/* Счётчик в шапке появляется вместе с первой задачей и исчезает вместе с
   последней: пустого места на его месте не остаётся. */
.informer { position: relative; }
.informer-btn {
    display: flex; align-items: center; gap: 6px;
    border: 1px solid var(--border); background: var(--accent-soft); color: var(--text);
    border-radius: 999px; padding: 3px 10px; cursor: pointer; font-size: 13px; line-height: 1.6;
}
.informer-btn:hover { background: var(--bg-hover); }
.informer.has-fail .informer-btn { background: transparent; color: var(--danger); border-color: var(--danger); }
.informer-count { font-variant-numeric: tabular-nums; }
.informer-panel {
    position: absolute; right: 0; top: calc(100% + 8px); z-index: 40;
    width: min(360px, calc(100vw - 24px));
    background: var(--bg-panel); border: 1px solid var(--border);
    border-radius: var(--radius); box-shadow: var(--shadow); padding: 10px;
}
.informer-head { font-size: 12px; color: var(--text-dim); margin-bottom: 6px; }
.informer-list { display: flex; flex-direction: column; gap: 8px; max-height: 60vh; overflow-y: auto; }
.informer-row { border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; background: var(--bg-soft); }
.informer-chat { font-size: 13px; color: var(--text); text-decoration: none; font-weight: 500; }
.informer-chat:hover { color: var(--accent); }
.informer-row-meta { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
.informer-row-acts { display: flex; gap: 6px; margin-top: 6px; }
.informer-act {
    border: 1px solid var(--border); background: transparent; color: var(--text-dim);
    border-radius: 7px; padding: 2px 8px; font-size: 12px; cursor: pointer;
}
.informer-act:hover { background: var(--bg-hover); color: var(--text); }
.informer-act:disabled { opacity: .5; cursor: default; }

/* --- Каркас ------------------------------------------------------------ */
.layout {
    display: grid;
    grid-template-columns: var(--sidebar-w) 1fr;
    height: calc(100vh - 52px);
    /* На телефоне «сто процентов высоты» — это высота окна ВМЕСТЕ с адресной
       строкой браузера, которая то появляется, то прячется: поле ввода из-за
       этого уезжало под панель браузера. `dvh` считает по видимой части.
       Строка с `vh` оставлена запасной для браузеров, не знающих `dvh`. */
    height: calc(100dvh - 52px);
    overflow: hidden;
}

.sidebar {
    display: flex;
    flex-direction: column;
    background: var(--bg-panel);
    border-right: 1px solid var(--border);
    min-height: 0;
}

.sidebar-top { padding: 12px; display: flex; flex-direction: column; gap: 8px; }

.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
    border: 0;
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 14px;
    font-weight: 550;
    cursor: pointer;
}
.btn-primary:hover { filter: brightness(1.06); }
.btn-primary:disabled { opacity: .55; cursor: default; }

.btn-quiet {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 10px;
    padding: 9px 14px;
    cursor: pointer;
    font-size: 14px;
}

/* Кнопки права «Чистильщик» (пункт 209, Э2.1) — компактные, прямо в строке таблицы. */
.cleanup-actions { white-space: nowrap; }
/* Поиск диалога по номеру (пункт 209, У1) — компактная строка с полем и кнопкой. */
.cleanup-dialog-search { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cleanup-dialog-search .input-mini {
    width: 120px;
    padding: 5px 8px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    color: var(--text);
    font-size: 13px;
}
.cleanup-dialog-result { margin-top: 6px; font-size: 13px; }
.cleanup-dialog-result:empty { display: none; }
/* Ряд кнопок перезапуска (демон, слив пула, службы) — отдельно от строки
   состояния «Машина «мозга»: …» (пункт 221, 04.09.2026). */
.cleanup-restart-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* Перезагрузка машины Pro целиком (пункт 209, Э3, третья кнопка) — самая
   тяжёлая заявка канала, предупреждение выделено цветом заранее, до клика. */
.cleanup-host-warn { color: var(--danger, #c0392b); margin-top: 8px; }
.btn-mini {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-dim);
    border-radius: 6px;
    padding: 3px 8px;
    margin-left: 6px;
    cursor: pointer;
    font-size: 12px;
}
.btn-mini:first-child { margin-left: 0; }
.btn-mini:hover { border-color: var(--text-dim); color: var(--text); }
.btn-mini-danger { color: #c0392b; border-color: #c0392b; }
.btn-mini-danger:hover { background: #c0392b; color: #fff; }

.chat-search, .field input, .composer textarea {
    width: 100%;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 9px 11px;
    color: var(--text);
    font: inherit;
    outline: none;
}
.chat-search:focus, .field input:focus, .composer textarea:focus { border-color: var(--accent); }

.chat-list { flex: 1; overflow-y: auto; padding: 4px 8px 8px; min-height: 0; }

.chat-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 10px;
    padding: 9px 10px;
    margin-bottom: 2px;
    cursor: pointer;
    color: var(--text);
    position: relative;
}
.chat-item:hover { background: var(--bg-hover); }
.chat-item.active { background: var(--accent-soft); border-color: var(--accent); }

.chat-item-title {
    font-size: 14px;
    font-weight: 520;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    padding-right: 22px;
}

/* Заголовок группы по времени: «Сегодня», «Вчера», «На этой неделе». */
.chat-group {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-dim);
    margin: 10px 2px 4px;
}
.chat-list > .chat-group:first-child { margin-top: 2px; }

/* Фрагмент переписки в находке: две строки, дальше — многоточие. */
.chat-item-snippet {
    margin-top: 3px;
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-dim);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.chat-item-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
    font-size: 12px;
    color: var(--text-dim);
}

.ctx-badge {
    font-variant-numeric: tabular-nums;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--bg-soft);
    border: 1px solid var(--border);
}
.ctx-badge.warn { color: var(--warn); border-color: var(--warn); }
.ctx-badge.danger { color: var(--danger); border-color: var(--danger); }

.chat-item-menu {
    position: absolute;
    top: 6px;
    right: 6px;
    opacity: 0;
    background: transparent;
    border: 0;
    color: var(--text-dim);
    cursor: pointer;
    font-size: 15px;
    padding: 2px 4px;
    border-radius: 6px;
}
.chat-item:hover .chat-item-menu, .chat-item.active .chat-item-menu { opacity: 1; }

/* выпадающее меню диалога */
.chat-menu {
    position: fixed;
    z-index: 60;
    min-width: 200px;
    padding: 4px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
}
.chat-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    font: inherit;
    color: var(--text);
    background: none;
    border: 0;
    border-radius: 6px;
    cursor: pointer;
}
.chat-menu-item:hover { background: var(--bg-hover); }

.chat-item.archived { opacity: .68; }
.archived-mark { opacity: .8; }

/* Инициативное сообщение: сервис вернулся к вопросу сам. Подпись сверху,
   чтобы ответ через час после разговора не выглядел сбоем. */
.msg-initiated {
    margin-bottom: 6px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--accent);
}

.msg.initiated .msg-body { border-left: 2px solid var(--accent); padding-left: 10px; }

/* Непрочитанный ответ. Заголовок наливается цветом, справа — счётчик:
   диалог должен читаться как «тут тебя ждут» боковым зрением, без чтения. */
.chat-item.unread .chat-item-title { font-weight: 680; color: var(--text); }

.unread-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 0 6px;
    min-width: 18px;
    font-size: 11px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
    color: var(--on-accent);
    background: var(--accent, #2f6fed);
    border-radius: 9px;
    vertical-align: 1px;
}

.archive-toggle {
    margin-top: 6px;
    padding: 5px 8px;
    font-size: 12px;
    color: var(--text-dim);
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    cursor: pointer;
}
.archive-toggle:hover { color: var(--text); background: var(--bg-hover); }
.archive-toggle[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }
.chat-item-menu:hover { background: var(--bg-panel); color: var(--text); }


.stats-icon { color: var(--accent); }

.empty-hint { color: var(--text-dim); font-size: 13px; padding: 14px 10px; }

/* --- Диалог ------------------------------------------------------------ */
/* min-height:0 — иначе грид-элемент растёт под контент и композер уезжает вниз */
.chat { display: flex; flex-direction: column; min-width: 0; min-height: 0; position: relative; }

.chat-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 18px;
    border-bottom: 1px solid var(--border);
    background: var(--bg-panel);
}

.chat-title {
    font-size: 15px;
    font-weight: 600;
    margin: 0;
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Номер диалога: он нужен, когда его ищут, и не должен спорить с названием. */
.chat-id {
    flex: 0 0 auto;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-dim);
    border-radius: 6px;
    padding: 2px 7px;
    font: inherit;
    font-size: 12px;
    line-height: 18px;
    cursor: pointer;
}
.chat-id:hover { color: var(--text); background: var(--bg-soft); }

/* Цена диалога по тарифам API (docs/02): зелёным полужирным — в шапке и,
   у администратора, в списке. */
.chat-cost {
    flex: 0 0 auto;
    color: var(--ok, #2f9e63);
    font-weight: 700;
    font-size: 13px;
    white-space: nowrap;
}
.chat-cost[hidden] { display: none; }

/* Настройки разговора одной группой — чтобы на телефоне переехать во вторую
   строку целиком, а не рассыпаться по шапке. */
.chat-settings { display: flex; align-items: center; gap: 12px; margin-left: auto; min-width: 0; }
.context-meter { display: flex; align-items: center; gap: 8px; min-width: 190px; position: relative; }
/* Совет «разговор разросся» (BACKLOG 449) — всплывает под счётчиком, а не
   растягивает шапку: у неё и так узкая полоса на телефоне. */
.context-advice {
    position: absolute; top: 100%; right: 0; z-index: 5; margin-top: 6px;
    display: flex; flex-direction: column; gap: 6px; align-items: flex-end;
    width: 240px; padding: 10px 12px; border-radius: 10px;
    background: var(--bg-elevated, var(--bg-soft)); border: 1px solid var(--border);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
    font-size: 12px; color: var(--text-dim); text-align: right;
}
.context-advice button {
    font: inherit; font-size: 12px; padding: 5px 10px; border-radius: 6px;
    border: 1px solid var(--accent); background: transparent; color: var(--accent); cursor: pointer;
}
.context-advice button:hover { background: var(--accent); color: var(--bg); }
.context-bar { flex: 1; height: 6px; background: var(--bg-soft); border-radius: 999px; overflow: hidden; }
.context-bar i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .25s; }
.context-bar.warn i { background: var(--warn); }
.context-bar.danger i { background: var(--danger); }
.context-label { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.context-spent { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* min-height:0 обязателен: без него флекс-элемент не сжимается и поле ввода уезжает за экран */
.messages { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 22px 18px 8px; }

.empty-state { max-width: 560px; margin: 6vh auto; text-align: center; color: var(--text-dim); }
.empty-state h2 { margin: 12px 0 6px; color: var(--text); font-size: 20px; }
.empty-hero { max-width: 100%; height: auto; border-radius: 12px; }

/* Первый экран: чем сервис занимается и с чего начать. Список — влево:
   по центру он читается как лозунги, а это перечень работ. */
.intro-abilities { list-style: none; margin: 14px 0 0; padding: 0; text-align: left; font-size: 13px; line-height: 1.5; }
.intro-abilities li { margin: 0 0 5px; }
.intro-abilities b { color: var(--text); font-weight: 600; }
.intro-examples-title { margin: 18px 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
.intro-examples { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.intro-example {
    border: 1px solid var(--border); background: var(--bg-panel); color: var(--text);
    border-radius: var(--radius); padding: 8px 12px; font: inherit; font-size: 13px;
    text-align: left; cursor: pointer; max-width: 100%;
}
.intro-example:hover { background: var(--accent-soft); border-color: var(--accent); }
.intro-more { margin: 16px 0 0; font-size: 13px; }

.msg { max-width: 780px; margin: 0 auto 16px; display: flex; gap: 10px; }
.msg-body { border-radius: var(--radius); padding: 10px 13px; box-shadow: var(--shadow); }
.msg.user { justify-content: flex-end; }
.msg.user .msg-body { background: var(--bubble-user); color: var(--bubble-user-text); }
.msg.assistant .msg-body { background: var(--bubble-bot); border: 1px solid var(--border); }

/* «Печатает…» — пока модель считает ответ. Если она уже что-то написала,
   над точками показывается сам текст: ответ идёт потоком, и ждать пустоту
   не нужно. Приглушённый цвет — чтобы черновик не путался с готовым ответом. */
.msg-text.stream { opacity: .75; margin-bottom: 6px; }
/* Строка ожидания вместо прыгающего многоточия: занятие, секунды, токены и
   привычная длительность. Точки показывали только «что-то происходит», а ждать
   тут случается минутами — и «модель читает файл» по ним не отличить от
   упавшего канала. Один пульсирующий кружок остался признаком живой работы. */
.typing-status { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; min-height: 20px; }
.typing-pulse {
    width: 7px; height: 7px; border-radius: 50%; align-self: center;
    background: var(--accent); animation: typing-pulse 1.4s infinite ease-in-out;
}
.typing-act { font-size: 13px; color: var(--text); }
.typing-meta { font-size: 12px; color: var(--text-dim); opacity: .85; }
/* «Остановить» — в самой строке ожидания, а не отдельной панелью: решение
   принимают, глядя на «идёт восьмая минута», и кнопка должна быть там же.
   Приглушённая: это выход, а не действие, к которому подталкивают. */
.typing-stop {
    margin-left: auto; font: inherit; font-size: 12px; line-height: 1.2;
    color: var(--text-dim); background: transparent; cursor: pointer;
    border: 1px solid var(--border); border-radius: 7px; padding: 3px 9px;
}
.typing-stop:hover { color: var(--text); background: var(--bg-hover); }
.typing-stop[disabled] { opacity: .6; cursor: default; }
/* Пояснение к долгому ожиданию: тише основного текста, но читаемое. */
.msg-hint { margin-top: 6px; font-size: 12px; line-height: 1.4; color: var(--text-dim); }
/* Лента хода работы (docs/46) — короткие вести о смысле шага, приглушённо и
   отдельно от самого текста ответа; под строкой ожидания и под готовым
   сообщением. */
.msg-feed { margin-top: 6px; font-size: 12px; line-height: 1.5; color: var(--text-dim); max-height: 160px; overflow-y: auto; }
.msg-feed-line { padding: 1px 0; }
.msg-feed-line::before { content: '· '; }
/* Файлы к ответу едут отдельным запросом и приезжают позже текста — эта строка
   стоит на их месте, пока они в пути, чтобы «файл в ответе» не выглядело
   обманом. */
.msg-files-wait { margin-top: 8px; font-size: 12px; color: var(--text-dim); font-style: italic; }

/* «Что сейчас в работе» на странице статистики: живая таблица заданий. */
.live-box { margin-top: 8px; }
.live-head {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-bottom: 8px;
    font-size: 13px;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
}
@keyframes typing-pulse {
    0%, 100% { opacity: .3; transform: scale(.85); }
    50% { opacity: 1; transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
    .typing-pulse { animation: none; opacity: .6; }
}
/* «Показать более раннее»: диалог открывается последними 50 сообщениями. */
.load-more { display: flex; justify-content: center; padding: 6px 0 12px; }
.load-more button {
    border: 1px solid var(--border); background: transparent; color: var(--text-dim);
    border-radius: 999px; padding: 5px 14px; font-size: 12px; cursor: pointer;
}
.load-more button:hover:not(:disabled) { color: var(--text); border-color: var(--accent); }
.load-more button:disabled { opacity: .6; cursor: default; }

.msg-body { max-width: 88%; }
/* pre-wrap здесь больше не нужен: переносы строк расставляет сама разметка
   (<p> и <br>), а с ним абзацы и списки получали бы вдобавок пустые строки
   исходника. Остаётся он только внутри <pre>, где отступы значимы. */
.msg-text { word-wrap: break-word; }
.msg-text > :first-child { margin-top: 0; }
.msg-text > :last-child { margin-bottom: 0; }
.msg-text p { margin: 0 0 10px; }
.msg-text h1, .msg-text h2, .msg-text h3,
.msg-text h4, .msg-text h5, .msg-text h6 {
    margin: 16px 0 8px; line-height: 1.3; font-weight: 600;
}
/* Заголовки в пузыре сообщения, а не на странице: h1 в 32 px рядом с текстом
   в 14 px выглядит криком. Разница между уровнями оставлена заметной — по ней
   и читается структура длинного ответа. */
.msg-text h1 { font-size: 20px; }
.msg-text h2 { font-size: 17px; }
.msg-text h3 { font-size: 15px; }
.msg-text h4, .msg-text h5, .msg-text h6 { font-size: 14px; opacity: .85; }
.msg-text ul, .msg-text ol { margin: 0 0 10px; padding-left: 22px; }
.msg-text li { margin: 3px 0; }
.msg-text li > ul, .msg-text li > ol { margin: 3px 0 0; }
.msg-text blockquote {
    margin: 0 0 10px; padding: 2px 0 2px 12px;
    border-left: 3px solid var(--border); opacity: .85;
}
.msg-text hr { border: 0; border-top: 1px solid var(--border); margin: 14px 0; }
.msg-text code { background: rgba(127, 127, 127, .18); padding: 1px 5px; border-radius: 5px; font-size: 13px; }
.msg-text pre { background: rgba(127, 127, 127, .14); padding: 10px 12px; border-radius: 9px; overflow-x: auto; margin: 0 0 10px; white-space: pre; }
.msg-text pre code { background: transparent; padding: 0; }
/* Таблица шире пузыря — обычное дело, поэтому она прокручивается внутри
   сообщения, а не растягивает переписку по горизонтали. */
.msg-text table { border-collapse: collapse; margin: 0 0 10px; font-size: 13px; display: block; overflow-x: auto; max-width: 100%; }
.msg-text th, .msg-text td { border: 1px solid var(--border); padding: 4px 9px; text-align: left; vertical-align: top; }
.msg-text th { background: rgba(127, 127, 127, .12); font-weight: 600; }
.msg.user .msg-text blockquote { border-left-color: rgba(255, 255, 255, .5); }
.msg.user .msg-text th, .msg.user .msg-text td { border-color: rgba(255, 255, 255, .35); }
.msg.user .msg-text hr { border-top-color: rgba(255, 255, 255, .35); }

/* Ссылка в переписке. Цвет ссылки (`--accent`) и цвет своего пузыря
   (`--bubble-user`) — это одно и то же значение, поэтому ссылка в собственном
   сообщении была не «плохо заметна», а невидима буквально: синим по синему.
   Внутри пузыря красим по цвету его текста, подчёркивание — обеим сторонам:
   в чужом пузыре ссылка отличается от текста только оттенком. */
.msg-text a { text-decoration: underline; text-underline-offset: 2px; }
.msg.user .msg-text a { color: var(--bubble-user-text); }
.msg-meta { margin-top: 6px; font-size: 11px; opacity: .65; display: flex; gap: 10px; align-items: center; }

/* Лайк и копирование под ответом. Держим их в мете, а не отдельной строкой:
   пузырь и так высокий, лишний ряд сдвигал бы переписку вниз. */
.msg-actions { display: flex; gap: 4px; margin-left: auto; }
.msg-act {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 7px; border: 0; border-radius: 999px;
    background: transparent; color: inherit; cursor: pointer;
    font: inherit; font-size: 11px; line-height: 1.6;
}
.msg-act:hover { background: var(--bg-hover); }
.msg-act[disabled] { opacity: .5; cursor: default; }
.msg-act.on { color: var(--danger); opacity: 1; }
.msg-act.done { color: var(--ok); opacity: 1; }
.msg-act-icon { font-size: 13px; line-height: 1; }

/* Кнопка у выделенного куска сообщения. Плавает над страницей: место ей
   задаёт само выделение, а не раскладка. */
.quote-pop {
    position: absolute; z-index: 60;
    padding: 4px 10px; border: 0; border-radius: 999px;
    background: var(--accent, #2f6fed); color: var(--on-accent); cursor: pointer;
    font: inherit; font-size: 12px; line-height: 1.4;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .25);
}
.quote-pop[hidden] { display: none; }

/* Заявка на право под ответом-отказом (пункт 229/Э2): своя строка на
   ресурс, кнопка сменяется текстом состояния после нажатия. */
.msg-grant-requests { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.msg-grant-request { font-size: 12px; }
.msg-grant-request .msg-act { padding-left: 0; }

.msg-atts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.msg-att-open { display: block; text-decoration: none; color: inherit; }
/* Картинка показывается во всю ширину сообщения, а не миниатюрой в 320 px:
   схемы и слайды в маленьком виде нечитаемы, а именно ради них сюда и ходят —
   человеку приходилось открывать каждую в новой вкладке. Высоту не режем:
   обрезанный по высоте лист выглядит как испорченный.

   Правило было, но не работало: `max-width: 320px` стоял в отдельном объявлении
   `.msg-att-pic` выше по файлу, и `width: 100%` его не отменял — ширину режет
   max-width, кто бы её ни задал. Держим оба свойства в одном месте, чтобы
   следующая правка не разъехалась так же. `flex: 1 0 100%` — потому что
   `.msg-atts` это flex-строка: без него картинка ужимается по содержимому и
   встаёт в ряд с соседним вложением. */
.msg-att-pic { display: block; width: 100%; max-width: 100%; flex: 1 0 100%; color: inherit; }
.msg-att-img { width: 100%; max-width: 100%; height: auto; border-radius: 10px; display: block; cursor: zoom-in; border: 1px solid var(--border); }
.att-origin { font-size: 11px; opacity: .6; margin-top: 4px; line-height: 1.4; }
.msg.user .att-origin { color: var(--bubble-user-text); opacity: .75; }
/* Схемы и иконки почти всегда рисуются чёрным по прозрачному: на тёмной теме
   без подложки от них остаётся пустой прямоугольник. */
.msg-att-img.is-svg { background: #fff; padding: 8px; object-fit: contain; }
.att-cap { display: flex; align-items: baseline; gap: 8px; font-size: 12px; margin-top: 4px; }
.att-cap-name { opacity: .7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att-cap .att-size { opacity: .55; }
.att-dl { margin-left: auto; white-space: nowrap; color: var(--accent, #2f6fed); text-decoration: none; border-bottom: 1px dashed currentColor; }
.att-dl:hover { opacity: .8; }
.msg.user .att-cap { color: var(--bubble-user-text); }
.msg.user .att-dl { color: var(--bubble-user-text); }
.msg-att-file {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 7px 10px;
    color: var(--text);
    text-decoration: none;
    font-size: 13px;
    max-width: 260px;
}
.msg.user .msg-att-file { background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .28); color: var(--bubble-user-text); }
.att-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.att-size { opacity: .7; font-size: 12px; white-space: nowrap; }

/* --- Деградация на запасной канал -------------------------------------- */
/* Предупреждение, а не ошибка: ответ всё-таки будет. Поэтому янтарный, а не
   красный, и без иконки-«стопа». */
.degraded-note {
    border: 1px solid rgba(200, 140, 0, .45);
    background: rgba(255, 176, 32, .10);
    border-radius: 10px;
    padding: 8px 11px;
    font-size: 13px;
    line-height: 1.45;
}
.degraded-head { display: flex; gap: 7px; align-items: baseline; font-weight: 600; }
.degraded-icon { flex: none; }
.degraded-list { margin: 5px 0 0; padding-left: 26px; }
.degraded-list li { margin: 1px 0; }
.msg .degraded-note { margin-top: 10px; }
.typing-degraded { margin-top: 8px; }
.brain-banner { max-width: 780px; margin: 0 auto; padding: 10px 18px 0; }

/* --- Информер способностей (пункт ДИСПИНФ) ------------------------------ */
/* Тот же янтарный тон, что у деградации: предупреждение, а не ошибка — часть
   сервиса недоступна, остальное работает как обычно. */
.capability-banner { padding: 0 14px 8px; display: flex; flex-direction: column; gap: 6px; }
.capability-note {
    border: 1px solid rgba(200, 140, 0, .45);
    background: rgba(255, 176, 32, .10);
    border-radius: 8px;
    padding: 6px 10px;
    font-size: 12.5px;
    line-height: 1.4;
}

/* --- Поле ввода -------------------------------------------------------- */
.composer { border-top: 1px solid var(--border); background: var(--bg-panel); padding: 10px 18px 14px; }
.composer-row { max-width: 780px; margin: 0 auto; display: flex; gap: 8px; align-items: flex-end; }
/* Потолок роста поля живёт ТОЛЬКО здесь: `app.js` читает его из вычисленных
   стилей. Прежде число стояло в трёх местах и уже разъехалось (220 и 240).
   Строка с `vh` идёт впереди запасной: браузеру без `dvh` достаётся она, а на
   телефоне «сто процентов высоты» включают адресную строку — та же грабля, что
   чинилась у `.layout`. */
.composer textarea {
    resize: none;
    min-height: 42px;
    max-height: 80vh;
    max-height: 80dvh;
}
.send-btn { height: 42px; }
.attach-btn { height: 42px; width: 42px; font-size: 17px; border: 1px solid var(--border); }
.composer-hint { max-width: 780px; margin: 6px auto 0; font-size: 12px; color: var(--text-dim); opacity: .8; }
.composer-note { max-width: 780px; margin: 6px auto 0; font-size: 12px; color: var(--text-dim); min-height: 16px; }
.composer-note.error { color: var(--danger); }
/* Кнопка «Повторить» в строке под полем ввода: рядом с сообщением о сбое, а не
   отдельным блоком — сбой и способ его исправить читаются одной строкой. */
.note-retry {
    margin-left: 8px; padding: 1px 8px; font: inherit; font-size: 12px; line-height: 1.6;
    color: var(--text); background: var(--bg-soft);
    border: 1px solid var(--border); border-radius: 999px; cursor: pointer;
}
.note-retry:hover { background: var(--bg-hover); }
.note-retry[disabled] { opacity: .6; cursor: default; }

.attach-strip { max-width: 780px; margin: 0 auto 8px; display: flex; flex-wrap: wrap; gap: 8px; }

/* Сторож NDA над полем ввода. Обычное состояние — спокойная серая строка о том,
   что файлы проверяются; снятая галочка красит блок в красное. Красный здесь не
   украшение: отключённое обезличивание — разовое исключение под ответственность
   человека, и выглядеть как обычная настройка оно не должно. */
.anon-row {
    max-width: 780px;
    margin: 0 auto 8px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    font-size: 12px;
    color: var(--text-dim);
}
/* Предупреждение режима наблюдения. Не красное: красный в этой строке занят
   отказом от защиты по решению человека, а здесь человек ни при чём — это
   состояние сервиса, о котором его честно предупреждают. */
.anon-watch { color: var(--warn, #b26a00); }
.anon-off { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; color: var(--danger); }
.anon-off input { accent-color: var(--danger); margin: 0; cursor: pointer; }
.anon-row.off {
    border: 1px dashed var(--danger);
    border-radius: 8px;
    padding: 6px 10px;
    color: var(--danger);
}
.anon-row.off .anon-off { font-weight: 600; }
.attach-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 6px 8px;
    font-size: 13px;
    max-width: 240px;
}
.attach-chip img { width: 28px; height: 28px; object-fit: cover; border-radius: 6px; }
.attach-chip button { border: 0; background: transparent; color: var(--text-dim); cursor: pointer; font-size: 15px; }
.attach-chip.pending { opacity: .6; }

.drop-overlay {
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--accent) 12%, var(--bg));
    border: 2px dashed var(--accent);
    border-radius: 12px;
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    color: var(--accent);
    z-index: 15;
    pointer-events: none;
}
.drop-overlay.on { display: flex; }

/* --- Вход -------------------------------------------------------------- */
.login-wrap { min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.login-card {
    width: 100%;
    max-width: 400px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 28px;
    box-shadow: var(--shadow);
}
.login-logo { display: flex; align-items: center; gap: 10px; font-size: 20px; font-weight: 650; }
/* Слоган под названием: тонкий и приглушённый, чтобы читался как подпись,
   а не как второй заголовок. */
.logo-text { display: inline-flex; flex-direction: column; line-height: 1.15; }
.logo-slogan { font-size: 11px; font-weight: 400; letter-spacing: 0; color: var(--text-dim); opacity: .85; white-space: nowrap; }
/* Метка «beta»: красная и мелкая. Красный здесь не для тревоги, а чтобы её
   было видно, — она предупреждает, а не украшает. Прижата к верху строки,
   как надстрочный знак у названия. */
.logo-beta {
    /* Шапка — flex с зазором 14px; метке такой зазор ни к чему, она должна
       читаться как надстрочный знак у названия, а не как отдельный пункт. */
    align-self: center;
    margin: -8px 0 0 -10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: lowercase;
    color: var(--danger, #d64545);
    cursor: help;
}
.logo-beta:focus-visible { outline: 2px solid var(--danger, #d64545); outline-offset: 2px; border-radius: 3px; }
.login-logo .logo-slogan { font-size: 12px; }
.empty-slogan { font-size: 13px; color: var(--text-dim); opacity: .85; margin: -4px 0 10px; }
.login-lead { color: var(--text-dim); font-size: 14px; margin: 12px 0 20px; }
.field { display: block; margin-bottom: 14px; }
.field span { display: block; font-size: 13px; color: var(--text-dim); margin-bottom: 5px; }
#login-form .btn-primary, #login-form .btn-quiet { width: 100%; margin-top: 4px; }
.form-note { font-size: 12px; color: var(--text-dim); margin: 14px 0 0; min-height: 16px; }
.form-note.error { color: var(--danger); }
.form-note.ok { color: var(--ok); }

/* --- Статистика -------------------------------------------------------- */

.tabs { display: flex; gap: 6px; margin: 18px 0 20px; border-bottom: 1px solid var(--border); }
.tab {
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--text-dim);
    padding: 9px 14px;
    font-size: 14px;
    cursor: pointer;
}
.tab.active { color: var(--text); border-bottom-color: var(--accent); font-weight: 550; }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 12px; }
.card {
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 14px;
}
.card-label { font-size: 12px; color: var(--text-dim); }
.card-value { font-size: 22px; font-weight: 650; margin-top: 4px; font-variant-numeric: tabular-nums; }
.card-sub { font-size: 12px; color: var(--text-dim); margin-top: 3px; }

.section-title { font-size: 15px; font-weight: 600; margin: 26px 0 10px; }

.bars { display: flex; align-items: flex-end; gap: 3px; height: 130px; padding: 8px 10px; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; }
.bar { flex: 1; background: var(--accent); border-radius: 3px 3px 0 0; min-height: 2px; opacity: .85; }
.bar:hover { opacity: 1; }
.bars-legend { display: flex; justify-content: space-between; font-size: 11px; color: var(--text-dim); margin-top: 6px; }
/* «Цена по тарифам API» (docs/09): столбик дня из двух частей — точная
   (сплошная) и оценка (бледная со штриховкой), чтобы досчёт прошлого не
   читался как замер. */
.bars-api-equiv { gap: 1px; }
.bar-stack { flex: 1; display: flex; flex-direction: column; min-width: 1px; border-radius: 3px 3px 0 0; overflow: hidden; }
.bar-part { flex-basis: 0; min-height: 1px; }
.bar-exact { background: var(--accent); opacity: .85; }
.bar-est { background: repeating-linear-gradient(135deg, var(--accent) 0 3px, transparent 3px 6px); opacity: .45; }
.bar-stack:hover .bar-exact { opacity: 1; }
.bar-stack:hover .bar-est { opacity: .65; }
.api-equiv-key::before { content: ''; display: inline-block; width: 10px; height: 10px; margin-right: 5px; vertical-align: -1px; border-radius: 2px; }
.api-equiv-key-exact::before { background: var(--accent); opacity: .85; }
.api-equiv-key-est::before { background: repeating-linear-gradient(135deg, var(--accent) 0 2px, transparent 2px 4px); opacity: .6; }
/* График времени ответа: две линии на одной шкале. Столбиками это было парами
   рядом, и сравнение приходилось делать глазами; на общей шкале расхождение
   медианы и среднего видно сразу. */
.chart-box { background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; padding: 8px 10px; }
.answer-chart { display: block; width: 100%; height: auto; }
.chart-grid { stroke: var(--border); stroke-width: 1; }
.chart-tick { fill: var(--text-dim); font-size: 10px; }
.chart-line { stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
/* Заливку сериям (polyline) не давать нигде: класс серии задаёт только stroke,
   fill для точек — отдельным правилом на .chart-dot. Так полилиния не красится
   как замкнутый многоугольник (SVG иначе соединяет последнюю точку с первой). */
.chart-med { stroke: var(--accent); }
.chart-avg { stroke: var(--accent-2, #e07b39); }
.chart-dot.chart-med { fill: var(--accent); }
.chart-dot.chart-avg { fill: var(--accent-2, #e07b39); }
.bars-key { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.bars-key-med { color: var(--accent); font-weight: 500; }
.bars-key-avg { color: var(--accent-2, #e07b39); font-weight: 500; }

/* График вовлечения: три линии, у каждой свой цвет и своя (независимая) шкала —
   числа разного порядка величины иначе легли бы плоскими чертами по низу. */
.chart-eng-active { stroke: var(--accent); }
.chart-eng-messages { stroke: var(--ok, #2f9e63); }
.chart-eng-chats { stroke: var(--accent-3, #8a63d2); }
.chart-dot.chart-eng-active { fill: var(--accent); }
.chart-dot.chart-eng-messages { fill: var(--ok, #2f9e63); }
.chart-dot.chart-eng-chats { fill: var(--accent-3, #8a63d2); }
.chart-eng-key { color: var(--text-dim); font-weight: 500; }
.chart-eng-key.chart-eng-active { color: var(--accent); }
.chart-eng-key.chart-eng-messages { color: var(--ok, #2f9e63); }
.chart-eng-key.chart-eng-chats { color: var(--accent-3, #8a63d2); }

/* График расхода токенов по дням: вход/выход на одной общей шкале — числа
   одного порядка величины, в отличие от вовлечения. */
.chart-tok-in { stroke: var(--accent); }
.chart-tok-out { stroke: var(--accent-2, #e07b39); }
.chart-dot.chart-tok-in { fill: var(--accent); }
.chart-dot.chart-tok-out { fill: var(--accent-2, #e07b39); }
.chart-tok-key { color: var(--text-dim); font-weight: 500; }
.chart-tok-key.chart-tok-in { color: var(--accent); }
.chart-tok-key.chart-tok-out { color: var(--accent-2, #e07b39); }

/* Переключатель периода графиков — один на весь блок. */
.period-switch { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }
.period-btn { padding: 5px 12px; border: 1px solid var(--border); border-radius: 999px; background: var(--bg-panel); color: var(--text-dim); font-size: 12px; cursor: pointer; }
.period-btn:hover { color: var(--text); }
.period-btn.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Активность сотрудников — горизонтальные столбцы: имя, полоса, число. */
.hbars { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; }
.hbars-row { display: grid; grid-template-columns: minmax(90px, 160px) 1fr auto; gap: 8px; align-items: center; }
.hbars-label { font-size: 12px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbars-bar { flex: 1; }
.hbars-val { font-size: 12px; color: var(--text-dim); min-width: 32px; text-align: right; }

/* сетка «день недели × час»: колонка подписей + 24 равные колонки часов */
.heat { display: grid; grid-template-columns: auto repeat(24, 1fr); gap: 2px; padding: 10px; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; min-width: 460px; }
.heat-corner, .heat-hour, .heat-day { font-size: 10px; color: var(--text-dim); white-space: nowrap; }
.heat-hour { text-align: center; }
.heat-day { padding-right: 6px; line-height: 16px; }
.heat-cell { height: 16px; border-radius: 3px; background: var(--accent); }
.heat-cell.empty { background: var(--bg-soft); }
.heat-cell:hover { outline: 1px solid var(--text-dim); }

table.data { width: 100%; border-collapse: collapse; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
table.data th, table.data td { padding: 9px 12px; text-align: left; font-size: 13px; border-bottom: 1px solid var(--border); }
table.data th { color: var(--text-dim); font-weight: 500; background: var(--bg-soft); }
table.data tr:last-child td { border-bottom: 0; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tr.row-total td { background: var(--bg-soft); font-weight: 600; }
/* «Чистильщик» (пункт 209): строка подозрительного задания/сессии — тот же
   тревожный цвет, что у прочих плохих показателей на этой странице. */
table.data tr.health-bad td { color: var(--danger); }
/* Прокрутка вбок остаётся страховкой (телефон, чужой шрифт), но на компьютере
   таблица обязана укладываться в экран при любых данных: числа не переносятся,
   а длинное название или ФИО в первой колонке обрезается многоточием. Иначе
   ширину блока задаёт самая длинная строка боевой выгрузки, и прокрутка
   возвращается сама. */
.table-scroll { overflow-x: auto; }
table.data td.num, table.data th.num { white-space: nowrap; }
table.data tbody td:first-child {
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.mini-bar { height: 5px; background: var(--bg-soft); border-radius: 999px; overflow: hidden; min-width: 60px; }
.mini-bar i { display: block; height: 100%; background: var(--accent); }
.loading { color: var(--text-dim); padding: 20px 0; }

/* --- Адаптив ----------------------------------------------------------- */
.sidebar-toggle { display: none; }

@media (max-width: 860px) {
    .layout { grid-template-columns: 1fr; }
    .sidebar {
        position: fixed;
        top: 52px;
        bottom: 0;
        left: 0;
        width: 84vw;
        max-width: 320px;
        z-index: 30;
        transform: translateX(-102%);
        transition: transform .2s;
        box-shadow: var(--shadow);
    }
    .sidebar.open { transform: none; }
    .sidebar-toggle { display: inline-block; }
    .msg-body { max-width: 94%; }
}

/* Затемнение под выехавшим списком. Живёт только на узком экране: на ноутбуке
   список стоит на своём месте и затемнять нечего. */
.sidebar-back {
    position: fixed;
    top: 52px;
    inset-inline: 0;
    bottom: 0;
    z-index: 29;
    background: rgba(16, 20, 34, .38);
}

/* --- Телефон ------------------------------------------------------------
   Обещания раздела docs/28-na-telefone.md. Правится здесь только то, что на
   узком экране меняет дело: место под переписку, поле ввода и цели касания.
   Настольная раскладка не трогается — она владельца устраивает. */
@media (max-width: 620px) {
    /* Место отдаётся переписке: поля по краям и ширина пузыря. */
    .messages { padding: 14px 10px 6px; }
    .composer { padding: 8px 10px 10px; }
    .msg { gap: 6px; margin-bottom: 12px; }
    .msg-body { max-width: 100%; }

    /* Шапка диалога: настройки разговора переезжают во вторую строку целиком.
       Прятать их нельзя — настройка, которой не видно, равносильна её
       отсутствию. */
    .chat-header { flex-wrap: wrap; gap: 8px; padding: 8px 10px; }
    .chat-settings { flex: 1 1 100%; margin-left: 0; gap: 10px; }
    .chat-settings .model-pick { margin-left: 0; }
    .context-meter { min-width: 0; flex: 1 1 auto; }
    .model-pick select { max-width: 108px; }

    /* Поле ввода не мельче 16 px: мобильный Safari увеличивает страницу при
       вводе в поле с меньшим шрифтом и обратно её не уменьшает. */
    .chat-search, .field input, .composer textarea,
    .access-rules-input { font-size: 16px; }

    /* Цели касания: мышью удобно попадать и в 32 px, пальцем — нет. */
    .icon-btn { width: 38px; height: 38px; }
    .attach-btn, .send-btn, .composer textarea { min-height: 44px; }
}

/* --- Окно «О сервисе» --------------------------------------------------- */
.modal-back {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(16, 20, 34, .45);
}
.modal {
    display: flex;
    flex-direction: column;
    width: min(760px, 100%);
    max-height: min(86vh, 900px);
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    outline: none;
}
.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
}
.modal-title { margin: 0; font-size: 17px; font-weight: 650; }
.modal-body { overflow: auto; padding: 16px 20px 22px; }

.about-lead { margin: 0 0 4px; color: var(--text-dim); }
.about-lead b { color: var(--text); }
.about-h {
    margin: 22px 0 10px;
    font-size: 13px;
    font-weight: 650;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-dim);
}
.about-list { margin: 0; padding: 0 0 0 26px; }
.about-list li { margin: 0 0 12px; color: var(--text-dim); }
.about-list li::marker { color: var(--accent); font-weight: 650; }
.about-list b { display: block; color: var(--text); font-weight: 600; }
.about-notes { margin: 0; padding: 0 0 0 20px; color: var(--text-dim); font-size: 14px; }
.about-notes li { margin: 0 0 7px; }
.about-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; }

@media (max-width: 860px) {
    .modal-back { padding: 0; }
    .modal { max-height: 100%; height: 100%; border: 0; border-radius: 0; }
}

/* Блок «новое»: отделён от привычных возможностей не потому, что недоделан, а
   потому, что непривычен — черновик под полем ввода легко принять за ответ, и
   предупредить об этом важнее, чем украсить. Та же пунктирная рамка, что и у
   самого черновика: человек узнаёт блок, увидев его в работе. */
.about-new {
    border: 1px dashed var(--border);
    border-left: 3px solid var(--warn);
    border-radius: 10px;
    padding: 12px 14px;
    background: var(--bg-soft);
    color: var(--text-dim);
}
.about-new b { display: block; color: var(--text); font-weight: 600; margin-bottom: 3px; }
/* --- Предответ: черновик по недописанному вопросу ------------------------
   Оформление здесь несёт смысл, а не вид: догадка по началу фразы обязана
   выглядеть непохоже на ответ. Пунктир, приглушённый цвет, моноширинный
   заголовок — всё для того, чтобы её нельзя было прочесть как готовый ответ
   и унести с собой. */
.pre-answer {
    margin: 0 16px 8px;
    padding: 8px 12px;
    border: 1px dashed var(--border);
    border-radius: 8px;
    background: transparent;
    color: var(--text-dim);
    font-size: 13px;
    line-height: 1.45;
    max-height: 190px;
    overflow-y: auto;
    opacity: .85;
}
.pre-answer .pre-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
}
.pre-answer .pre-title {
    font-size: 11px;
    letter-spacing: .04em;
    text-transform: uppercase;
    opacity: .8;
}
.pre-answer .pre-hide {
    border: 0;
    background: none;
    color: inherit;
    font-size: 11px;
    cursor: pointer;
    opacity: .7;
    padding: 0;
}
.pre-answer .pre-hide:hover { opacity: 1; text-decoration: underline; }
.pre-answer .pre-body { white-space: pre-wrap; }
/* Пока считается — заголовок дышит; переписывается вопрос — весь блок гаснет. */
.pre-answer.working .pre-title { animation: pre-breathe 1.6s ease-in-out infinite; }
.pre-answer.stale { opacity: .4; }
@keyframes pre-breathe { 0%, 100% { opacity: .45; } 50% { opacity: .95; } }

/* Строка о прогретых каналах: то же оформление, что и у сводки очереди рядом,
   но приглушённее — это состояние машины, а не работа человека. */
.brain-line { color: var(--text-dim); font-size: 12px; }

/* --- здоровье сервера (общая вкладка статистики) ----------------------------
   Плитки, а не таблица: показателей мало, и каждый читается сам по себе. Цвет
   несёт смысл — по нему видно «всё хорошо / присмотреться / плохо» до чтения
   цифр, — но цветом дело не ограничивается: значение и подпись говорят то же
   словами, иначе блок был бы бесполезен тем, кто цвета не различает. */
.health-block { margin-top: 22px; }

.health-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
}

.health-cell {
    border: 1px solid var(--border);
    border-left-width: 3px;
    border-radius: 8px;
    padding: 10px 12px;
}

.health-cell.ok   { border-left-color: var(--ok); }
.health-cell.warn { border-left-color: var(--warn); }
.health-cell.bad  { border-left-color: var(--danger); }

.health-label { color: var(--text-dim); font-size: 12px; }
.health-value { font-size: 18px; font-weight: 600; margin-top: 2px; }
.health-sub   { color: var(--text-dim); font-size: 12px; margin-top: 2px; }

/* Строка машины «мозга» (BACKLOG 347): подпись над её плитками. Молчащая
   машина остаётся строкой, а не исчезает — «нет пульса» словами и цветом. */
.health-machine {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
    margin: 12px 0 6px;
}
.health-machine-name { font-weight: 600; }
.health-machine-dead { color: var(--danger); font-size: 13px; }

.health-probs { margin-top: 12px; }
.health-ok    { color: var(--text-dim); font-size: 13px; }

.health-prob {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 8px 0;
    border-top: 1px solid var(--border);
}

.health-prob-title { font-size: 14px; font-weight: 600; }

.health-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--danger);
    margin-top: 6px;
    flex: none;
}

/* --- окно просмотра вложения ------------------------------------------------
   Шире окна «О сервисе» (1040 против 760): здесь читают статью и смотрят
   таблицу, а узкая колонка с таблицей на десяток столбцов бесполезна. */
.viewer-back {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(16, 20, 34, .55);
}
.viewer {
    display: flex;
    flex-direction: column;
    width: min(1040px, 100%);
    height: min(88vh, 1000px);
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    outline: none;
}
.viewer-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 10px 16px;
    border-bottom: 1px solid var(--border);
}
.viewer-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-size { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.viewer-dl { margin-left: auto; }
.viewer-note {
    padding: 8px 16px;
    font-size: 12px;
    color: var(--text-dim);
    border-bottom: 1px solid var(--border);
}
.viewer-body { flex: 1; overflow: auto; padding: 18px 22px; }
.viewer-loading, .viewer-empty { color: var(--text-dim); padding: 30px 0; text-align: center; }
.viewer-more { margin-top: 10px; font-size: 12px; color: var(--text-dim); }
/* Текст статьи читают глазами, а не сканируют: колонка ограничена по ширине,
   иначе строка на 1000 px теряется при переходе на следующую. */
.viewer-md { max-width: 760px; }
.viewer-img { max-width: 100%; height: auto; display: block; margin: 0 auto; }
.viewer-frame { width: 100%; height: 100%; min-height: 60vh; border: 0; }
.viewer-media { width: 100%; }
.viewer-code {
    background: rgba(127, 127, 127, .12);
    padding: 14px 16px;
    border-radius: 9px;
    overflow-x: auto;
    font-size: 13px;
    line-height: 1.55;
    margin: 0;
    white-space: pre;
}
.viewer-table { overflow-x: auto; }
.viewer-table table { border-collapse: collapse; font-size: 13px; }
.viewer-table th, .viewer-table td {
    border: 1px solid var(--border);
    padding: 5px 10px;
    text-align: left;
    vertical-align: top;
    white-space: nowrap;
}
.viewer-table th { background: rgba(127, 127, 127, .12); font-weight: 600; position: sticky; top: 0; }

/* Скачивание с выбором формата. Меню, а не ряд кнопок: форматов до пяти, и
   в шапке они не помещаются, а объяснить, чем .docx лучше .md, всё равно надо. */
.dl-menu { position: relative; }
.dl-btn {
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text);
    border-radius: 999px;
    padding: 5px 14px;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    white-space: nowrap;
}
.dl-btn:hover { border-color: var(--accent); }
.dl-list {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 5;
    min-width: 260px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: var(--shadow);
    overflow: hidden;
}
.dl-item {
    display: block;
    padding: 8px 14px;
    text-decoration: none;
    color: inherit;
    border-bottom: 1px solid var(--border);
}
.dl-item:last-child { border-bottom: 0; }
.dl-item:hover { background: var(--bg-hover); }
.dl-item-name { display: block; font-size: 13px; }
.dl-item-hint { display: block; font-size: 11px; color: var(--text-dim); margin-top: 2px; }

.att-view { margin-left: auto; font-size: 11px; opacity: .7; }
.msg-att-file:hover .att-view { opacity: 1; color: var(--accent); }

@media (max-width: 720px) {
    .viewer-back { padding: 0; }
    .viewer { height: 100%; border: 0; border-radius: 0; }
    .viewer-body { padding: 14px; }
}

/* Печать окна просмотра — штатный путь к PDF: своего генератора PDF на
   хостинге нет и быть не может, а браузер печатает в файл сам. Печатается
   только содержимое окна, всё остальное со страницы убирается. */
@media print {
    body > *:not(.viewer-back) { display: none !important; }
    .viewer-back { position: static; padding: 0; background: none; display: block; }
    .viewer { width: auto; height: auto; max-height: none; border: 0; box-shadow: none; }
    .viewer-head, .viewer-note { display: none; }
    .viewer-body { overflow: visible; padding: 0; }
    .viewer-md { max-width: none; }
    .viewer-table th, .viewer-table td { white-space: normal; }
}
.viewer-pdf { display: flex; flex-direction: column; height: 100%; }
.viewer-pdf .viewer-frame { flex: 1; }

/* Выбор модели в шапке диалога. Стоит слева от счётчика контекста: это
   настройка разговора, а не действие над ним, поэтому не кнопка. */
.model-pick { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.model-pick-label { font-size: 11px; color: var(--text-dim); }
.model-pick select {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 8px;
    font: inherit;
    font-size: 12px;
    cursor: pointer;
    max-width: 130px;
}
.model-pick select:hover { border-color: var(--accent); }
.model-pick select option { background: var(--bg-panel); color: var(--text); }
@media (max-width: 720px) {
    .model-pick-label { display: none; }
    .model-pick select { max-width: 120px; }
}

/* --- «Права и навыки» --------------------------------------------------- */
/* Пользуется той же рамкой, что и статистика (.stats-wrap): это соседние
   экраны «про меня в сервисе», и разъезжаться им незачем. */


.access-kind {
    font-size: 15px;
    margin: 22px 0 8px;
    color: var(--text-dim);
    font-weight: 600;
}

.access-list {
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.access-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
}

.access-row:last-child { border-bottom: none; }

.access-mark {
    flex: 0 0 22px;
    text-align: center;
    font-size: 15px;
    line-height: 1.5;
}

.access-row.on  .access-mark { color: var(--ok); }
.access-row.off .access-mark,
.access-row.absent .access-mark,
.access-row.planned .access-mark { color: var(--text-dim); }

/* Выключенное и задуманное приглушаем, но не прячем: человек должен видеть,
   что такая возможность у сервиса есть, и понимать, чего именно у него нет. */
.access-row.off .access-title,
.access-row.absent .access-title,
.access-row.planned .access-title { color: var(--text-dim); }

/* «Вместо этого: …» — половина смысла строки «Не умеет»: отказ без ближайшего
   возможного отправляет человека решать задачу самому. */
.access-instead { font-size: 13px; margin-top: 3px; line-height: 1.45; color: var(--text); }

/* Пункт 113: право открыто, а клиента на машине «мозга» нет. Цвет тревоги —
   это не «не умеет» и не «в разработке», а расхождение, которое надо чинить. */
.access-daemon-note { font-size: 13px; margin-top: 3px; line-height: 1.45; color: var(--warn); }

/* Правила работы с ресурсом — тот же текст, что уезжает модели. Свёрнуто по
   умолчанию: у иного права правил на страницу, и развёрнутыми они превратили бы
   каталог в простыню. Текст показывается как есть, поэтому моноширинно и с
   переносом по словам — в нём живут команды и имена полей. */
.access-rules { margin-top: 10px; }
.access-rules-head {
    cursor: pointer;
    font-size: 13px;
    color: var(--text-dim);
    user-select: none;
}
.access-rules-head:hover { color: var(--text); }
.access-rules-label { font-size: 12px; color: var(--text-dim); margin-top: 8px; }
.access-rules-text {
    margin: 4px 0 0;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg-soft);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-word;
    overflow-x: auto;
}
/* Правку не выдаём за написанное в коде: строка стоит под текстом, а не в
   подсказке к нему. */
.access-rules-edited:not(:empty) {
    margin-top: 6px;
    font-size: 12px;
    color: var(--text-dim);
}
/* Правка правил — только у администратора, поэтому отделена рамкой сверху:
   выше показ, ниже действие. */
.access-rules-edit {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px dashed var(--border);
}
.access-rules-sub { font-size: 12px; color: var(--text-dim); margin-top: 6px; }
.access-rules-input {
    width: 100%;
    min-height: 70px;
    margin-top: 4px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    line-height: 1.5;
    resize: vertical;
}
.access-rules-actions { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.access-rules-state { margin-top: 6px; font-size: 12px; color: var(--text-dim); }
.access-rules-state.bad { color: var(--danger, #c33); }

/* Личный ключ к внешней системе (свой вебхук Б24). Поле живёт внутри строки
   права, а не отдельным экраном: ключ без права не нужен, а право без ключа не
   работает — человек должен видеть их рядом. */
.access-secret {
    margin-top: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-soft);
}
.access-secret-title { font-weight: 600; font-size: 13px; }
.access-secret-hint { color: var(--text-dim); font-size: 12px; margin-top: 3px; line-height: 1.45; }
.access-secret-steps { color: var(--text-dim); font-size: 12px; line-height: 1.5; margin: 8px 0 0; padding-left: 20px; }
.access-secret-steps li { margin-bottom: 5px; }
.access-secret-steps li:last-child { margin-bottom: 0; }
/* Как завести доступ — свёрнуто: шаги видны всем, но каталог прав они бы
   превратили в простыню. */
.access-steps { margin-top: 8px; }
.access-steps > summary { cursor: pointer; font-size: 12px; color: var(--text-dim); }
.access-steps[open] > summary { margin-bottom: 4px; }
.access-secret-redirect {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    margin-top: 8px; font-size: 12px;
}
.access-secret-redirect code {
    background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
    padding: 2px 6px; font-size: 11px; word-break: break-all;
}
/* Подключение согласием: короткий путь стоит ВЫШЕ ручного ввода — им
   пользуется большинство, а три поля остаются для тех, у кого ключ уже есть. */
.access-oauth {
    margin-top: 8px; padding-bottom: 10px;
    border-bottom: 1px dashed var(--border);
    display: grid; gap: 8px;
}
.access-oauth-hint { color: var(--text-dim); font-size: 12px; line-height: 1.45; }
.access-oauth .btn { justify-self: start; }
/* Ручной ввод — под раскрытием: рядом с кнопкой те же два поля шли на экране
   дважды и читались как сбой вёрстки, а не как второй путь. */
.access-secret-manual { margin-top: 8px; }
.access-secret-manual > summary { cursor: pointer; font-size: 12px; color: var(--text-dim); }
.access-secret-manual[open] > summary { margin-bottom: 6px; }
.access-note {
    margin-bottom: 12px; padding: 10px 12px;
    border: 1px solid var(--border); border-radius: 10px;
    background: var(--bg-soft); font-size: 13px;
}
.access-secret-state { font-size: 12px; margin-top: 6px; color: var(--text-dim); }
.access-secret-state.bad { color: var(--danger, #c0392b); }
.access-secret-row { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.access-secret-input {
    flex: 1 1 260px;
    min-width: 0;
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text);
    font-size: 13px;
}
.access-secret-fields { display: grid; gap: 10px; margin-top: 10px; }
.access-secret-field { display: flex; flex-direction: column; gap: 4px; }
.access-secret-label { font-size: 12px; color: var(--text-dim); }
.access-secret-fhint { font-size: 11px; color: var(--text-dim); line-height: 1.45; }
/* Поле ключа шире строки ввода списка: адрес вебхука и refresh-токен длинные,
   а обрезанный конец — ровно та ошибка, которую человек тут и не заметит. */
.access-secret-field .access-secret-input { flex: 1 1 auto; width: 100%; }
.access-secret-drop { margin-top: 6px; font-size: 12px; }
/* Набор записей (пункт 129): список «домен — логин», без паролей. */
.access-secret-entries { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.access-secret-entry-row {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg); font-size: 13px;
}
.access-secret-entry-host { font-weight: 600; }
.access-secret-entry-user { color: var(--text-dim); }
.access-secret-entry-row .access-secret-drop { margin-top: 0; margin-left: auto; }

.access-body { flex: 1 1 auto; min-width: 0; }
.access-title { font-weight: 600; }
.access-about { color: var(--text-dim); font-size: 13px; margin-top: 2px; line-height: 1.45; }

.access-state {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--text-dim);
    background: var(--bg-soft);
    border-radius: 999px;
    padding: 3px 10px;
    white-space: nowrap;
}

.access-row.on .access-state { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%, transparent); }

.access-admin { margin-top: 34px; }

/* Рубильник местного режима для ВСЕГО сервиса (пункт 130) — своя панель над
   таблицей людей, а не строка в ней: решение про сервис целиком, а не про
   одного человека. */
.access-service-switch {
    margin-top: 12px;
    padding: 4px 14px 10px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.access-service-switch .access-card-row { border-top: none; }

.access-grid {
    margin-top: 12px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    /* Столбцов может стать больше, чем помещается: горизонтальная прокрутка
       внутри блока, а не у всей страницы. Вертикальная — тоже внутри: без
       своего прокручиваемого блока закреплённая шапка не закрепляется
       ни к чему. */
    overflow: auto;
    max-height: 70vh;
}

.access-grid-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border);
}

.access-grid-row:last-child { border-bottom: none; }

.access-grid-head {
    font-size: 12px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: .03em;
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--bg-soft);
}

.access-user { font-weight: 600; }
.access-email { font-size: 12px; color: var(--text-dim); }

.switch { display: inline-flex; align-items: center; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.switch-track {
    width: 38px;
    height: 22px;
    border-radius: 999px;
    background: var(--bg-hover);
    border: 1px solid var(--border);
    position: relative;
    transition: background .15s ease;
}

.switch-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--bg-panel);
    box-shadow: 0 1px 2px rgba(20, 25, 45, .25);
    transition: transform .15s ease;
}

.switch input:checked + .switch-track { background: var(--ok); border-color: var(--ok); }
.switch input:checked + .switch-track::after { transform: translateX(16px); }
.switch input:disabled + .switch-track { opacity: .45; cursor: not-allowed; }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-label { margin-left: 10px; font-size: 14px; color: var(--text-dim); }

.access-note {
    margin-top: 12px;
    font-size: 13px;
    color: var(--ok);
}

.access-note.bad { color: var(--danger); }

@media (max-width: 700px) {
    /* Не прячем: значок «✓ / · / ⋯» без подписи читается как украшение, а это
       единственный ответ на вопрос «есть у меня это или нет». */
    .access-state { font-size: 11px; padding: 2px 8px; }
    .access-row { flex-wrap: wrap; }
}

/* Строка на человека с раскрытием — единственный вид «Кому что выдано» на
   любой ширине. Матрицы «человек × право» больше нет: одиннадцать прав не
   помещались в экран ни при какой подгонке колонок. */
.access-cards {
    margin-top: 12px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.access-card { border-bottom: 1px solid var(--border); }
.access-card:last-child { border-bottom: none; }

.access-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 48px;
    padding: 10px 14px;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.access-card-title { flex: 1 1 auto; min-width: 0; }
.access-card-title .access-user,
.access-card-title .access-email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.access-card-count {
    flex: 0 0 auto;
    font-size: 12px;
    color: var(--text-dim);
    background: var(--bg-soft);
    border-radius: 999px;
    padding: 3px 10px;
    white-space: nowrap;
}

.access-card-head::after {
    content: '▾';
    flex: 0 0 auto;
    color: var(--text-dim);
    transition: transform .15s ease;
}

.access-card.is-open .access-card-head::after { transform: rotate(180deg); }

/* На широком экране одиннадцать прав столбиком — это экран прокрутки вниз
   вместо прокрутки вбок. Раскладываем в несколько колонок по месту. */
.access-card-body {
    padding: 0 14px 10px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    column-gap: 24px;
}

.access-card-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 44px;
    border-top: 1px solid var(--border);
}

.access-card-name { font-size: 14px; }

/* Строка советов (BACKLOG 333/Э3) — во всю ширину раскрытой карточки, под
   переключателями прав, а не в их сетке колонок. */
.access-advice {
    grid-column: 1 / -1;
    border-top: 1px solid var(--border);
    padding-top: 8px;
    margin-top: 4px;
}
.access-advice-head { font-size: 13px; color: var(--muted); margin-bottom: 6px; }
.access-advice-item {
    font-size: 14px;
    padding: 6px 0;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.access-advice-item:first-of-type { border-top: none; }
.access-advice-item.tone-bad { color: var(--danger, #c0392b); }
.access-advice-useful { font-size: 12px; color: var(--muted); white-space: nowrap; }

/* Журнал доступа: та же сетка, что и таблица выдачи, но колонки узкие и их
   шесть — поэтому свои ширины. Колонки ужимаются: сетка не распирается
   содержимым, а длинная почта обрезается многоточием — прокрутки вбок здесь
   быть не должно. */
.access-log-grid .access-grid-row { gap: 12px; }
.log-c {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.log-c0 { flex: 0 1 78px; }
.log-c1 { flex: 0 1 132px; }
.log-c2 { flex: 1 1 200px; }
.log-c3 { flex: 1 1 170px; }
.log-c4 { flex: 1 1 170px; }
.log-c5 { flex: 0 1 110px; }

.access-log-grid .access-grid-head .log-c { font-size: 12px; }
.log-when { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.log-src { color: var(--text-dim); }

/* Появление, открытие и закрытие права различаются цветом: в списке из двух
   сотен строк глаз ищет именно «что закрыли», и читать это словами долго. */
.ev-new { color: var(--accent); }
.ev-on  { color: var(--ok); }
.ev-off { color: var(--danger); }

/* --- Панель «Файлы диалога» и списки файлов ------------------------------ */
/* Третья колонка, а не всплывающее окно: файл ищут, глядя в переписку, и
   закрывать её ради списка неудобно. Ширина фиксированная — список читается
   строками, а не плиткой, и растягивать его не за чем. */
/* Панель прижата к правому краю окна и НЕ участвует в сетке .layout.
   Сначала она была третьей колонкой грида — и это оказалось хрупко: стоило
   классу-переключателю не оказаться на месте, как элемент падал в первую
   колонку следующей строки, то есть под список диалогов слева. Позиция
   правого края не должна зависеть от того, доехал ли класс: fixed справа
   выглядит правильно в любом состоянии, а открытая панель лишь поджимает
   переписку отступом. */
.files-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--bg-panel);
    border-left: 1px solid var(--border);
    position: fixed;
    top: 52px;
    right: 0;
    bottom: 0;
    width: 320px;
    z-index: 25;
    box-shadow: var(--shadow);
}

/* Класс с `display: flex` сильнее браузерного `[hidden] { display: none }`,
   поэтому закрытая панель всё равно оставалась на экране — пустой рамкой у
   правого края (а до этого, третьей колонкой грида, уезжала под список
   диалогов слева). Скрытие приходится объявлять своим правилом. */
.files-panel[hidden] { display: none; }

/* Переписке отдаём место под панель, чтобы длинные ответы не уезжали под неё. */
body.files-open .chat { padding-right: 320px; }

.files-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 8px 10px 14px;
    border-bottom: 1px solid var(--border);
}

.files-title { font-weight: 600; font-size: 14px; }
.files-count { color: var(--text-dim); font-size: 12px; margin-right: auto; }
.files-list { overflow: auto; padding: 8px; display: flex; flex-direction: column; gap: 4px; }
.files-empty { color: var(--text-dim); font-size: 13px; padding: 12px 6px; line-height: 1.5; }

.file-tile {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 8px;
    border-radius: 10px;
    cursor: pointer;
    border: 1px solid transparent;
}

.file-tile:hover { background: var(--bg-soft); border-color: var(--border); }

.file-tile-pic {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    border-radius: 8px;
    background: var(--bg-soft);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    overflow: hidden;
}

.file-tile-pic img { width: 100%; height: 100%; object-fit: cover; }
/* Присланное человеком отмечено полосой слева: в списке «моё» и «сделанное
   сервисом» различают в первую очередь. */
.file-tile.from-user .file-tile-pic { box-shadow: inset 3px 0 0 var(--accent); }

.file-tile-main { min-width: 0; flex: 1; }
.file-tile-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-tile-meta { color: var(--text-dim); font-size: 11px; margin-top: 2px; }
.file-tile-chat {
    color: var(--accent);
    font-size: 11px;
    margin-top: 2px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.file-tile-chat:hover { text-decoration: underline; }

@media (max-width: 860px) {
    /* Узкий экран: панель ложится поверх переписки, отступ ей не отдаём —
       иначе на 400 px ширины для самой переписки не осталось бы места. */
    body.files-open .chat { padding-right: 0; }
    .files-panel { width: 88vw; max-width: 340px; z-index: 30; }
}

/* --- Панель «Рекомендации» (BACKLOG 333, Э2) ------------------------------ */
/* Тот же приём, что у «Файлов диалога» — колонка у правого края, а не
   всплывающее окно. Отличие принципиальное: у неё нет кнопки «закрыть» —
   только свернуть в узкую полоску. Полоска ýже панели файлов и с меньшим
   z-index: когда открываются обе, файлы ложатся поверх (docs/65). */
.advice-panel {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--bg-panel);
    border-left: 1px solid var(--border);
    position: fixed;
    top: 52px;
    right: 0;
    bottom: 0;
    width: 320px;
    z-index: 20;
    box-shadow: var(--shadow);
    transition: width .15s ease;
}
.advice-panel[hidden] { display: none; }

body.advice-open .chat { padding-right: 320px; }
body.advice-collapsed .chat { padding-right: 44px; }
/* Обе панели сразу — ширину диктует более широкая (файлы диалога). */
body.files-open.advice-open .chat,
body.files-open.advice-collapsed .chat { padding-right: 320px; }

.advice-panel.collapsed { width: 44px; overflow: hidden; }

.advice-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 8px 10px 14px;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    user-select: none;
}
.advice-title { font-weight: 600; font-size: 14px; white-space: nowrap; }
.advice-count {
    color: var(--text-dim);
    font-size: 12px;
    margin-right: auto;
    background: var(--bg-soft);
    border-radius: 10px;
    padding: 0 7px;
    min-width: 16px;
    text-align: center;
}
.advice-arrow { color: var(--text-dim); font-size: 13px; transition: transform .15s ease; }
.advice-panel.collapsed .advice-arrow { transform: rotate(180deg); }
.advice-panel.collapsed .advice-title { display: none; }
.advice-panel.collapsed .advice-head { justify-content: center; padding: 10px 4px; }
.advice-panel.collapsed .advice-list { display: none; }

.advice-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 8px; display: flex; flex-direction: column; gap: 8px; }
.advice-empty { color: var(--text-dim); font-size: 13px; padding: 12px 6px; line-height: 1.5; }

.advice-item {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 9px 10px;
}
.advice-item.tone-good { border-left: 3px solid var(--ok); }
.advice-item.tone-bad { border-left: 3px solid var(--danger); }
.advice-text { font-size: 13px; line-height: 1.45; }
.advice-actions { display: flex; gap: 8px; margin-top: 7px; }
.advice-actions button {
    font-size: 12px;
    border: 1px solid var(--border);
    background: var(--bg-soft);
    border-radius: 8px;
    padding: 3px 9px;
    cursor: pointer;
}
.advice-actions button:hover { border-color: var(--accent); }
.advice-thanks { font-size: 12px; color: var(--text-dim); margin-top: 6px; }

.advice-panel.collapsed .advice-latency { display: none; }
/* Не больше пятой части колонки: список инструментов длинный и отнимал место
   у самих рекомендаций. Остальное — прокруткой внутри блока. */
.advice-latency {
    border-top: 1px solid var(--border);
    padding: 10px 8px 12px;
    flex: 0 0 auto;
    max-height: 20%;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.advice-latency[hidden] { display: none; }
.advice-latency-head { font-size: 13px; font-weight: 600; margin-bottom: 6px; flex-shrink: 0; }
.advice-latency-list { display: flex; flex-direction: column; gap: 5px; min-height: 0; overflow: auto; }
.advice-latency-item {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    font-size: 12px;
    line-height: 1.4;
}
.advice-latency-title { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.advice-latency-value { flex-shrink: 0; text-align: right; }
.advice-latency-req {
    font-size: 12px;
    border: 1px solid var(--border);
    background: var(--bg-soft);
    border-radius: 8px;
    padding: 1px 7px;
    cursor: pointer;
}
.advice-latency-req:hover { border-color: var(--accent); }

@media (max-width: 860px) {
    /* На телефоне постоянной полоски нет вовсе — открывается только кнопкой
       в шапке, поверх переписки, и закрывается той же кнопкой. Одна кнопка
       на весь жизненный цикл на телефоне — не нарушение «закрыть нельзя»:
       это тот же переключатель видимости, что и на десктопе у полоски. */
    body.advice-open .chat,
    body.advice-collapsed .chat { padding-right: 0; }
    .advice-panel { width: 88vw; max-width: 340px; z-index: 21; }
    .advice-panel.collapsed { width: 0; }
    .advice-mobile-btn { display: inline-flex; }
}
@media (min-width: 861px) {
    .advice-mobile-btn { display: none; }
}

/* --- Профиль ------------------------------------------------------------- */
.user-chip {
    display: inline-block;
    max-width: 26vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-dim);
    text-decoration: none;
    padding: 5px 9px;
    border-radius: 9px;
    font: inherit;
    font-size: 13px;
}

.user-chip:hover { background: var(--bg-soft); border-color: var(--border); color: var(--text); }
.user-chip.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }



.profile-files { padding: 0; max-height: 46vh; }

/* --- экран «Как работает» ------------------------------------------------ */
.docs-wrap { max-width: 1180px; }
.docs-layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: 28px; align-items: start; }
.docs-toc { position: sticky; top: 16px; display: flex; flex-direction: column; gap: 2px; }
.docs-toc-item {
    display: block; padding: 7px 10px; border-radius: 8px; text-decoration: none;
    color: var(--text-dim); font-size: 14px; line-height: 1.35; border-left: 2px solid transparent;
}
.docs-toc-item:hover { background: var(--bg-soft); color: var(--text); }
.docs-toc-item.is-active { background: var(--bg-soft); color: var(--text); border-left-color: var(--accent); font-weight: 600; }
.docs-toc-group {
    margin: 14px 0 4px; padding: 0 10px; font-size: 12px; line-height: 1.3;
    color: var(--text-dim); text-transform: uppercase; letter-spacing: .04em;
    border-top: 1px solid var(--border); padding-top: 10px;
}
.docs-body { min-width: 0; line-height: 1.6; }
.docs-body h1 { font-size: 24px; margin: 0 0 16px; }
.docs-body h2 { font-size: 18px; margin: 28px 0 10px; }
.docs-body h3 { font-size: 15px; margin: 22px 0 8px; color: var(--text-dim); }
.docs-body p, .docs-body ul, .docs-body ol { margin: 0 0 12px; }
.docs-body li { margin: 4px 0; }
.docs-body table { margin: 12px 0; }
.docs-body blockquote {
    margin: 12px 0; padding: 8px 14px; border-left: 3px solid var(--accent);
    background: var(--bg-soft); border-radius: 0 8px 8px 0; color: var(--text-dim);
}
.docs-body hr { margin: 24px 0; border: 0; border-top: 1px solid var(--border); }
@media (max-width: 800px) {
    .docs-layout { grid-template-columns: 1fr; }
    .docs-toc { position: static; flex-direction: row; flex-wrap: wrap; margin-bottom: 16px; }
    .docs-toc-item { border-left: 0; border-bottom: 2px solid transparent; }
    .docs-toc-item.is-active { border-left: 0; border-bottom-color: var(--accent); }
}

/* --- экран «Что нового» ------------------------------------------------- */
.changelog-wrap { max-width: 760px; }
.changelog-list { display: flex; flex-direction: column; gap: 22px; }
.changelog-day {
    padding: 14px 16px; border: 1px solid var(--border); border-radius: 12px;
    background: var(--bg-soft);
}
.changelog-date { font-size: 15px; margin: 0 0 8px; color: var(--text-dim); font-weight: 600; }
.changelog-items { margin: 0; padding-left: 18px; line-height: 1.55; }
.changelog-items li { margin: 5px 0; }

/* Планы (/backlog) переиспользуют раскладку журнала изменений: те же карточки,
   только вместо даты — название группы, а под ним одна поясняющая строка.
   Отвергнутое приглушено, но не спрятано: это тоже ответ на вопрос человека. */
.plans-note { margin: 0 0 8px; font-size: 13px; color: var(--text-dim); }
.plans-declined .changelog-items { color: var(--text-dim); }

/* Нажатый пункт навигации, пока грузится страница: клик обязан отзываться
   сразу, иначе на медленном канале он читается как «не сработало». */
.topnav-item.is-loading, .user-chip.is-loading { opacity: .65; }

/* --- Примеры (/examples) -------------------------------------------------
   Вкладка = название кейса с пунктирным подчёркиванием (просьба владельца,
   BACKLOG.md пункт 132): закрытая вкладка выглядит как ссылка, которую можно
   открыть, открытая — как заголовок. Диалог внутри — те же `.msg`/`.msg-body`/
   `.msg-text`, что и в настоящей переписке: пример обязан выглядеть как жизнь,
   а не как отдельная вёрстка. */
.examples-wrap { max-width: 900px; }
.examples-tabs {
    display: flex; flex-wrap: wrap; gap: 4px 18px;
    margin: 0 0 20px; padding-bottom: 12px;
    border-bottom: 1px solid var(--border);
}
.examples-tab {
    background: transparent; border: 0; cursor: pointer;
    font: inherit; font-size: 13.5px; color: var(--text-dim);
    padding: 4px 0;
    text-decoration: underline; text-decoration-style: dashed; text-underline-offset: 3px;
}
.examples-tab:hover { color: var(--text); }
.examples-tab.active { color: var(--text); font-weight: 600; text-decoration-style: solid; text-decoration-color: var(--accent); }
.examples-note { color: var(--text-dim); font-size: 13px; line-height: 1.5; margin: 0 0 16px; }
.examples-case { margin-bottom: 8px; }
.examples-messages .msg { max-width: 100%; }

/* --- Запуск «Умных задач» ------------------------------------------------
   Единственный экран сервиса, с которого что-то пишется в чужую рабочую
   систему. Оформление здесь спокойное намеренно: кнопка «поставить» не должна
   выглядеть приглашением нажать не глядя. */
.tasks-block { margin: 0 0 22px; }
.tasks-block h2 { font-size: 15px; margin: 0 0 8px; }
.tasks-rules {
    background: var(--bg-soft);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    margin: 0 0 6px;
    line-height: 1.55;
}
.tasks-count { color: var(--text-dim); font-size: 13.5px; margin: 0; }
.tasks-sample {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 12px 14px;
}
.tasks-sample-title { font-weight: 600; margin-bottom: 4px; }
.tasks-sample-meta { color: var(--text-dim); font-size: 13px; }
.tasks-sample-body {
    white-space: pre-wrap;
    margin: 10px 0 0;
    font-family: inherit;
    line-height: 1.55;
}
.tasks-list { margin: 0; padding-left: 22px; line-height: 1.7; }
/* Вид строки (пункт 126, 29.08.2026): одна таблица черновика несёт и дела
   «Умных задач», и записи в CRM — метка перед строкой говорит, куда именно
   она уедет, до того как человек прочитает её содержимое. */
.tasks-kind {
    display: inline-block;
    font-size: 11.5px;
    color: var(--text-dim);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0 6px;
    margin-right: 6px;
    line-height: 1.6;
}
.tasks-ok { color: #2e7d32; }
.tasks-gone { color: var(--text-dim); }
.tasks-bad { color: #c62828; }
.tasks-danger { border-color: #c62828; color: #c62828; }
.tasks-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 8px; }
.tasks-said { flex-basis: 100%; color: var(--text-dim); font-size: 13.5px; min-height: 18px; }

/* --- Карточка запуска задач в переписке ------------------------------ */
/* Те же кнопки, что на странице запуска, рядом с ответом модели: работа
   разговорная, а уходить со страницы ради каждого шага незачем. Рамка
   намеренно заметная — это единственное место переписки, откуда что-то
   пишется в чужую рабочую систему. */
.run-card {
    margin: 12px 0 0;
    border: 1px solid var(--accent);
    border-radius: 10px;
    padding: 12px 14px;
    background: var(--accent-soft);
    font-size: 14px;
}
.run-card-load { color: var(--text-dim); font-size: 13.5px; }
.run-card-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.run-card-link { font-size: 13px; }
.run-card-status { color: var(--text-dim); font-size: 13.5px; margin-top: 2px; }
.run-card-title { font-weight: 600; margin-top: 6px; }
.run-card-rules, .run-card-count { font-size: 13.5px; margin-top: 4px; }
.run-card-stale { color: var(--warn); font-size: 13.5px; margin-top: 6px; }
.run-card-sample {
    margin-top: 10px;
    background: var(--bg-panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
}
.run-card-sample-title { font-weight: 600; }
.run-card-sample-meta { color: var(--text-dim); font-size: 13px; margin-top: 2px; }
.run-card-sample-body {
    white-space: pre-wrap;
    margin: 8px 0 0;
    font-family: inherit;
    font-size: 13.5px;
    line-height: 1.5;
    max-height: 180px;
    overflow: auto;
}
.run-card-acts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.run-card-said { color: var(--text-dim); font-size: 13.5px; min-height: 18px; margin-top: 8px; }
.run-card-bad { color: var(--danger); }

/* --- Диалоги сервиса (администратору) ------------------------------------ */
/* Экран разбора: сверху перечень без текстов, снизу открытая переписка.
   Две зоны на одной странице, а не две страницы, потому что смотрят их
   вперемежку — нашёл строку, прочитал, вернулся к списку. */
.page-hint { color: var(--text-dim); font-size: 12.5px; margin: 6px 0 0; }

.dlg-filters { display: flex; gap: 10px; align-items: center; margin: 4px 0 0; flex-wrap: wrap; }
.dlg-q { flex: 1 1 320px; max-width: 420px; padding: 8px 12px;
    border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-panel); color: inherit; }
.dlg-days { padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius);
    background: var(--bg-panel); color: inherit; }

.dlg-grid .access-grid-row { gap: 12px; }
.dlg-c0 { flex: 0 0 62px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.dlg-c1 { flex: 1 1 300px; }
.dlg-c2 { flex: 1 1 180px; }
.dlg-c3 { flex: 0 0 96px; }
.dlg-c4 { flex: 0 0 80px; }
.dlg-c5 { flex: 0 0 120px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.dlg-c6 { flex: 0 0 84px; font-variant-numeric: tabular-nums; }
.dlg-arch { color: var(--text-dim); font-size: 12px; }
.ev-read { color: var(--accent); }

.dlg-one { margin-top: 28px; }
.dlg-one-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px; margin-bottom: 12px; }
.dlg-msg { border: 1px solid var(--border); border-radius: var(--radius);
    padding: 10px 14px; margin-bottom: 10px; background: var(--bg-panel); }
.dlg-user { border-left: 3px solid var(--accent); }
.dlg-msg-meta { font-size: 12px; color: var(--text-dim); margin-bottom: 6px; }
/* Текст показывается как есть, без разбора разметки: разбирают то, что человек
   написал, а не то, как это выглядело в переписке. */
.dlg-msg-text { white-space: pre-wrap; word-break: break-word; font: inherit; margin: 0; }
.dlg-cut { margin-top: 6px; font-size: 12px; color: var(--danger); }
.dlg-file { margin-top: 6px; font-size: 12.5px; color: var(--text-dim); }

/* Разметка риска разглашения (docs/vnutri/07, Э3): один случай, две кнопки. */
.rc-card { border: 1px solid var(--border); border-radius: var(--radius);
    padding: 14px 16px; background: var(--bg-panel); max-width: 720px; }
.rc-summary { white-space: pre-wrap; word-break: break-word; font: inherit; margin: 10px 0; }
.rc-btns { display: flex; gap: 10px; margin-top: 8px; }

/* Редакции самопрезентации (BACKLOG 335, Э2): текст новинок и предпросмотр. */
.pe-slides { width: 100%; max-width: 680px; font: inherit; margin: 10px 0;
    box-sizing: border-box; }
.pe-preview { margin: 10px 0; }

/* Приёмка (пункт СЧЁТ, docs/vnutri/05): строка на пункт реестра. */
.pk-table { display: flex; flex-direction: column; gap: 6px; }
.pk-row { display: flex; gap: 10px; align-items: baseline; padding: 6px 10px;
    border: 1px solid var(--border); border-radius: var(--radius); flex-wrap: wrap; }
.pk-row-pass { border-left: 3px solid var(--ok, #2a8f4e); }
.pk-row-fail { border-left: 3px solid var(--danger); }
.pk-row-human { border-left: 3px solid var(--text-dim); }
.pk-row-unknown { border-left: 3px solid var(--border); }
.pk-num { font-size: 12px; color: var(--text-dim); white-space: nowrap; }
.pk-state { font-size: 12px; font-weight: 600; white-space: nowrap; }
.pk-title { flex: 1; min-width: 200px; }
.pk-evidence { font-size: 12px; color: var(--text-dim); flex-basis: 100%; }

/* Подсказка о возможности (docs/26-podskazki.md). Одна полоска рядом с той
   кнопкой, о которой речь; координаты ставит скрипт по месту якоря, поэтому
   здесь только вид. На узком экране полоска не должна вылезать за край —
   отсюда потолок ширины в долях окна, а не в пикселях. */
.hint-bubble {
    position: fixed;
    z-index: 60;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    max-width: min(340px, calc(100vw - 16px));
    padding: 10px 12px;
    border: 1px solid var(--accent, var(--border));
    border-radius: 10px;
    background: var(--bg-soft, var(--bg));
    color: var(--text);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
    font-size: 13px;
    line-height: 1.4;
}
/* Якорь скрыт (кнопка файлов у пустого диалога) — полоска уходит в угол, но не
   пропадает: текст полезен и без стрелки на кнопку. */
.hint-bubble.hint-corner {
    top: auto;
    left: auto;
    right: 16px;
    bottom: 16px;
}
.hint-bubble .hint-ok {
    flex: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: transparent;
    color: inherit;
    font: inherit;
    padding: 2px 10px;
    cursor: pointer;
}
.hint-bubble .hint-ok:hover { text-decoration: underline; }

/* Память между диалогами: выжимка в профиле показывается как есть — переносами
   строк, которые в неё положила модель, а не склеенным абзацем. */
.memory-text {
    white-space: pre-wrap;
    word-break: break-word;
    font: inherit;
    margin: 0 0 10px;
    padding: 12px 14px;
    border: 1px solid var(--line, #e3e6ea);
    border-radius: 8px;
    background: var(--panel-soft, #fafbfc);
}
.panel-empty { margin: 0 0 10px; color: var(--muted, #77808a); }

/* Полоса готовности разбора правил NDA (пункт НДАПОЛНОТА, 09.09.2026). */
.nda-readiness { margin: 0 0 14px; }
.readiness-bar {
    display: flex; height: 8px; border-radius: 999px; overflow: hidden;
    background: var(--bg-soft); margin: 0 0 6px;
}
.readiness-seg { display: block; height: 100%; }
.readiness-seg-ok { background: var(--accent); }
.readiness-seg-failed { background: var(--danger); }
.readiness-seg-nofile { background: var(--border); }
.readiness-seg-pending { background: var(--text-dim); }
.readiness-label { font-size: 13px; margin: 0 0 2px; }
.readiness-synced { font-size: 12px; color: var(--text-dim); margin: 0 0 2px; }
.readiness-missing { font-size: 12px; color: var(--text-dim); }
#chat-memory-wrap { gap: 6px; }
#chat-memory-wrap input { margin: 0; }

/* --- отзыв о странице -------------------------------------------------
   Кнопка стоит на каждой странице справа внизу: она не часть какого-то
   экрана, а способ сказать про любой из них. Поверх переписки не мешает —
   узкая, приглушённая, и на телефоне сжимается до значка. */
.fb-open {
    position: fixed; right: 16px; bottom: 16px; z-index: 40;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 12px; border-radius: 999px;
    border: 1px solid var(--border); background: var(--bg-panel); color: var(--text-dim);
    font-size: 13px; cursor: pointer; opacity: .75;
}
.fb-open:hover { opacity: 1; color: var(--text); }
@media (max-width: 620px) { .fb-open-text { display: none; } }

.fb-modal {
    position: fixed; inset: 0; z-index: 60; display: flex;
    align-items: center; justify-content: center;
    background: rgba(0,0,0,.45); padding: 16px;
}
.fb-box {
    width: 100%; max-width: 520px; background: var(--bg-panel);
    border: 1px solid var(--border); border-radius: 12px; padding: 16px;
    display: flex; flex-direction: column; gap: 10px;
}
.fb-head { display: flex; align-items: center; justify-content: space-between; }
.fb-hint, .fb-meta { font-size: 12px; color: var(--text-dim); }
.fb-text {
    width: 100%; resize: vertical; font: inherit; font-size: 16px;
    padding: 8px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--bg); color: var(--text);
}
.fb-files { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fb-file-btn { font-size: 13px; color: var(--accent); cursor: pointer; }
.fb-file-list { font-size: 12px; color: var(--text-dim); }
.fb-note { font-size: 13px; min-height: 1em; }
.fb-note.warn { color: var(--danger, #c0392b); }
.fb-note.ok { color: var(--ok, #2e7d32); }
.fb-actions { display: flex; gap: 8px; justify-content: flex-end; }

.fb-card {
    border: 1px solid var(--border); border-radius: 10px;
    padding: 12px; margin-bottom: 10px;
    display: flex; flex-direction: column; gap: 8px;
}
.fb-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fb-card-page { font-size: 12px; color: var(--text-dim); }
.fb-card-text { white-space: pre-wrap; }
.fb-card-reply {
    border-left: 3px solid var(--accent); padding-left: 10px;
    white-space: pre-wrap;
}
.fb-status {
    font-size: 12px; padding: 2px 8px; border-radius: 999px;
    border: 1px solid var(--border); color: var(--text-dim);
}
.fb-status-answered { color: var(--accent); }
.fb-status-closed { opacity: .6; }

/* Текст NDA под найденным пунктом (пункт НДАССЫЛКА, 11.09.2026) — то же
   устройство модалки, что у отзыва о странице (`.fb-modal`/`.fb-box`), но
   своим классом: содержимое здесь длинный документ, а не форма. */
.nda-clause-link { background: none; border: 0; padding: 0; color: var(--accent); cursor: pointer; text-align: left; font: inherit; }
.nda-clause-link:hover { text-decoration: underline; }
.nda-text-modal {
    position: fixed; inset: 0; z-index: 60; display: flex;
    align-items: center; justify-content: center;
    background: rgba(0,0,0,.45); padding: 16px;
}
.nda-text-box {
    width: 100%; max-width: 640px; max-height: 80vh; background: var(--bg-panel);
    border: 1px solid var(--border); border-radius: 12px; padding: 16px;
    display: flex; flex-direction: column; gap: 10px; overflow: hidden;
}
.nda-text-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.nda-text-body { overflow-y: auto; white-space: pre-wrap; font-size: 13.5px; line-height: 1.5; }
.nda-text-body mark { background: var(--accent); color: var(--bg-panel); border-radius: 3px; padding: 0 2px; }
.fb-del { align-self: flex-start; background: none; border: 0; cursor: pointer; }

.btn-link { background: none; border: 0; padding: 0; color: var(--accent); cursor: pointer; text-align: left; font: inherit; }
.btn-link:hover { text-decoration: underline; }

/* Окно самопрезентации (BACKLOG 335, Э1, docs/66-samoprezentaciya.md) — то же
   устройство модалки, что у `.nda-text-modal`, своим классом: тут карусель со
   слайдами и картинкой, а не текст документа. */
.presentation-modal {
    position: fixed; inset: 0; z-index: 60; display: flex;
    align-items: center; justify-content: center;
    background: rgba(0,0,0,.45); padding: 16px;
}
.presentation-box {
    width: 100%; max-width: 460px; max-height: 86vh; background: var(--bg-panel);
    border: 1px solid var(--border); border-radius: 12px; padding: 16px;
    display: flex; flex-direction: column; gap: 12px; overflow: hidden;
}
.presentation-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.presentation-title { font-weight: 600; font-size: 16px; }
.presentation-body { overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.presentation-img { max-width: 100%; border-radius: 8px; display: block; }
.presentation-text { font-size: 14px; line-height: 1.5; }
.presentation-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.presentation-dots { display: flex; gap: 6px; }
.presentation-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--border); }
.presentation-dot.active { background: var(--accent); }
.presentation-nav { display: flex; gap: 8px; }
.presentation-nav button {
    padding: 6px 14px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--bg-panel); cursor: pointer; font: inherit;
}
.presentation-nav button:disabled { opacity: .4; cursor: default; }
@media (max-width: 620px) {
    .presentation-modal { padding: 8px; }
    .presentation-box { max-width: none; width: 100%; height: 100%; max-height: none; border-radius: 8px; }
    .presentation-nav button { min-height: 38px; padding: 6px 16px; }
    .presentation-head .icon-btn { min-width: 38px; min-height: 38px; }
}
.user-chip-dot { color: var(--accent); margin-left: 4px; font-size: 18px; line-height: 0; }

/* Поставленные задачи — ссылками в портал: смысл пробы в том, чтобы
   посмотреть, что вышло, а не запомнить номер задачи. */
.run-card-done { margin-top: 10px; }
.run-card-done-head { color: var(--text-dim); font-size: 13px; margin-bottom: 4px; }
.run-card-done-row { font-size: 13.5px; line-height: 1.6; }

/* Строка о судьбе разговора в самой переписке. Тихая и по центру: это не
   сообщение, а отметка сервиса — её пишет не человек и не модель. */
.chat-event {
    margin: 14px auto;
    max-width: 640px;
    text-align: center;
    color: var(--text-dim);
    font-size: 13px;
    line-height: 1.5;
}

/* ── «Показать коллеге» (docs/51-pokazat-kollege.md) ────────────────────────
   Кнопка яркая намеренно: соседние иконки шапки — про настройки разговора, а
   эта про то, чем человек хочет поделиться, и серой она потерялась бы среди
   них ровно так же, как ступень модели (7 нажатий на 377 вопросов). */
.share-btn {
    border: 0;
    border-radius: 999px;
    padding: 6px 14px;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    color: #fff;
    background: var(--accent-2);
    cursor: pointer;
    white-space: nowrap;
}
.share-btn:hover { filter: brightness(1.06); }

/* Полоса выбора над полем ввода. Появляется только во время выбора: постоянная
   строка «поделитесь» быстро перестаёт читаться. */
.share-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 0 16px 8px;
    padding: 10px 12px;
    border: 1px solid var(--accent-2);
    border-radius: var(--radius);
    background: var(--bg-panel);
}
.share-bar-count { flex: 1 1 auto; font-size: 13px; color: var(--text-dim); }

/* Во время выбора нажатие на сообщение значит «отметить», поэтому действия под
   ответом на это время убраны: две разные реакции на один клик — способ
   отметить не то и не заметить этого. */
.messages.picking .msg { cursor: pointer; }
.messages.picking .msg-actions { display: none; }
.messages.picking .msg[data-id] .msg-body {
    outline: 1px dashed var(--border);
    outline-offset: 3px;
}
.messages.picking .msg.picked .msg-body {
    outline: 2px solid var(--accent-2);
    outline-offset: 3px;
}
.messages.picking .msg[data-id] .msg-body::after {
    content: '';
    position: absolute;
    top: 6px;
    inset-inline-end: 6px;
    width: 16px;
    height: 16px;
    border: 2px solid var(--border);
    border-radius: 4px;
    background: var(--bg-panel);
}
.messages.picking .msg.picked .msg-body::after {
    content: '✓';
    border-color: var(--accent-2);
    background: var(--accent-2);
    color: #fff;
    font-size: 12px;
    line-height: 16px;
    text-align: center;
}
.messages.picking .msg .msg-body { position: relative; }

/* Окно предпросмотра. Текст показывается целиком и моноширинно: человек должен
   прочитать ровно то, что уедет в буфер, — вместе с BB-кодом. */
.share-viewer .viewer-body { padding: 0; }
.share-text {
    width: 100%;
    height: 100%;
    min-height: 320px;
    box-sizing: border-box;
    border: 0;
    padding: 14px 16px;
    resize: none;
    font: 13px/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--text);
    background: var(--bg-panel);
}
.share-text:focus { outline: none; }

@media (max-width: 620px) {
    /* 16px — не вкус: мельче, и мобильный Safari увеличивает страницу при
       постановке курсора, а обратно она не уменьшается. */
    .share-text { font-size: 16px; }
    .share-btn { padding: 6px 10px; }
}

/* Страница «Деплой» (docs/61) — светофор по девяти узлам. */
.status-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
    margin-bottom: 24px;
}
.status-node {
    padding: 12px 14px;
    border-radius: 10px;
    background: var(--bg-panel);
    border: 1px solid var(--border, #2a2a2a);
}
.status-node-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}
.status-dot {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    margin-top: 3px;
    flex: none;
}
.status-green .status-dot { background: #2ea043; }
.status-yellow .status-dot { background: #d29922; }
.status-red .status-dot { background: #da3633; }
.status-label { font-weight: 600; }
.status-details { font-size: 13px; opacity: .75; margin-top: 2px; }
.status-events h2 { font-size: 15px; margin: 0 0 8px; }
.status-event { font-size: 13px; padding: 4px 0; border-bottom: 1px solid var(--border, #2a2a2a); }
.status-empty { opacity: .6; font-size: 13px; }
/* Превью — последние 3 события узла, видны сразу, без клика (пункт СЛУЖБЫКВАДРАТ). */
.status-preview { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border, #2a2a2a); }
.status-preview .status-event { border-bottom: none; padding: 3px 0; opacity: .85; }
.status-event-fact { opacity: 1; }
.status-event-state { opacity: .6; font-style: italic; }
/* «Ещё» — остаток истории узла под явным, не скрытым маркером раскрытия. */
.status-node-more { margin-top: 6px; }
.status-node-more > summary { cursor: pointer; font-size: 12px; opacity: .8; }
.status-node-more .status-history { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border, #2a2a2a); }
.status-node-more .status-history .status-event { border-bottom: none; padding: 3px 0; opacity: .85; }
/* Общая сводная лента — свёрнута по умолчанию, дублирует то, что уже видно в квадратиках. */
.status-events-all { margin-top: 8px; }
.status-events-all > summary { cursor: pointer; font-weight: 600; }
.status-events-all[open] > summary { margin-bottom: 8px; }
