/* Тема: светлая по умолчанию, тёмная через prefers-color-scheme */
:root{
  --bg:#f4f5f7; --panel:#ffffff; --panel-2:#fafbfc; --border:#dfe1e6; --line:#d3dae4;
  --text:#172b4d; --muted:#5e6c84; --faint:#97a0af;
  --accent:#0052cc; --accent-soft:#deebff;
  --p1:#de350b; --p1-soft:#ffebd6;
  --green:#00875a; --yellow:#ff991f; --red:#bf2600; --grey:#6b778c;
  --shadow:0 1px 3px rgba(9,30,66,.08),0 0 1px rgba(9,30,66,.12);
  --shadow-lg:0 8px 24px rgba(9,30,66,.12),0 0 1px rgba(9,30,66,.16);
  /* Design tokens v2.1 - light theme */
  --fs:14.5px; --col-w:820px; --rail-w:320px; --pad-x:28px;
  --font:Inter,-apple-system,"Segoe UI",system-ui,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --v21-bg:#fafaf9; --v21-surface:#fff; --v21-surface-2:#f5f5f4; --v21-surface-3:#ebe9e6;
  --v21-border:#ebe9e6; --v21-border-2:#d6d3d1; --v21-border-ctl:#868483;
  --v21-fg:#1c1917; --v21-fg-2:#57534e; --v21-fg-3:#716d67; --v21-fg-4:#88847f;
  --v21-ink:#0a0a0a;
  --v21-live:#16a34a; --v21-live-text:#0f7f38; --v21-live-soft:#f0fdf4;
  --v21-warn:#b45309; --v21-warn-soft:#fff7ed;
  --v21-err:#b91c1c; --v21-err-soft:#fef2f2;
  --v21-user:#4338ca; --v21-user-soft:#eef2ff;
  --v21-focus:#1d4ed8;
  --v21-shadow-lg:0 24px 60px -16px rgba(20,20,20,.18);
}
@media (prefers-color-scheme: dark){
  :root{
    --bg:#0b0f1a; --panel:#161b26; --panel-2:#1c2230; --border:#262d3d; --line:#2b3542;
    --text:#e6ebf2; --muted:#9aa5b8; --faint:#5c6678;
    --accent:#4c9aff; --accent-soft:#103759;
    --p1:#ff7459; --p1-soft:#5a2418;
    --green:#36b37e; --yellow:#ffab00; --red:#ff7459; --grey:#8590a2;
    --shadow:0 1px 3px rgba(0,0,0,.4),0 0 1px rgba(0,0,0,.5);
    --shadow-lg:0 12px 32px rgba(0,0,0,.5),0 0 1px rgba(0,0,0,.6);
    /* Design tokens v2.1 - dark theme */
    --v21-bg:#0d0d0e; --v21-surface:#161617; --v21-surface-2:#1c1c1e; --v21-surface-3:#232325;
    --v21-border:#232325; --v21-border-2:#303033; --v21-border-ctl:#6d6d73;
    --v21-fg:#ededee; --v21-fg-2:#b5b5b8; --v21-fg-3:#848489; --v21-fg-4:#6d6d75;
    --v21-ink:#f5f5f5;
    --v21-live:#4ade80; --v21-live-text:#4ade80; --v21-live-soft:rgba(74,222,128,.10);
    --v21-warn:#fbbf24; --v21-warn-soft:rgba(251,191,36,.10);
    --v21-err:#f87171; --v21-err-soft:rgba(248,113,113,.10);
    --v21-user:#a5b4fc; --v21-user-soft:rgba(165,180,252,.10);
    --v21-focus:#93b4ff;
    --v21-shadow-lg:0 24px 60px -16px rgba(0,0,0,.60);
  }
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg); color:var(--text);
  font-size:14px; line-height:1.45;
  -webkit-font-smoothing:antialiased;
}
button{font-family:inherit;font-size:inherit;cursor:pointer}
input,textarea,select{font-family:inherit;font-size:14px}
a{color:var(--accent);text-decoration:none}

/* Экран входа */
.auth-wrap{
  min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;
  background:var(--v21-bg);
  color:var(--v21-fg);
  font-family:var(--font);font-size:var(--fs);
}
.auth-card{
  width:100%;max-width:380px;background:var(--v21-surface);border:1px solid var(--v21-border);
  border-radius:12px;box-shadow:var(--v21-shadow-lg);padding:32px;
}
.brand{display:flex;align-items:center;gap:8px;margin-bottom:4px;font-weight:600;font-size:14px}
.brand-mark{
  width:16px;height:16px;background:var(--v21-ink);border-radius:4px;position:relative;flex:none;
}
.brand-mark::after{content:"";position:absolute;inset:4px;background:var(--v21-bg);border-radius:1px}
.brand-name{font-size:14px;font-weight:600;letter-spacing:-.01em}
.field{margin-top:16px}
.field label{display:block;font-size:12.5px;color:var(--v21-fg-3);margin-bottom:6px;font-weight:500}
.field input{
  width:100%;padding:10px 12px;border:1px solid var(--v21-border-ctl);border-radius:8px;
  background:var(--v21-surface-2);color:var(--v21-fg);outline:none;transition:border-color .15s;
  font-family:inherit;
}
.field input:focus{border-color:var(--v21-focus);outline:2px solid var(--v21-focus);outline-offset:2px}
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:10px 12px;border-radius:6px;border:1px solid transparent;
  font-weight:500;font-size:13px;transition:all .15s;
}
.btn-primary{background:var(--v21-ink);color:var(--v21-bg);border-color:var(--v21-ink)}
.btn-primary:hover{opacity:.92}
.btn-ghost{background:transparent;color:var(--v21-fg);border:1px solid var(--v21-border-ctl)}
.btn-ghost:hover{background:var(--v21-surface-2)}
.btn-block{width:100%}

/* Шапка приложения */
.app{min-height:100vh;display:flex;flex-direction:column}
.topbar{
  display:flex;align-items:center;gap:16px;padding:10px 16px;
  background:var(--panel);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:10;
}
.topbar .brand-name{font-size:16px}
.tabs{display:flex;gap:2px;margin-left:8px}
.tab{
  padding:8px 14px;border:none;background:transparent;color:var(--muted);
  border-radius:6px;font-weight:500;transition:background .15s,color .15s;
}
.tab:hover{background:var(--panel-2);color:var(--text)}
.tab.active{background:var(--accent-soft);color:var(--accent)}
.spacer{flex:1}
/* Ссылки на публичные страницы.
   Отличаются от вкладок намеренно: подчёркивание и обычный цвет ссылки
   говорят, что это уход на другую страницу, а не переключение внутри
   кабинета. Одинаковый вид обещал бы вкладку и обманывал бы на первом же
   нажатии. */
.ext-links{display:flex;gap:14px;margin-right:14px}
.ext-links a{
  font-size:12px;color:var(--muted);text-decoration:none;
  border-bottom:1px solid transparent;padding-bottom:1px;
}
.ext-links a:hover{color:var(--text);border-bottom-color:var(--border)}
/* Те же ссылки на экране входа: там они стоят под формой и по центру, потому
   что вокруг нет панели, к левому краю которой можно прижаться. */
.auth-links{justify-content:center;margin:18px 0 6px}
.auth-links-note{text-align:center;font-size:11px;margin:0}
.org-pill{
  font-size:12px;color:var(--muted);padding:4px 10px;
  background:var(--panel-2);border:1px solid var(--border);border-radius:20px;
}
.ok-pill{
  display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--green);
  padding:3px 8px;background:rgba(0,135,90,.1);border-radius:20px;
}
.ok-dot{width:6px;height:6px;border-radius:50%;background:var(--green)}

/* Шапка на узком экране.
   Семь вкладок плюс бренд, здоровье, пилюля организации и «Выйти» не
   помещаются в одну строку уже на планшете. Вкладки уходят на отдельную
   строку (order:1, flex:1 0 100%) и прокручиваются по горизонтали — все
   семь остаются достижимыми, а не выезжают за обрезанный край шапки.
   Верхняя строка держит бренд у левого края, а «Выйти» у правого через
   spacer. Бренд, здоровье и кнопка выхода зафиксированы (flex-shrink:0),
   а амортизатором служит пилюля организации: min-width:0 позволяет ей
   сжиматься ниже содержимого, ellipsis обрезает длинное имя. Так кнопка
   «Выйти» не вытесняется за край и не обрезается контейнером .app.
   Брейкпоинт 820px совпадает с существующими для .task-layout и .dash-cols. */
@media (max-width:820px){
  .topbar{flex-wrap:wrap;gap:8px;padding:8px 12px}
  .tabs{order:1;flex:1 0 100%;margin-left:0;overflow-x:auto;
        -webkit-overflow-scrolling:touch;padding-bottom:2px}
  .tab{flex:0 0 auto;white-space:nowrap}
  .topbar .brand,.topbar .ok-pill,.topbar .btn{flex-shrink:0}
  .org-pill{min-width:0;max-width:30vw;overflow:hidden;
            text-overflow:ellipsis;white-space:nowrap}
}
/* Телефон (≤480): wordmark убирается, остаётся марка «Н» — без этого на 375px
   строка бренд+здоровье+организация+«Выйти» не помещается даже с усечением.
   Пилюля организации уже урезана блоком 820px. */
@media (max-width:480px){
  .topbar .brand-name{display:none}
}

/* Экран 375px: однорядная шапка с прокруткой вкладок.
   Подход отличается от брейкпоинта 820px: там вкладки уходят на вторую
   строку (flex-wrap:wrap + order:1), а здесь всё остаётся в одной строке —
   вкладки прокручиваются по горизонтали. Это сохраняет больше вертикального
   пространства на самых узких экранах, где каждая строка на счету. */
@media (max-width:375px){
  .topbar{flex-wrap:nowrap;gap:4px;padding:6px 8px}
  .tabs{order:0;flex:0 1 auto;margin-left:2px;overflow-x:auto;
        -webkit-overflow-scrolling:touch}
  .tab{flex:0 0 auto;white-space:nowrap;padding:5px 8px;font-size:12px}
  .topbar .brand,.topbar .ok-pill,.topbar .btn{flex-shrink:0}
  .org-pill{min-width:0;max-width:18vw;overflow:hidden;
            text-overflow:ellipsis;white-space:nowrap;font-size:10px;padding:3px 6px}
  .topbar .ok-pill{font-size:10px;padding:2px 6px}
  .topbar .btn{font-size:11px;padding:5px 8px}
}

/* Контент
   Приложение занимает окно и не прокручивается целиком: прокручивается
   содержимое. Иначе поле ввода разговора уезжает вниз вместе со страницей, и
   чтобы написать реплику, надо сначала долистать до конца переписки. Именно на
   это указал владелец 12.08.2026: поле ввода обязано стоять внизу и не
   двигаться. */
.app{height:100vh;overflow:hidden}
.content{flex:1;min-height:0;padding:16px;max-width:100%;overflow-y:auto}
/* Экран, который сам управляет своей прокруткой (разговор), отбирает её у
   контейнера. Без этого получаются две прокрутки одна в другой. */
.content.own-scroll{overflow:hidden;padding:0}
.view{display:none}
.view.active{display:block}
.content.own-scroll .view.active{display:flex;flex-direction:column;height:100%;min-height:0}

.settings-page{max-width:760px;margin:0 auto;padding:12px 0 32px}
.settings-head{margin-bottom:18px}
.settings-head h1{font-size:24px;margin:0 0 4px}
.settings-card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:18px;margin-top:12px}
.settings-card h2{font-size:15px;margin:0 0 14px}
.settings-field{display:grid;grid-template-columns:minmax(150px,220px) 1fr;align-items:center;gap:6px 16px;margin-top:12px}
.settings-field>span,.settings-check b{font-weight:600}
.settings-field input,.settings-field select{width:100%;padding:8px 10px;border:1px solid var(--border);border-radius:6px;background:var(--panel-2);color:var(--text)}
.settings-field small{grid-column:2;color:var(--muted)}
.settings-check{display:flex;align-items:flex-start;gap:10px;padding:10px 0}
.settings-check input{margin-top:3px;accent-color:var(--accent)}
.settings-check span{display:flex;flex-direction:column;gap:2px}
.settings-check small,.settings-note{color:var(--muted)}
.settings-note{border-left:3px solid var(--yellow);padding:6px 10px;margin:12px 0 0}
@media (max-width:600px){
  .settings-field{grid-template-columns:1fr}
  .settings-field small{grid-column:1}
}

/* Разговор: колонка на всю высоту, лента прокручивается, ввод внизу.
   Ширина колонки ограничена: строка длиной во весь широкий монитор не читается,
   глаз теряет начало следующей. */
.chat{display:flex;flex-direction:column;height:100%;min-height:0}
.chat-head{
  flex:0 0 auto;padding:12px 20px;border-bottom:1px solid var(--border);
  background:var(--panel);
}
.chat-head-inner{max-width:820px;margin:0 auto;display:flex;align-items:baseline;gap:12px}
.chat-head .chat-title{font-weight:600;font-size:15px}
.chat-head .chat-note{color:var(--muted);font-size:12px}
.chat-scroll{flex:1;min-height:0;overflow-y:auto;padding:20px 0 8px}
.chat-inner{max-width:820px;margin:0 auto;padding:0 20px;display:flex;flex-direction:column;gap:18px}
.chat-foot{
  flex:0 0 auto;border-top:1px solid var(--border);background:var(--panel);
  padding:12px 20px 14px;
}
.chat-foot-inner{max-width:820px;margin:0 auto}

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

   Ширина строки здесь не ограничена восемьюстами точками, как в разговоре:
   колонка задачи уже узкая, и второе ограничение оставило бы пустые поля по
   краям вместо текста. */
.task-chat{
  height:min(62vh,620px);min-height:320px;margin-top:10px;
  border:1px solid var(--border);border-radius:10px;overflow:hidden;
  background:var(--panel-2);
}
.task-chat .chat-scroll{padding:14px 0 6px}
.task-chat .chat-inner{max-width:none;padding:0 14px;gap:14px}
.task-chat .chat-foot{padding:10px 14px 12px}
.task-chat .chat-foot-inner{max-width:none}
/* Как получен ответ. Строка появляется только у тяжёлого режима: писать
   «ответ дан одним вызовом» под каждой репликой значит приучить не читать. */
.mode-note:empty{display:none}
.mode-note{
  margin-top:6px;font-size:11px;color:var(--muted);
  border-left:2px solid var(--accent);padding-left:8px;
}
/* Событие работы в ленте: та же плитка, но приглушённая. Это не чья-то реплика,
   а отметка машины о переходе, и путать её с разговором нельзя. */
.turn-event .turn-who{color:var(--muted);font-weight:500}
.turn-event .turn-body{color:var(--muted);font-size:13px}

/* Реплика. Без пузырей и без выравнивания по правому краю: это переписка с
   организацией, а не мессенджер, и длинный текст в пузыре читается хуже. Автора
   несёт подпись, свою реплику отличает левая граница. */
.turn{display:flex;flex-direction:column;gap:6px}
.turn-head{display:flex;align-items:baseline;gap:8px}
.turn-who{font-weight:600;font-size:13px}
.turn-time{font-size:11px;color:var(--faint);font-variant-numeric:tabular-nums}
.turn-body{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.55}
.turn.mine{border-left:2px solid var(--accent);padding-left:12px;margin-left:-14px}
.turn.mine .turn-who{color:var(--accent)}
.turn-tag{
  font-size:11px;padding:1px 6px;border-radius:4px;
  background:var(--p1-soft);color:var(--red);
}

/* Поле ввода. Растёт под текст до предела и дальше прокручивается: жёсткие две
   строки прячут начало собственной реплики. */
.composer-box{
  display:flex;gap:8px;align-items:flex-end;
  border:1px solid var(--border);border-radius:10px;background:var(--panel-2);
  padding:8px 8px 8px 12px;
}
.composer-box:focus-within{border-color:var(--accent)}
.composer-box textarea{
  flex:1;border:none;background:transparent;color:var(--text);outline:none;
  resize:none;min-height:24px;max-height:200px;line-height:1.5;padding:4px 0;
}
.composer-hint{
  display:flex;justify-content:space-between;gap:12px;
  font-size:11px;color:var(--faint);margin-top:6px;
}
.composer-hint kbd{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;
  border:1px solid var(--border);border-radius:3px;padding:0 3px;
}
.composer-box .mic{
  flex:0 0 auto;
  width:34px;height:34px;border:1px solid var(--border);border-radius:50%;
  background:transparent;color:var(--v21-fg-2);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  font-size:16px;padding:0;
}
.composer-box .mic[hidden]{display:none}
.composer-box .mic.recording{
  animation:micPulse 1.2s ease-in-out infinite;
  border-color:var(--red);color:var(--red);
}
.voice-state,.voice-interim{
  min-height:1.2em;
  margin-top:4px;
  color:var(--muted);
  font-size:12px;
}
.voice-interim{font-style:italic}
@keyframes micPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.4)}
  50%{box-shadow:0 0 0 8px rgba(239,68,68,0)}
}
/* Куда пойдёт новая задача: видно ДО отправки, а не после. Имя проекта
   усекается, чтобы длинное название не растягивало строку ввода. */
.proj-chip{display:inline-flex;align-items:center;gap:6px;max-width:100%;
  font-size:11px;color:var(--muted,#93a0bd);margin-bottom:6px}
.proj-chip .proj-chip-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--fg-2,#d7def0)}
.proj-chip button{background:none;border:0;color:var(--muted,#93a0bd);
  cursor:pointer;text-decoration:underline;font-size:11px;padding:0}

/* Предложение действия. Отдельная карточка, а не строка в тексте: нажатие
   что-то меняет в системе, и это обязано выглядеть иначе, чем ответ словами. */
.proposal{
  border:1px solid var(--border);border-left:3px solid var(--yellow);
  border-radius:8px;background:var(--panel-2);padding:12px 14px;
}
.proposal-cap{
  font-size:10px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--yellow);font-weight:600;margin-bottom:6px;
}
.proposal-what{font-weight:500;margin-bottom:4px}
.proposal-why{font-size:12px;color:var(--muted);margin-bottom:10px}
.proposal-acts{display:flex;gap:8px;align-items:center}
.proposal-done{font-size:12px;color:var(--green);font-weight:500}
.proposal-fail{font-size:12px;color:var(--red)}

/* Канбан по состояниям: колонки берутся из машины состояний, не красятся
   (различие несёт цвет надписи), а недопустимые при перетаскивании гаснут и
   называют причину. */
.kan-col.guard-off{opacity:.35}
.kan-col.guard-on{border-color:var(--accent)}
.guard-why{
  font-size:11px;color:var(--muted);padding:6px 10px;border-top:1px dashed var(--border);
}
.state-dot{width:8px;height:8px;border-radius:50%;display:inline-block;flex:0 0 auto}
.state-dot.running{background:var(--green)}
.state-dot.watched{background:var(--yellow)}
.state-dot.halted{background:var(--red)}
.state-dot.awaiting_human{background:var(--accent)}
.state-dot.pending{background:var(--faint)}
.state-dot.finished{background:var(--grey)}

/* Объяснённый ноль: три вида, различаются цветом надписи и наличием действия.
   Пустая доска без причины уже стоила проекту трёх суток простоя. */
.zero{
  border:1px solid var(--border);border-radius:8px;background:var(--panel-2);
  padding:16px 18px;max-width:62ch;
}
.zero-kind{
  font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;
  margin-bottom:6px;
}
.zero.nothing .zero-kind{color:var(--green)}
.zero.nocapacity{border-left:3px solid var(--red)}
.zero.nocapacity .zero-kind{color:var(--red)}
.zero.waiting .zero-kind{color:var(--accent)}
.zero-title{font-weight:600;margin-bottom:4px}
.zero-text{color:var(--muted);font-size:13px}
.zero-dur{font-variant-numeric:tabular-nums}

/* Доска */
.board{display:flex;gap:12px;overflow-x:auto;padding-bottom:12px;align-items:flex-start}
.col{
  flex:0 0 300px;background:var(--panel-2);border:1px solid var(--border);
  border-radius:8px;display:flex;flex-direction:column;min-height:200px;
}
.col-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:10px 12px;font-weight:600;font-size:13px;border-bottom:1px solid var(--border);
}
.col-count{
  font-size:11px;color:var(--muted);background:var(--panel);
  padding:1px 8px;border-radius:10px;border:1px solid var(--border);
}
.col-body{padding:8px;display:flex;flex-direction:column;gap:8px;flex:1}
.col-body.drag-over{background:var(--accent-soft)}

.card{
  background:var(--panel);border:1px solid var(--border);border-radius:6px;
  padding:10px;cursor:pointer;transition:box-shadow .15s,border-color .15s;
  position:relative;
}
.card:hover{box-shadow:var(--shadow);border-color:var(--muted)}
.card.p1{border-left:3px solid var(--p1)}
.card.p1::after{
  content:"P1";position:absolute;top:6px;right:6px;
  font-size:9px;font-weight:800;color:var(--p1);
  background:var(--p1-soft);padding:1px 5px;border-radius:8px;letter-spacing:.3px;
}
.card-seq{font-size:11px;color:var(--muted);font-weight:600}
.card-title{font-size:13px;font-weight:600;margin-top:2px;line-height:1.35}
.card-meta{font-size:11px;color:var(--muted);margin-top:6px;display:flex;flex-direction:column;gap:2px}
.card-meta b{color:var(--text);font-weight:500}
.card-prio{font-size:10px;color:var(--faint);font-weight:600}
.card-transitions{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border)}
.card-transitions-loading{font-size:10px;color:var(--faint);border-top-style:dashed}
.kan-transition-btn{padding:5px 8px;font-size:10.5px;line-height:1.2;touch-action:manipulation;cursor:pointer}
.kan-transition-btn:disabled,.kan-transition-btn[aria-disabled=true],.kan-transition-btn[aria-busy=true]{opacity:.55;cursor:not-allowed}
.kan-transition-btn:focus-visible,.trans-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.empty-col{font-size:12px;color:var(--faint);padding:14px 8px;text-align:center}

/* Дерево заданий */
.task-layout{display:grid;grid-template-columns:300px 1fr;gap:16px;align-items:flex-start}
@media (max-width:820px){.task-layout{grid-template-columns:1fr}}
.side-panel{
  background:var(--panel);border:1px solid var(--border);border-radius:8px;
  padding:12px;position:sticky;top:64px;max-height:calc(100vh - 80px);overflow:auto;
}
.side-title{font-size:12px;font-weight:600;color:var(--muted);margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}
.project-item{
  padding:9px 11px;border-radius:6px;cursor:pointer;font-size:13px;
  border:1px solid transparent;margin-bottom:4px;
}
.project-item:hover{background:var(--panel-2)}
.project-item.active{background:var(--accent-soft);color:var(--accent);border-color:var(--accent-soft)}
.tree-panel{
  background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:16px;min-height:400px;
}
.tree-node{margin-left:0}
.tree-children{margin-left:20px;border-left:1px dashed var(--border);padding-left:12px}
.tree-row{
  display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:6px;
  cursor:pointer;transition:background .12s;
}
.tree-row:hover{background:var(--panel-2)}
.tree-seq{font-size:11px;color:var(--muted);font-weight:600;min-width:40px}
.tree-title{font-size:13px;flex:1}
.tree-status{font-size:10px;padding:1px 7px;border-radius:10px;font-weight:600;white-space:nowrap}
.tree-trust{font-size:10px;color:var(--faint)}
.tree-empty{color:var(--muted);font-size:13px;padding:8px}

/* Карточки статусов */
.st-backlog{background:rgba(107,119,140,.16);color:var(--grey)}
.st-queued{background:rgba(0,82,204,.14);color:var(--accent)}
.st-in_progress{background:rgba(0,135,90,.14);color:var(--green)}
.st-review{background:rgba(255,153,31,.18);color:#b86e00}
.st-awaiting_approval{background:rgba(191,38,0,.14);color:var(--red)}
.st-done{background:rgba(0,135,90,.22);color:var(--green)}
.st-blocked{background:rgba(191,38,0,.18);color:var(--red)}
.st-cancelled{background:rgba(107,119,140,.22);color:var(--faint)}

/* Просмотр задачи */
.task-detail{display:grid;grid-template-columns:1fr 320px;gap:16px;align-items:flex-start}
@media (max-width:980px){.task-detail{grid-template-columns:1fr}}
.task-main{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:20px}
.back-link{
  display:inline-flex;align-items:center;gap:4px;font-size:12px;color:var(--muted);
  background:none;border:none;padding:4px 0;margin-bottom:8px;
}
.back-link:hover{color:var(--accent)}
.task-head{display:flex;align-items:flex-start;gap:12px;margin-bottom:4px}
.task-seq{font-size:12px;color:var(--muted);font-weight:700;padding-top:2px}
.task-title{font-size:20px;font-weight:700;margin:0;letter-spacing:-.3px}
.task-body{margin-top:14px;color:var(--text);white-space:pre-wrap;word-break:break-word;font-size:13.5px}
.section-title{font-size:12px;font-weight:600;color:var(--muted);margin:18px 0 6px;text-transform:uppercase;letter-spacing:.5px}
.criteria{margin:0;padding-left:18px;font-size:13px}
.criteria li{margin-bottom:4px}
.task-aside{display:flex;flex-direction:column;gap:12px;position:sticky;top:64px}
.meta-box{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px}
.meta-row{display:flex;justify-content:space-between;align-items:center;font-size:12.5px;padding:5px 0;border-bottom:1px solid var(--border)}
.meta-row:last-child{border-bottom:none}
.meta-key{color:var(--muted)}
.meta-val{font-weight:500;text-align:right;max-width:60%}
.meta-act{display:block;margin-top:4px;margin-left:auto;background:transparent;border:none;padding:0;font-size:12px;color:var(--muted);cursor:pointer}
.meta-act:hover{color:var(--accent)}
.status-badge{font-size:11px;padding:2px 9px;border-radius:12px;font-weight:600;display:inline-block}

/* Переходы состояния на экране задачи.
   drag-and-drop на канбане не работает с клавиатуры и тача, а переход
   рукой человека — единственный способ сдвинуть задачу по графу состояний.
   Кнопки берутся из готовой ручки /transitions и шлются в /state. */
.trans-list{display:flex;flex-direction:column;gap:6px;margin-top:6px}
.trans-btn{justify-content:flex-start;width:100%;font-weight:500;font-size:12.5px;cursor:pointer}
.trans-btn:disabled,.trans-btn[aria-disabled=true],.trans-btn[aria-busy=true]{opacity:.55;cursor:not-allowed}

/* Переписка */
.messages-wrap{margin-top:20px;border-top:1px solid var(--border);padding-top:14px}
.msg-list{display:flex;flex-direction:column;gap:8px;margin-bottom:12px}
.msg{
  background:var(--panel-2);border:1px solid var(--border);border-radius:8px;
  padding:10px 12px;position:relative;
}
.msg.untrusted{
  border-color:var(--red);background:rgba(191,38,0,.06);
  border-left:3px solid var(--red);
}
.msg.interrupt{border-left:3px solid var(--yellow)}
.msg-head{display:flex;align-items:baseline;gap:8px;margin-bottom:4px;flex-wrap:wrap}
.msg-author{font-weight:600;font-size:13px}
.msg-title{font-size:11px;color:var(--muted)}
.msg-time{font-size:11px;color:var(--faint);margin-left:auto}
.msg-body{font-size:13px;white-space:pre-wrap;word-break:break-word}
.msg-tag{
  display:inline-block;font-size:9px;font-weight:800;letter-spacing:.4px;
  padding:1px 6px;border-radius:8px;text-transform:uppercase;margin-left:6px;vertical-align:middle;
}
.tag-interrupt{background:rgba(255,153,31,.2);color:#b86e00}
.tag-untrusted{background:rgba(191,38,0,.18);color:var(--red)}
.composer{display:flex;gap:8px;margin-top:8px}
.composer textarea{
  flex:1;padding:9px 11px;border:1px solid var(--border);border-radius:6px;
  background:var(--panel-2);color:var(--text);resize:vertical;min-height:42px;max-height:140px;outline:none;
}
.composer textarea:focus{border-color:var(--accent)}
.composer .btn{align-self:flex-start}

/* Прочее */
.toast{
  position:fixed;bottom:20px;right:20px;background:var(--panel);
  border:1px solid var(--border);border-left:3px solid var(--red);
  padding:12px 16px;border-radius:6px;box-shadow:var(--shadow-lg);
  font-size:13px;max-width:340px;z-index:100;animation:slidein .2s ease;
}
.toast.ok{border-left-color:var(--green)}
@keyframes slidein{from{transform:translateY(10px)}to{transform:none}}
/* opacity не анимируется: в момент мутации текста регион должен быть видим,
   иначе часть скринридеров (VoiceOver) не объявляет live-регион на opacity:0. */
.spinner{
  display:inline-block;width:14px;height:14px;border:2px solid var(--border);
  border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
.loading{display:flex;align-items:center;gap:10px;color:var(--muted);padding:20px;font-size:13px}
.state-empty{padding:40px 20px;text-align:center;color:var(--muted);font-size:14px}
/* Блок отказа загрузки: отличается от пустого списка красной каймой и текстом
   причины. Те же отступы, что у .loading/.state-empty, чтобы встал на их месте. */
.load-err{border-left:3px solid var(--red);background:var(--p1-soft);padding:14px 16px;margin:16px}
.load-err .load-err-kind{color:var(--red);font-size:12px;font-weight:600;margin-bottom:4px}
.load-err .load-err-msg{color:var(--text);font-size:13px}
.load-err .load-err-hint{color:var(--muted);font-size:12px;margin-top:6px}
.subtle{color:var(--muted);font-size:12px}
.refresh-note{font-size:11px;color:var(--faint);margin-top:4px}

/* Классы вместо инлайновых стилей: политика содержимого запрещает style=,
   и заданный атрибутом отступ браузер молча не применяет. */
.mt-8  { margin-top: 8px; }
.mt-10 { margin-top: 10px; }
.mt-18 { margin-top: 18px; }
.mb-10 { margin-bottom: 10px; }
.mb-12 { margin-bottom: 12px; }
.subtitle { margin: 6px 0 4px; }
.brand-mark-sm { width: 26px; height: 26px; font-size: 13px; border-radius: 6px; }
.btn-sm { padding: 6px 12px; }
.state-empty-pad { padding: 20px; }

/* === Панель решений владельца ===
   Задача разметки одна: чтобы решение читалось и нажималось с телефона, не
   разворачивая ничего. Поэтому вариант это карточка со своей ценой, а не строка
   таблицы: в таблице цена варианта уезжает за правый край, и человек выбирает,
   не прочитав, что станет хуже. */
.staff-avatar{width:44px;height:44px;border-radius:50%;object-fit:cover;
  border:1px solid var(--border);margin-right:8px;flex:none}
.staff-avatar-none{visibility:hidden}
.tab{position:relative}
/* The count sits ABOVE the word, top-right, and must not stretch the
   button line: inline-block pushed the caption up on Решения/Приёмка. */
.tab-badge{
  position:absolute;top:-7px;right:-6px;min-width:18px;padding:0 5px;
  background:var(--p1);color:#fff;border-radius:9px;
  font-size:11px;font-weight:700;line-height:18px;text-align:center;
}
.dec-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.dec-sum{font-size:15px}
.dec-toggle{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:13px}

.dec{
  background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--border);
  border-radius:8px;padding:16px 18px;margin-bottom:14px;box-shadow:var(--shadow);
}
.dec-ready{border-left-color:var(--p1)}
.dec-decided{opacity:.72;border-left-color:var(--green)}
.dec-withdrawn{opacity:.55}
.dec-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.dec-title{margin:0;font-size:16px;font-weight:650;flex:1 1 auto;min-width:220px}
.dec-ring{color:var(--muted);font-size:12px;white-space:nowrap}
.dec-state{font-size:12px;padding:2px 8px;border-radius:10px;background:var(--panel-2);color:var(--muted);white-space:nowrap}
.dec-state-wait{background:var(--p1-soft);color:var(--p1);font-weight:600}
.dec-state-done{background:var(--accent-soft);color:var(--accent)}
.dec-context{font-size:14px;margin-bottom:8px;max-width:80ch}
.dec-blocks,.dec-free{font-size:13.5px;margin-bottom:8px;max-width:80ch}
.dec-src{color:var(--faint);font-size:12px;margin-bottom:12px;word-break:break-word}
.dec-empty{
  font-size:13.5px;color:var(--muted);background:var(--panel-2);
  border:1px dashed var(--border);border-radius:6px;padding:10px 12px;margin-bottom:12px;
}

.opts{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));margin-bottom:12px}
.opt{
  background:var(--panel-2);border:1px solid var(--border);border-radius:6px;
  padding:12px 13px;display:flex;flex-direction:column;gap:7px;
}
.opt-rec{border-color:var(--accent)}
.opt-chosen{border-color:var(--green);background:var(--panel)}
.opt-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.opt-label{font-weight:650}
.opt-tag{
  font-size:11px;padding:1px 7px;border-radius:9px;
  background:var(--accent-soft);color:var(--accent);white-space:nowrap;
}
.opt-tag-done{background:var(--panel-2);color:var(--green)}
.opt-body{font-size:13.5px}
.opt-cost{font-size:13px;color:var(--muted)}
.opt-cost-k{color:var(--yellow);font-weight:600}
.opt-ev{font-size:12px;color:var(--faint);word-break:break-word}
.opt-foot{display:flex;align-items:center;gap:10px;margin-top:auto;flex-wrap:wrap}
.opt-author{font-size:11.5px;color:var(--faint);flex:1 1 auto}

/* Отметка задачи для пакетного снятия. Коробка крупнее обычной: по ней
   попадают пальцем на телефоне, а список снимают именно с него. */
.dec-pick{display:flex;align-items:center;align-self:center}
.dec-pick input{width:17px;height:17px;cursor:pointer;accent-color:var(--p1)}
/* Отметка на карточке доски. Стоит перед номером и не растягивает шапку:
   карточек на экране десятки, и лишняя строка сместила бы всю колонку. */
.card-pick{width:15px;height:15px;margin-right:7px;vertical-align:-2px;cursor:pointer;accent-color:var(--p1)}

.dec-bulk{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:8px 12px;margin-bottom:10px;
  background:var(--panel-2);border:1px solid var(--border);border-radius:6px;
}

/* Acceptance screen card: same blocks as decisions, plus the acceptance criteria
   and the executor line. The criteria is highlighted separately because it is
   what the owner decides by, not by the title. */
.acc-criteria{font-size:13.5px;margin-bottom:8px;max-width:80ch;color:var(--fg-2)}
.acc-meta{font-size:12.5px;margin-bottom:10px}

.dec-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding-top:10px;border-top:1px solid var(--border)}
.dec-free-input{
  flex:1 1 220px;min-width:160px;padding:6px 9px;border:1px solid var(--border);
  border-radius:5px;background:var(--panel);color:var(--text);
}

@media (max-width:620px){
  .dec{padding:13px 14px}
  .dec-title{font-size:15px}
  .opts{grid-template-columns:1fr}
  .dec-actions{gap:6px}
  .dec-free-input{flex:1 1 100%}
}

/* Событие журнала в ленте задачи. Отличается от реплики намеренно: человек
   должен видеть, где сказанное человеком, а где сделанное машиной. */
.msg-event { border-left: 2px solid var(--line, #2a3550); background: transparent; }
.msg-event .msg-body { color: var(--muted, #93a0bd); }
.msg-tag.tag-move { background: rgba(90,140,255,.14); color: #8fb0ff; }
.msg-tag.tag-agent { background: rgba(120,110,255,.16); color: #a99cff; }
.msg-tag.tag-human { background: rgba(60,190,140,.16); color: #64d6a5; }

/* Сотрудники: карточка на человека или агента. */
.staff-dept { margin-bottom: 22px; }
.staff-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.staff-card { background: var(--panel, #141b2e); border: 1px solid var(--line, #223); border-radius: 10px; padding: 12px 14px; }
.staff-head { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.staff-name { font-weight: 600; }
.staff-title { color: var(--muted, #93a0bd); font-size: 13px; margin-bottom: 6px; }
.staff-meta { font-size: 12px; }
.profession-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.profession-card { display: flex; flex-direction: column; gap: 10px; }
.profession-card .staff-head { justify-content: flex-start; align-items: center; gap: 8px; }
.profession-card .staff-name { margin-right: auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profession-card .profession-agents:empty { display: none; }
.profession-card .profession-agents { flex: none; }
.profession-description { color: var(--text); font-size: 13px; line-height: 1.45; }
.profession-agents { display: flex; align-items: center; min-height: 26px; }
.profession-agent { display: inline-flex; border-radius: 50%; text-decoration: none; }
.profession-agent + .profession-agent { margin-left: -5px; }
.profession-agent .ava { margin-right: 0; box-shadow: 0 0 0 2px var(--panel, #141b2e); }
.profession-agent:hover .ava { position: relative; z-index: 1; border-color: var(--accent); }
.profession-path { font-size: 11px; overflow-wrap: anywhere; }

/* Переключатель оси доски. Раньше осей было два экрана, и человек должен был
   помнить, на каком из них какая правда. Теперь доска одна, а ось объявлена
   явно и подписана тем, что она означает: молчаливое переключение смысла
   колонок это тот же класс расхождения показаний, ради которого заведена
   машина состояний. */
.axis-switch{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:12px;
}
.axis-cap{
  font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);
}
.axis-btn{
  padding:5px 12px;border:1px solid var(--border);background:var(--panel);
  color:var(--muted);border-radius:6px;font-size:13px;
}
.axis-btn:hover{color:var(--text)}
.axis-btn.on{background:var(--accent-soft);color:var(--accent);border-color:var(--accent)}
.axis-note{font-size:12px;color:var(--faint)}

/* Проекты. Работу было буквально некуда положить: проектов не показывал ни один
   экран, хотя в модели они есть с самого начала (задача без родителя). */
.proj-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:4px}
.proj-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:12px}
.proj-card{
  background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px;
  display:flex;flex-direction:column;gap:8px;
}
.proj-head{display:flex;align-items:center;gap:8px}
.proj-seq{font-size:11px;color:var(--faint);font-variant-numeric:tabular-nums}
.proj-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.proj-meta{display:flex;gap:12px;flex-wrap:wrap;font-size:12px;color:var(--muted)}
.proj-warn{color:var(--accent)}
.proj-err{color:var(--red)}
.proj-acts{display:flex;gap:8px;margin-top:2px}

/* Модалка постановки. Поверх экрана, а не переходом: постановка не должна
   уводить человека с того места, где он работал. */
.modal-wrap{
  position:fixed;inset:0;background:rgba(9,30,66,.55);z-index:200;
  display:flex;align-items:center;justify-content:center;padding:24px;
}
.modal{
  width:100%;max-width:520px;background:var(--panel);border:1px solid var(--border);
  border-radius:10px;box-shadow:var(--shadow-lg);padding:20px;max-height:90vh;overflow-y:auto;
}
.modal-title{font-weight:600;font-size:16px}
.modal-sub{font-size:12px;color:var(--muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.modal textarea{
  width:100%;padding:9px 11px;border:1px solid var(--border);border-radius:6px;
  background:var(--panel-2);color:var(--text);resize:vertical;outline:none;
}
.modal textarea:focus,.modal input:focus{border-color:var(--accent)}
.modal-note{font-size:11px;color:var(--faint);margin-top:12px}
.modal-acts{display:flex;align-items:center;gap:8px;margin-top:14px}
.modal-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.modal select{
  width:100%;padding:9px 11px;border:1px solid var(--border);border-radius:6px;
  background:var(--panel-2);color:var(--text);outline:none;
}
@media (max-width:560px){ .modal-row{grid-template-columns:1fr} }

/* Вложения. Скрепка есть, хранилища файлов у платформы нет — файл уходит
   содержимым, и это подписано под полем. Молчаливая скрепка, «приложившая» файл
   в никуда, хуже отсутствующей: человек уверен, что собеседник файл видит. */
.clip{
  border:none;background:transparent;font-size:16px;line-height:1;padding:4px 2px;
  color:var(--muted);align-self:flex-end;
}
.clip:hover{color:var(--text)}
.composer-box.drop{border-color:var(--accent);background:var(--accent-soft)}
.attach-list{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:8px}
.attach{
  display:inline-flex;align-items:center;gap:6px;font-size:12px;
  background:var(--panel-2);border:1px solid var(--border);border-radius:6px;padding:3px 8px;
}
.attach-name{overflow-wrap:anywhere}
.attach-size{color:var(--faint);font-variant-numeric:tabular-nums}
.attach-x{border:none;background:transparent;color:var(--muted);font-size:14px;line-height:1;padding:0 2px}
.attach-x:hover{color:var(--red)}
.attach-note{font-size:11px;color:var(--faint)}
.attach-error{background:var(--error-soft);border-color:var(--error);color:var(--error)}
.attach-error-icon{font-weight:bold;margin:0 2px}
.attach-error-text{flex:1;max-width:400px;font-size:12px;line-height:1.3}
.materials-list{display:flex;flex-direction:column;gap:12px;margin-top:8px}
.material-item{background:var(--panel-2);border:1px solid var(--border);border-radius:6px;padding:12px;font-size:13px}
.material-title{font-weight:600;margin-bottom:4px}
.material-locator{font-family:monospace;font-size:11px;color:var(--muted);word-break:break-all;margin-bottom:6px;background:var(--panel);padding:6px;border-radius:3px}
.material-why{color:var(--faint);line-height:1.4;font-size:12px}
.attach-info{display:flex;align-items:center;gap:8px}
.attach-hint{font-size:11px;color:var(--faint);white-space:nowrap}
/* Дашборд. Сводит то, что жило за ссылками в шапке и уводило в новое окно.
   Плитка обязана нести не только число, но и подпись, что это число значит:
   голая цифра «0» одинаково выглядит и когда всё сделано, и когда всё сломалось. */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin-bottom:16px}
.tile{
  background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px;
}
.tile-n{font-size:28px;font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums}
.tile-l{font-size:13px;font-weight:500;margin-top:2px}
.tile-note{font-size:11px;color:var(--faint);margin-top:4px}
.tile.live .tile-n{color:var(--green)}
.tile.warn .tile-n{color:var(--accent)}
.tile.err .tile-n{color:var(--red)}
.dash-cols{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:14px}
.dash-block{
  background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px;
}
.caps{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);margin-bottom:8px}
.dash-line{font-size:13px;color:var(--accent);margin-bottom:6px}
.dash-task{
  display:flex;align-items:center;gap:8px;padding:6px 0;cursor:pointer;
  border-bottom:1px solid var(--border);
}
.dash-task:last-child{border-bottom:none}
.dash-task:hover .dash-title{color:var(--accent)}
.dash-seq{font-size:11px;color:var(--faint);font-variant-numeric:tabular-nums}
.dash-title{font-size:13px;overflow-wrap:anywhere}
@media (max-width:820px){ .dash-cols{grid-template-columns:1fr} }

/* Дочерние задачи внутри карточки верхнего уровня. Показаны списком, а не
   графом: на трёх десятках задач граф превращается в клубок, а «эта внутри той»
   читается строкой. Граф остаётся опцией, как и просил владелец. */
.kids{display:flex;flex-direction:column;margin-top:4px;border-top:1px solid var(--border)}
.kid{
  display:flex;align-items:center;gap:8px;padding:6px 0;cursor:pointer;
  border-bottom:1px solid var(--border);font-size:13px;
}
.kid:last-child{border-bottom:none}
.kid:hover .kid-title{color:var(--accent)}
.kid-seq{font-size:11px;color:var(--faint);font-variant-numeric:tabular-nums}
.kid-title{flex:1;overflow-wrap:anywhere}
.kid-state{font-size:11px;color:var(--muted)}
.kids-none{font-size:12px;color:var(--faint);margin-top:6px}

/* Диспетчерская: слева работа деревом, по центру разговор, справа справка.
   Средняя колонка резиновая, боковые фиксированы: разговор должен получать
   всю лишнюю ширину, а панели читаются одинаково на любом экране. */
/* Высота берётся от родителя, а не от магического calc(100vh - 96px): высота
   шапки не фиксирована (бейдж числа решений, перенос вкладок на узком экране),
   и любое её отличие от 96px уводило поле ввода за срез — .content.own-scroll
   режет overflow, и .chat-foot исчезал вместе с ним. Владелец видел поле
   секунду и терял. Родитель .view.active уже = 100% колонки, этого достаточно. */
.dispatch{display:grid;grid-template-columns:280px minmax(0,1fr) 260px;gap:14px;
  align-items:stretch;height:100%;min-height:0}
.dispatch-left,.dispatch-right{background:var(--panel,#141b2e);border:1px solid var(--line,#223);
  border-radius:12px;padding:12px;overflow-y:auto;min-height:0}
.dispatch-mid{min-width:0;min-height:0;display:flex;flex-direction:column}
.dispatch-head{font-size:12px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted,#93a0bd);margin-bottom:10px}
.dispatch-secondary-head{margin-top:18px}
.conversation-session{background:var(--panel-2);border:1px solid var(--border);border-radius:8px;padding:10px}
.session-empty{color:var(--muted);font-size:12px;margin-bottom:8px}
.session-facts{margin:0;display:flex;flex-direction:column;gap:8px}
.session-facts div{display:flex;flex-direction:column;gap:2px}
.session-facts dt{font-size:11px;color:var(--muted)}
.session-facts dd{margin:0;font-size:13px;font-weight:600;overflow-wrap:anywhere}
.session-actions{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.staff-jarvis{cursor:pointer}
.staff-jarvis:hover,.staff-jarvis:focus{border-color:var(--accent);outline:none}

.talk-mode{display:inline-flex;margin-left:auto;border:1px solid var(--border-ctl);border-radius:8px;overflow:hidden}
.talk-btn{border:0;background:transparent;color:var(--fg-2);font:inherit;padding:4px 10px;cursor:pointer}
.talk-btn+.talk-btn{border-left:1px solid var(--border-ctl)}
.talk-btn[aria-pressed="true"]{background:var(--accent);color:#fff}
.talk-btn:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.talk-jarvis{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.talk-jarvis[hidden]{display:none}
.chat.jarvis-mode>.chat-scroll,.chat.jarvis-mode>.chat-foot{display:none}
.chat.jarvis-mode>.talk-jarvis .chat-scroll{display:block}
.chat.jarvis-mode>.talk-jarvis .chat-foot{display:flex}
.session-field{display:block;color:var(--fg-3);font-size:12px;margin:12px 0 6px}
.conversation-session select{width:100%;min-width:0}
.session-provider-facts code{white-space:normal;overflow-wrap:anywhere;color:var(--fg-2)}
.session-error{color:var(--danger);font-size:12px;margin:8px 0;overflow-wrap:anywhere}

@media(max-width:1100px){.talk-jarvis{min-height:60vh}}
.disp-toolbar{display:flex;gap:6px;margin-bottom:8px}
.disp-search{flex:1;min-width:0;background:var(--field,#0e1424);border:1px solid var(--line,#223);
  border-radius:8px;color:inherit;font-size:12px;padding:6px 8px}
.disp-search::placeholder{color:var(--muted,#93a0bd)}
.disp-new{flex:0 0 auto;font-size:12px;padding:6px 10px}
.disp-node{margin-bottom:6px}
.disp-root{display:flex;align-items:center;gap:6px;cursor:pointer;padding:6px 4px;border-radius:8px}
.disp-root:hover{background:rgba(255,255,255,.04)}
.disp-root.selected{background:rgba(120,160,255,.14)}
.disp-caret{width:12px;color:var(--muted,#93a0bd);flex:0 0 auto}
/* Имя проекта усекается многоточием, а не ломает сетку: имя длиннее 60 знаков
   обычное дело (сырой текст задачи в заголовке — дефект, который мы правим),
   и без усечения широкое имя растягивает левую колонку и теснит разговор.
   Полный текст — в title, по наведению. */
.disp-name{flex:1;min-width:0;font-size:13px;line-height:1.35;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.disp-count{flex:0 0 auto;color:var(--muted,#93a0bd);font-size:11px}
.disp-badge{background:rgba(255,120,80,.18);color:#ff9b72;border-radius:10px;
  padding:1px 7px;font-size:11px;flex:0 0 auto}
.disp-kids{margin:2px 0 6px 18px;display:flex;flex-direction:column;gap:2px}
.disp-kid{display:flex;justify-content:space-between;gap:8px;cursor:pointer;
  padding:5px 6px;border-radius:6px;font-size:12px}
.disp-kid:hover{background:rgba(255,255,255,.04)}
.disp-kid-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.disp-kid-state{color:var(--muted,#93a0bd);flex:0 0 auto}
.fact{display:flex;justify-content:space-between;padding:7px 0;
  border-bottom:1px solid rgba(255,255,255,.05)}
.fact-key{color:var(--muted,#93a0bd);font-size:13px}
.fact-val{font-weight:600}
.fact-hot{color:#ff9b72}
/* Один брейкпоинт, как в дизайн-системе: боковые колонки уходят вниз. */
@media (max-width:1100px){
  .dispatch{grid-template-columns:1fr;height:auto}
  .dispatch-left,.dispatch-right{max-height:240px}
}
/* Тревожное слово внутри строки, а не отдельной плашкой: «молчит 40 мин» это
   часть предложения, и вырывать его в баннер значило бы кричать там, где надо
   назвать. Цвет берётся из той же таблицы токенов, что у плиток (--red), чтобы
   красный в интерфейсе означал одно и то же везде. */
.warn-text{color:var(--red)}
/* ============================================================
   Пульт, панель настройки, Developer Mode. Спроектировано Kimi K3
   13.08.2026 по требованиям владельца; первоисточник выдачи —
   research-ui/kimi-pult-design_v1.0.md, часть 4.1.
   ============================================================ */
/* === Пульт: правая колонка холста и полноэкранный режим ===
   Липкой остаётся только шапка с ответом на «всё ли штатно» и тревогой —
   правило трёх уровней: кричит одно место, остальное фоном. */
.pult{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--panel);border-left:1px solid var(--border)}
.pult-head{position:sticky;top:0;z-index:5;background:var(--panel);padding:12px 14px 10px;border-bottom:1px solid var(--border)}
.pult-status{font-size:16px;font-weight:600;line-height:1.3}
.pult-status.ok{color:var(--green)}
.pult-status.wait{color:var(--accent)}
.pult-status.err{color:var(--red)}
.pult-age{font-size:11px;color:var(--faint);margin-top:2px;font-variant-numeric:tabular-nums}
.pult-full-btn{margin-top:6px;border:none;background:transparent;color:var(--muted);font-size:12px;cursor:pointer;padding:2px 0}
.pult-full-btn:hover{color:var(--accent)}
.pult-scroll{flex:1;min-height:0;overflow-y:auto;padding:10px 12px;display:flex;flex-direction:column;gap:10px}
.pult-block{background:var(--panel-2);border:1px solid var(--border);border-radius:8px;padding:10px 12px}
.pult-cap{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);margin-bottom:6px}
.pult-line{display:flex;justify-content:space-between;gap:8px;padding:3px 0;font-size:13px;color:var(--text)}
.pult-line .n{font-variant-numeric:tabular-nums;font-weight:600}
.pult-note{font-size:12px;color:var(--muted);margin-top:4px}
.pult-budget{margin-top:8px}
.pult-sess{display:block;width:100%;text-align:left;border:none;background:transparent;border-top:1px solid var(--border);padding:7px 0;cursor:pointer;color:var(--text);font-size:13px}
.pult-sess:hover{background:var(--panel)}
.pult-sess-detail{font-size:12px;color:var(--muted);padding:4px 0 8px;white-space:pre-wrap}
.pult-ext{font-size:12px;color:var(--muted);text-decoration:underline}
/* Полноэкранный пульт: тот же набор блоков, сетка в три колонки чтения */
.pult.full{position:fixed;inset:0;z-index:150;border-left:none}
.pult.full .pult-scroll{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;align-content:start}

/* Полоса тихого отказа и устаревших данных: левая цветная граница 3px + мягкий фон —
   тот же рецепт, что у .toast и .proposal, новых цветов не вводится */
.stale-banner{border-left:3px solid var(--yellow);background:var(--panel-2);padding:6px 10px;font-size:12px;color:var(--muted);border-radius:0 6px 6px 0;margin:6px 0;display:flex;justify-content:space-between;gap:8px}
.stale-banner button{border:none;background:transparent;color:var(--accent);cursor:pointer;font-size:12px}
.fail-strip{border-left:3px solid var(--red);background:var(--p1-soft);padding:8px 12px;font-size:13px;color:var(--text);border-radius:0 6px 6px 0;margin:6px 0}
.wait-strip{border-left:3px solid var(--accent);background:var(--accent-soft);padding:8px 12px;font-size:13px;color:var(--text);border-radius:0 6px 6px 0;margin:6px 0}

/* Столбик очереди над линией лимита (атом queue-over-limit из 51a, раздел 11):
   без него «очередь пуста» и «очередь стоит, потому что слот занят» выглядят одинаково */
.queuebar{display:flex;align-items:flex-end;gap:3px;height:44px;margin:8px 0 2px;position:relative;border-bottom:2px solid var(--border)}
.queuebar .qslot{width:18px;background:var(--green);border-radius:3px 3px 0 0}
.queuebar .qslot.queued{background:var(--yellow)}
.queuebar .qlimit{position:absolute;left:0;right:0;border-top:1px dashed var(--red)}
.queuebar-cap{font-size:11px;color:var(--muted);display:flex;justify-content:space-between}
.queuebar-cap .over{color:var(--red)}

/* === Панель настройки под полем ввода ===
   Панель физически ПОД полем и растёт вниз: разворот не сдвигает ни textarea, ни ленту. */
.tune{border-top:1px solid var(--border);padding:4px 2px 0}
.tune-row{display:flex;align-items:center;gap:16px;min-height:28px;flex-wrap:wrap}
.tune-item{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
.tune-item select{font-size:12px;color:var(--text);background:var(--panel);border:1px solid var(--border);border-radius:6px;padding:2px 4px}
.tune-item input[type=checkbox]{accent-color:var(--accent)}
.tune-item.off{color:var(--faint)}
.tune-state{font-size:11px;color:var(--faint)}
.tune-more{margin-left:auto;border:none;background:transparent;color:var(--muted);font-size:12px;cursor:pointer;padding:2px 4px}
.tune-more:hover{color:var(--accent)}
/* Пояснения всплывают НАД всем подвалом, а не растягивают его и не накрывают
   поле ввода. Оба промаха видел своими глазами на живом стенде 13.08.2026:
   рост панели вниз толкал поле на 114 пикселей вверх (владелец прямо требовал,
   «чтобы поле ввода не уезжало»), а всплытие от самой панели закрывало поле
   целиком - человек не видел, куда писать. Отсчёт идёт от `.chat-foot`, поэтому
   пояснение встаёт над подвалом, в области ленты. */
.chat-foot{position:relative}
.tune-detail{display:none;padding:6px 0 2px;font-size:12px;color:var(--muted)}
.tune.open .tune-detail{position:absolute;bottom:100%;left:20px;right:20px;z-index:20;
  max-width:820px;margin:0 auto;
  background:var(--panel);border:1px solid var(--border);
  border-radius:8px;padding:8px 12px;box-shadow:var(--shadow-lg)}
.tune.open .tune-detail{display:block}
.tune-detail p{margin:2px 0}

/* Блок активации оптимизатора над полем ввода — тот же приём, что фишки вложений:
   снимается одним крестиком, исходный текст человека не трогается никогда */
.optim-block{border:1px solid var(--accent);border-left-width:3px;border-radius:6px;background:var(--accent-soft);padding:8px 10px;margin-bottom:6px;font-size:13px;color:var(--text);position:relative;white-space:pre-wrap}
.optim-block .attach-x{position:absolute;top:6px;right:8px}
.optim-block-cap{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--accent);margin-bottom:4px}

/* Карточка уточняющих вопросов в ленте — третий исход отправки из 51a, раздел 8 */
.optim-card{background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:8px;padding:10px 12px;margin:8px 0}
.optim-q{margin:8px 0}
.optim-q-t{font-size:13px;font-weight:600;margin-bottom:4px}
.optim-opt{display:inline-block;border:1px solid var(--border);border-radius:20px;padding:3px 10px;margin:2px 4px 2px 0;font-size:12px;cursor:pointer;background:transparent;color:var(--text)}
.optim-opt.on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.optim-own{width:100%;box-sizing:border-box;margin-top:4px;font-size:12px;padding:5px 8px;border:1px solid var(--border);border-radius:6px;background:var(--panel);color:var(--text)}

/* Смета директора до отправки: каждое число с источником и меткой факт/оценка */
.estimate{background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--yellow);border-radius:8px;padding:10px 12px;margin:6px 0}
.est-line{display:flex;justify-content:space-between;gap:10px;padding:3px 0;font-size:13px}
.est-line .est-src{font-size:11px;color:var(--faint)}
.est-fact{color:var(--green);font-size:11px}
.est-guess{color:var(--yellow);font-size:11px}
.est-acts{display:flex;gap:8px;margin-top:8px}
.est-fail{font-size:13px;color:var(--text);padding:4px 0}

/* === Developer Mode ===
   Системная разметка отличается моноширинной меткой и приглушением;
   идентификаторы подписаны словами — голый хеш не появляется и здесь */
.dev-toggle{border:1px solid var(--border);background:transparent;color:var(--muted);border-radius:20px;padding:3px 12px;font-size:12px;cursor:pointer}
.dev-toggle.on{border-color:var(--accent);background:var(--accent-soft);color:var(--accent)}
.dev-block{border:1px dashed var(--border);border-radius:6px;padding:6px 10px;margin:6px 0;font-size:12px;color:var(--muted)}
.dev-tag{font-family:ui-monospace,monospace;font-size:11px;letter-spacing:.04em;color:var(--faint);text-transform:uppercase}
.dev-tag.err{color:var(--red)}
.dev-kv{font-variant-numeric:tabular-nums;color:var(--muted)}
.dev-tools{margin-top:4px}
.dev-tools summary{cursor:pointer;font-size:12px;color:var(--muted)}
.dev-tool{font-family:ui-monospace,monospace;font-size:11px;color:var(--faint);padding:2px 0;white-space:pre-wrap}
.dev-note{font-size:12px;color:var(--muted);border-left:3px solid var(--grey);padding:4px 10px;margin:6px 0}

/* === Холст: ширины колонок и перестройка по брейкпоинтам ===
   Пульт уже 1024px уходит в оверлей: уже трёх колонок центр читать невозможно */
.canvas{display:flex;height:100%;min-height:0}
.canvas .rail{flex:0 0 280px;border-right:1px solid var(--border)}
.canvas .center{flex:1;min-width:0}
.canvas .pult{flex:0 0 360px}
@media (max-width:1279px){
  .canvas .rail{flex-basis:220px}
  .canvas .pult{flex-basis:300px}
}
@media (max-width:1023px){
  .canvas .pult{position:fixed;top:0;right:0;bottom:0;width:400px;max-width:92vw;z-index:140;box-shadow:var(--shadow-lg)}
  .pult.full .pult-scroll{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:767px){
  .canvas .rail{position:fixed;top:0;left:0;bottom:0;width:280px;max-width:85vw;z-index:140;background:var(--panel);box-shadow:var(--shadow-lg);transform:translateX(-100%);transition:transform .2s}
  .canvas .rail.open{transform:none}
  .pult.full .pult-scroll{grid-template-columns:1fr}
}

/* Материалы задачи. Пояснение НЕ сворачивается и не обрезается многоточием:
   критерий 4 NB-UI-021 требует, чтобы оно было видно без раскрытия, а
   ограничение таблицы (CHECK task_material_why_said, не меньше двадцати знаков)
   существует ровно потому, что голый список адресов не открывают. */
.materials{display:flex;flex-direction:column;gap:10px;margin:6px 0 4px}
.material{border:1px solid var(--line);border-radius:8px;padding:10px 12px}
.material-head{display:flex;gap:8px;align-items:baseline;justify-content:space-between}
.material-title{font-weight:600;overflow-wrap:anywhere}
.material-kind{font-size:.85em}
.material-locator{margin-top:4px;overflow-wrap:anywhere}
.material-locator code{font-size:.9em;color:var(--muted)}
.material-why{margin-top:6px;color:var(--fg);white-space:pre-wrap}

/* Отказ в списке вложений. Отличается от принятого файла цветом и рамкой, а не
   только текстом: строка «двоичный: приложить нельзя» рядом с принятыми файлами
   в одинаковом оформлении читается как ещё один приложенный файл, и человек
   отправляет реплику, считая, что файл ушёл.
   Критерий 1 NB-UI-021 требует, чтобы причина не исчезала по таймеру; она
   исчезает только по кнопке «убрать», как и принятый файл. */
.attach-rejected {
  border-color: var(--red);
  color: var(--red);
  background: transparent;
}
.attach-reason {
  opacity: .95;
  font-size: .92em;
}

/* === Runs screen === */
.runs-layout{display:grid;grid-template-columns:360px minmax(0,1fr);gap:14px;
  height:calc(100vh - var(--nav-h) - 60px);min-height:400px}
.runs-list-col{background:var(--panel);border:1px solid var(--border);
  border-radius:10px;display:flex;flex-direction:column;min-height:0;overflow:hidden}
.runs-detail-col{background:var(--panel);border:1px solid var(--border);
  border-radius:10px;padding:14px;overflow-y:auto}
.runs-toolbar{display:flex;flex-direction:column;gap:8px;padding:10px;
  border-bottom:1px solid var(--border)}
.runs-filters{display:flex;gap:6px;flex-wrap:wrap}
.runs-filter{background:var(--panel-2);border:1px solid var(--border);color:var(--muted);
  border-radius:8px;padding:4px 12px;font-size:12px;cursor:pointer;transition:.15s}
.runs-filter:hover{color:var(--text)}
.runs-filter.active{background:var(--accent-soft);border-color:var(--accent);
  color:var(--accent);font-weight:600}
.runs-search{width:100%;padding:7px 10px;border:1px solid var(--border);
  border-radius:8px;font-size:13px;background:var(--panel-2);color:var(--text)}
.runs-search:focus{border-color:var(--accent)}
.runs-list{overflow-y:auto;flex:1;min-height:0;padding:6px}
.run-row{padding:10px 12px;border-radius:8px;cursor:pointer;
  border:1px solid transparent;margin-bottom:2px}
.run-row:hover{background:var(--panel-2)}
.run-row.selected{background:var(--accent-soft);border-color:var(--accent)}
.run-what{font-size:13px;line-height:1.4;color:var(--text);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.run-meta{display:flex;align-items:center;gap:8px;margin-top:6px;
  font-size:11px}
.run-role{color:var(--muted);font-weight:500}
.run-time{white-space:nowrap}
.run-outcome{margin-left:auto;font-weight:600;padding:1px 8px;border-radius:10px}
.run-out-active{background:rgba(0,82,204,.12);color:var(--accent)}
.run-out-done{background:rgba(0,135,90,.16);color:var(--green)}
.run-out-err{background:rgba(191,38,0,.14);color:var(--red)}
.run-detail-head{border-bottom:1px solid var(--border);padding-bottom:12px;margin-bottom:12px}
.run-detail-what{font-size:15px;line-height:1.45;color:var(--text)}
.run-detail-subtle{margin-top:6px;font-size:12px}
.run-detail-role{font-weight:600;color:var(--text)}
.run-stopreport{margin-top:8px;font-size:12px;color:var(--muted);
  padding:8px 10px;background:var(--panel-2);border-radius:6px;white-space:pre-wrap}
.run-detail-toggle{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.run-toggle-hint{font-size:11px}
.run-flow{display:flex;flex-direction:column;gap:8px}
.run-payload{font-size:11px;max-height:300px;overflow:auto;padding:8px;
  background:var(--panel-2);border-radius:6px;white-space:pre-wrap;word-break:break-all}

/* Employee portrait. A circle of fixed size: an avatar that changes size with
   the length of the name tears the turn list apart vertically. */
.ava{
  display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:28px;height:28px;border-radius:50%;overflow:hidden;
  background:var(--panel-2);border:1px solid var(--border);
  font-size:12px;font-weight:600;color:var(--muted);
  vertical-align:middle;margin-right:8px;
}
.ava-sm{width:24px;height:24px;font-size:11px}
.ava-img{width:100%;height:100%;object-fit:cover;display:block;border-radius:50%}
img.ava-img.ava{margin-right:8px}
