    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    :root {
      --bg:            #f6f7fa;
      /* Единый цвет подложки: область контента рядом с чатом, шапки групп Ганта,
         групповые задачи в списках. Один токен — чтобы эти поверхности не
         расходились по оттенкам, как было с тремя разными хардкодами */
      --backdrop:      #eef1f6;
      /* Подложка области контента. По умолчанию = фон страницы; рядом с открытым
         чатом .flow-main-col делает её на тон глубже — и всё, что на ней сидит
         (фильтр-бар, Гант, строки), перекрашивается вместе с ней */
      --area-bg:       var(--bg);
      --sidebar-bg:    #f9f9f9;
      --sidebar-hover: rgba(0,0,0,0.05);
      --sidebar-active:rgba(0,0,0,0.07);

      --purple:        #051c3b;
      --purple-dark:   #0e3360;
      --purple-light:  #e7edf6;
      --purple-mid:    #c5d2e4;
      --purple-tab-bg: #eff2f7;

      --teal:          #2ab4a0;
      --red:           #e05252;
      --orange:        #f0a04b;

      --text-primary:  #1a1d35;
      /* Основной текст в карточках: описания разделов, подписи полей данных.
         Раньше жил инлайном как #3b4a5e в разметке каждой страницы */
      --text-body:     #3b4a5e;
      --text-secondary:#6b7280;
      --text-muted:    #9ca3af;
      --border:        #e8e7f3;
      --border-mid:    #d4d2e8;
      --card:          #ffffff;

      --shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.03);
      --shadow-md: 0 4px 12px rgba(0,0,0,0.07);
      --r:  8px;
      --rs: 5px;
    }

    body {
      font-family: 'Inter', -apple-system, sans-serif;
      background: #f6f7fa;
      color: var(--text-primary);
      display: flex;
      align-items: stretch;
      height: 100vh;
      overflow: clip;
      font-size: 13px;
      position: relative;
      padding: 6px;             /* поля окна: теснее, чем были 10 */
      gap: 10px;                /* один зазор между всеми панелями */
    }

    /* ────────────────── TEAM RAIL ────────────────── */
    .rail {
      width: 48px; min-width: 48px;
      background: #fff;
      border-radius: 14px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
      display: flex; flex-direction: column; align-items: center;
      padding: 10px 0 8px; gap: 4px;
      z-index: 20;
    }
    .rail-item {
      position: relative;
      width: 34px; height: 34px; border-radius: 9px;
      cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      font-size: 12px; font-weight: 700; color: #555;
      transition: all 0.12s;
    }
    .rail-item:hover { background: rgba(0,0,0,0.06); color: #111; }
    .rail-item.active { background: rgba(0,0,0,0.08); color: #111; }
    .rail-item.active::before {
      content: ''; position: absolute; left: -6px; top: 50%;
      transform: translateY(-50%);
      width: 3px; height: 20px; border-radius: 0 3px 3px 0;
      background: #111;
    }
    .rail-badge {
      position: absolute; top: -4px; right: -4px;
      background: var(--red); color: #fff;
      font-size: 9px; font-weight: 700; padding: 1px 5px;
      border-radius: 10px; line-height: 1.5;
      border: 2px solid #fff;
    }
    .rail-divider {
      width: 22px; height: 1px;
      background: #e0e0e0;
      margin: 3px 0; flex-shrink: 0;
    }
    .rail-plus {
      background: rgba(0,0,0,0.04);
      color: #aaa; font-weight: 400; font-size: 18px; line-height: 1;
    }
    .rail-plus:hover { background: rgba(0,0,0,0.08); color: #333; }
    .rail-spacer { flex: 1; }
    .rail-user {
      border-radius: 50%;
      background: linear-gradient(135deg,#2a4d7f,#ec4899);
      font-size: 11px; color: #fff;
    }
    .rail-status {
      position: absolute; bottom: -2px; right: -2px;
      width: 9px; height: 9px; border-radius: 50%;
      background: #34d399;
      border: 2px solid #fff;
    }

    /* ────────────────── SIDEBAR ────────────────── */
    .sidebar-col {
      width: var(--sidebar-w, 265px); min-width: var(--sidebar-w, 265px);
      display: flex; flex-direction: column;
      z-index: 10; position: relative;
    }
    /* Ручка изменения ширины — узкая зона у правого края, курсор-стрелка */
    .sidebar-resizer {
      position: absolute; top: 0; right: -4px; width: 9px; height: 100%;
      cursor: col-resize; z-index: 30; touch-action: none;
    }
    .sidebar-resizer::before {
      content: ''; position: absolute; top: 0; left: 4px; width: 1px; height: 100%;
      background: transparent; transition: background .12s;
    }
    .sidebar-resizer:hover::before,
    body.sidebar-resizing .sidebar-resizer::before { background: #b9c2d0; }
    body.sidebar-resizing { cursor: col-resize; user-select: none; }
    .sidebar {
      background: #fff;
      border-radius: 14px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
      display: flex; flex-direction: column; overflow: hidden;
      flex: 1; min-height: 0;
    }
    .sidebar > .logo { flex-shrink: 0; }
    /* Скроллер начинается ниже логотипа (от линии над «Выполнение»), без кнопок-стрелок */
    .sidebar-body {
      flex: 1; min-height: 0; display: flex; flex-direction: column;
      overflow-y: auto; overflow-x: hidden;
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
      /* Именно margin, а не padding: padding внутри скролл-контейнера виден
         только когда список домотан до конца, а зазор нужен всегда */
      margin-bottom: 5px;
    }
    .sidebar-body::-webkit-scrollbar { width: 5px; }
    .sidebar-body::-webkit-scrollbar-button { display: none; height: 0; width: 0; }
    .sidebar-body::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .sidebar-body::-webkit-scrollbar-thumb:hover { background: #b9b6d4; }
    .sidebar-body::-webkit-scrollbar-track { background: transparent; }
    .ws-pills-flat {
      margin: 0 0 10px;
      /* отступов по краям нет: слева бутерброд прижат к краю панели,
         справа к краю строки прижата «+ Задача» */
      padding: 0;
      /* высота не фиксирована: на узком сайдбаре «+ Задача» уезжает на вторую
         строку, а не сжимает пилюли пространств */
      min-height: 40px;
      display: flex; align-items: center; flex-wrap: wrap; row-gap: 6px;
      background: transparent;
      flex-shrink: 0;
    }

    /* Бутерброд слева от пилюль пространств — сворачивает сайдбар в узкую полосу */
    .sb-burger {
      /* Пока скрыт: раздел открывает полоса слева, бургер ничего не вызывал */
      display: none !important;
      /* 12px справа — столько же, сколько в первой строке страницы: при
         сворачивании пилюли пространств остаются на том же месте */
      width: 28px; height: 28px; flex-shrink: 0; margin-right: 12px;
      display: flex; align-items: center; justify-content: center;
      border: none; background: transparent; border-radius: 7px;
      color: #55617a; cursor: pointer;
      transition: background .12s, color .12s;
    }
    .sb-burger:hover { background: #e6eaf2; color: #16345c; }

    /* ── Свёрнутый сайдбар ──
       В полосе остаются бутерброд и пилюли пространств; сама панель становится
       поповером и выезжает вправо от полосы по наведению мыши (клик по
       бутерброду возвращает её на место) */
    /* Строка пространств переезжает в первую строку страницы, к хлебным крошкам */
    #mainTopbar > .ws-pills-flat {
      margin: 0 12px 0 0; padding: 0; min-height: 40px;
      flex-shrink: 0; flex-wrap: nowrap;
    }
    /* Бутерброд прижат к левому краю строки, пилюли отбиты от него и от «В работу» */
    #mainTopbar:has(> .ws-pills-flat) { padding-left: 0; }
    /* Первая строка идёт во всю ширину окна — над сайдбаром и контентом.
       app.js поднимает её в body, раскладку дальше держит грид */
    body:has(> #mainTopbar) {
      display: grid;
      grid-template-columns: auto minmax(0, 1fr);
      grid-template-rows: auto minmax(0, 1fr);
    }
    body > #mainTopbar { grid-column: 1 / -1; grid-row: 1; }
    /* Явные ячейки: когда сайдбар всплывает поповером и уходит из потока,
       контент не должен перепрыгивать в его нулевую колонку */
    body:has(> #mainTopbar) > .sidebar-col { grid-column: 1; grid-row: 2; }
    body:has(> #mainTopbar) > .content-col { grid-column: 2; grid-row: 2; }
    /* Чат отдельной колонкой между сайдбаром и контентом */
    body.chat-col-open:has(> #mainTopbar) { grid-template-columns: auto auto minmax(0, 1fr); }
    body.sb-hidden.chat-col-open:has(> #mainTopbar) { grid-template-columns: 0 auto minmax(0, 1fr); }
    body.chat-col-open:has(> #mainTopbar) > #chat-panel { grid-column: 2; grid-row: 2; }
    /* В свёрнутом сайдбаре зазоры сетки обнулены — колонке чата возвращаем свой,
       иначе полоса прокрутки ленты прилипает к карточке контента */
    body.sb-hidden.chat-col-open:has(> #mainTopbar) > #chat-panel { margin-right: 8px; }
    body.chat-col-open:has(> #mainTopbar) > .content-col { grid-column: 3; grid-row: 2; }
    /* Колонка чата без своей карточки: переписка сидит прямо на фоне страницы */
    /* .proj-panel — та же панель на страницах процесса, команды и конфигурации */
    body > #chat-panel.task-panel,
    body > #chat-panel.proj-panel {
      position: relative;
      display: flex; flex-direction: column; min-height: 0;
      /* Дефолт ширины — треть страницы без полосы (--left-col-def) */
      width: var(--chat-col-w, var(--left-col-def, 460px)); padding: 0; overflow: hidden;
      background: transparent; box-shadow: none;
    }
    /* Ручка ширины у правого края колонки — та же механика, что у сайдбара */
    .chat-col-resizer {
      position: absolute; top: 0; right: 0; width: 8px; height: 100%;
      cursor: col-resize; z-index: 30; touch-action: none;
    }
    .chat-col-resizer::before {
      content: ''; position: absolute; top: 0; right: 3px; width: 1px; height: 100%;
      background: transparent; transition: background .12s;
    }
    .chat-col-resizer:hover::before,
    body.sidebar-resizing .chat-col-resizer::before { background: #b9c2d0; }
    /* Гриппер виден всегда: короткая скруглённая метка по центру зазора
       между панелями — понятно, что границу можно тянуть */
    .chat-col-resizer::after {
      content: ''; position: absolute; top: 50%; right: -5px;
      transform: translateY(-50%);
      width: 3px; height: 36px; border-radius: 3px;
      background: #cdd5e0; transition: background .12s;
    }
    .chat-col-resizer:hover::after,
    body.sidebar-resizing .chat-col-resizer::after { background: #9fabbd; }
    /* Чат сущности из меню чипа: фрейм с vibe-страницей в «только чате»
       заполняет колонку, крестик — поверх фрейма в правом верхнем углу
       (шапка чата в доке освобождает ему место отступом справа) */
    .entity-chat-wrap {
      position: relative; flex: 1; min-height: 0;
      display: flex; flex-direction: column;
    }
    .entity-chat-wrap > .chat-dock-frame { flex: 1; min-height: 0; }
    /* Страница во фрейме области шелла — без своей обвязки: топбар и полосы
       прячем, поля страницы убираем (рамку области рисует сам шелл) */
    body.in-frame #mainTopbar,
    body.in-frame .lb-rail,
    body.in-frame .rb-rail,
    /* Сайдбар-фрагмент во фрейме некому размечать (leftbar.js выключен) —
       без разметки он показывался бы целиком, прячем вовсе */
    body.in-frame #sidebar-slot,
    body.in-frame .sidebar-col { display: none !important; }
    body.in-frame { padding: 0 !important; gap: 0 !important; }
    /* Композер стартового экрана — не шире 640px, как строка чата */
    .dash-groups .dpx-chat { max-width: 640px; margin-left: auto; margin-right: auto; }
    /* Рамку и тень рисует область шелла — карточка страницы во фрейме плоская */
    body.in-frame .main,
    body.in-frame .ai-main-col > .main,
    body.in-frame .head-card { border: none !important; box-shadow: none !important; border-radius: 0 !important; }
    /* Кнопки «свернуть панель» и «закрыть» дублировали бы кнопки области */
    body.in-frame .proj-header > .page-max,
    body.in-frame .proj-header > .page-close,
    body.in-frame .tab-bar-actions > .page-max,
    body.in-frame .tab-bar-actions > .page-close { display: none !important; }
    /* Значок сущности с её типом переехал в заголовок области (index.html
       копирует его при загрузке фрейма) — в самой шапке он больше не нужен */
    body.in-frame .proj-header > .head-mark { display: none !important; }
    /* «О чём этот экран» — тоже кнопка области: в кадре своя не нужна */
    body.in-frame .hint-toggle { display: none !important; }

    /* ── Композер на страницах разделов (app.js: sectionComposerLoad) ──
       Поле ввода прижато к низу фрейма, содержимое прокручивается над ним и
       затухает у нижнего края — так же, как лента чата на активностях */
    /* Своего верхнего поля строке инструментов не нужно: воздух от полосы
       вкладок держит поле самой ленты, как у любого первого блока.
       Снизу её и так отделяет отступ списка */
    /* Строка фильтров в ленте: 10px сверху и липкая — при прокрутке остаётся
       на месте, а содержимое уходит под неё */
    body .vibe-feed .plan-filter-bar {
      margin-top: 10px; margin-bottom: 0;
      position: sticky; top: 0; z-index: 15;
    }

    /* Список работ потока шире прочих блоков ленты: в строке кроме названия
       стоят навык, объём и статус — в 480px они наезжают друг на друга.
       Потолка у него нет вовсе: список забирает всё, что осталось от
       «Планирования», а тому отдаём ровно 480px и жаться не даём */
    body .vibe-feed #mini-scenario { max-width: none; }
    /* Ширину задаём и в строку, и в колонку: контейнер переключает
       направление, и одного flex-basis не хватает — в колонке он про высоту */
    body .vibe-feed #mini-scenario .vibe-panel-cols > .section {
      flex: 0 0 480px; width: 100%; max-width: 480px; align-self: stretch;
    }
    body .vibe-feed #mini-scenario .vibe-panel-cols > .scenario-list {
      flex: 1 1 auto; width: 100%; max-width: none;
    }
    /* Тот же потолок и вне ленты (панель показана вкладкой): без .vibe-feed
       правило выше не срабатывало, и «Планирование» тянулось на всю ширину.
       «Сценарий» из потолка исключён — ему нужны прежние 600px */
    body #app-scenario > .vibe-panel-cols > .section:not(.scenario-list) { max-width: 480px; margin-inline: auto; }
    body .vibe-feed .flow-works-bar { max-width: 600px; margin-left: auto; margin-right: auto; }

    /* Сверху у ленты то же поле, что по бокам; снизу воздух даёт собственный
       отступ последнего блока — своё поле там давало лишнюю прокрутку */
    /* Сверху поля нет: строка фильтров и первый блок стоят у самого верха
       области, свой отступ им даёт собственный margin */
    body .vibe-feed { padding-top: 0; padding-bottom: 0; }

    body.has-composer .view > .content {
      -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
              mask-image: linear-gradient(to bottom, #000 calc(100% - 40px), transparent);
    }
    /* На панелях-скроллхостах нижние 12px маски были непрозрачными — ради
       полосы прокрутки. Но маска общая на всю область, и вместе с полосой
       в этой щели проступали строки списка. Содержимое важнее: гасим до низа,
       полоса тает вместе с ним */
    /* Сверху поля нет: над композером и так стоит затухание содержимого,
       а на страницах со своей прокруткой — её полоса */
    body.has-composer .view > .vibe-foot { flex-shrink: 0; padding: 0 24px 14px; position: relative; }
    body.has-composer .view > .vibe-foot .dpx-chat { max-width: 800px; margin: 0 auto; }
    /* Композер сам не должен попадать под затухание — он вне области прокрутки */
    body.has-composer .view > .vibe-foot { z-index: 2; background: transparent; }
    /* Имя страницы, дублирующее заголовок области. Класс .in-frame здесь на
       <html> — его ставит крошечный скрипт в <head> каждой такой страницы,
       поэтому заголовок скрыт с первой отрисовки и не мелькает */
    html.in-frame .head-card .proj-title.page-title { display: none; }
    /* Если кроме этого имени в шапке ничего не осталось (табов нет, кнопки
       окна принадлежат области) — прячем и саму шапку: пустая полоса просто
       съедала место над содержимым */
    html.in-frame .head-card:has(> .inner > .proj-header > .proj-title.page-title):not(:has(.tab-bar)) {
      display: none;
    }
    /* Сырой код в шапке (до того, как eidScan собрал из него значок) не
       показываем: он рисуется разметкой сразу, а прячется только скриптом —
       и в кадре успевал мелькнуть в области имени. Собранный чип лежит уже
       внутри .head-mark, под это правило не попадает */
    .head-card .proj-header > .proj-id { display: none; }
    /* Док сущности — карточкой: рамка-тень по контуру, как у соседних панелей */
    .entity-chat-wrap {
      background: #fff; border-radius: 10px; overflow: hidden;
      box-shadow: 0 2px 8px rgba(0, 0, 0, .08), 0 0 0 1px rgba(0, 0, 0, .04);
    }
    /* Закрытый чат не оставляет колонку в сетке: панель, однажды созданная
       прямо в body (страницы без своего чата), прячется целиком */
    body:not(.chat-col-open) > #chat-panel { display: none; }
    /* Композер не прилипает к нижнему краю окна */
    body > #chat-panel .ai-foot { padding-bottom: 12px; }
    /* Лента отбита от правого края колонки — там ручка ширины и полоса прокрутки */
    body > #chat-panel .ai-body { padding-right: 32px; }
    #mainTopbar > .ws-pills-flat > .sb-burger { margin: 0 12px 0 0; }
    #mainTopbar > .ws-pills-flat > .ws-pills { margin-right: 10px; }
    /* «В работу» отбита от пилюль: margin-left: auto в строке по содержимому не работает */
    #mainTopbar > .ws-pills-flat > .task-btn { margin-left: 10px; }
    /* Свёрнутый сайдбар не занимает колонку — вместе с ней убираем и зазор,
       иначе контент отъезжает вправо на ширину gap */
    body.sb-hidden:has(> #mainTopbar) { grid-template-columns: 0 minmax(0, 1fr); column-gap: 0; }
    body.sb-hidden > .sidebar-col {
      width: 0; min-width: 0;
      /* Ширину не анимируем: в потоке она бы расталкивала контент вправо, а
         потом возвращала его обратно — поповер въезжает своей анимацией */
    }
    body.sb-hidden > .sidebar-col > .new-btn-wrap,
    body.sb-hidden > .sidebar-col > .sidebar,
    body.sb-hidden > .sidebar-col > .mode-pills,
    body.sb-hidden > .sidebar-col > .sidebar-user,
    body.sb-hidden > .sidebar-col > .sidebar-resizer { display: none; }
    /* Наведение на строку пространств раскрывает панель поповером: ширина
       растёт, а отрицательный внешний отступ оставляет её вне потока */
    /* Поповер выводим из потока: ширина в потоке остаётся нулевой,
       контент под панелью не двигается */
    body.sb-hidden > .sidebar-col.peek {
      /* Координаты считаются от ячейки грида (вторая строка), поэтому нули:
         панель встаёт ровно туда же, где стоит закреплённый сайдбар */
      /* left: 0 + внешний отступ: координаты считаются от padding-box тела,
         поэтому фиксированный left давал двойной отступ от края окна */
      position: absolute; left: 0; margin-left: 10px; top: 0; bottom: 10px;
      width: var(--sidebar-w, 265px); min-width: var(--sidebar-w, 265px);
      margin-top: 0; margin-right: 0; margin-bottom: 0; z-index: 80;
      animation: sbPeekIn .14s ease;
      /* Пустая полоса поповера над панелью накрывала бутерброд и съедала клик —
         события ловят только сами панель и карточка пользователя */
      pointer-events: none;
    }
    body.sb-hidden > .sidebar-col.peek > * { pointer-events: auto; }
    @keyframes sbPeekIn {
      from { opacity: 0; transform: translateX(-10px); }
      to   { opacity: 1; transform: none; }
    }
    body.sb-hidden > .sidebar-col.peek > .sidebar,
    body.sb-hidden > .sidebar-col.peek > .mode-pills,
    body.sb-hidden > .sidebar-col.peek > .sidebar-user {
      display: flex;
      box-shadow: 0 14px 38px rgba(16,30,60,0.22), 0 0 0 1px rgba(0,0,0,0.05);
    }

    /* Сплит-кнопка «Новая задача | ▾» — карточка в стиле панели учётки */
    .new-btn-wrap {
      position: relative; display: flex; gap: 8px;
      margin: 9px 0 19px; flex-shrink: 0;
    }
    /* display: flex перебивал [hidden] — на страницах, где создавать нечего,
       кнопка «Добавить» должна пропадать целиком */
    .new-btn-wrap[hidden] { display: none; }
    .new-btn-main, .nba-chev {
      height: 32px; min-height: 0; box-sizing: border-box;
      border: none; background: none; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      color: #16345c; font-size: 12.5px; font-weight: 600; white-space: nowrap;
      transition: background 0.12s;
    }
    /* «Добавить» — служебная кнопка: спокойная серая заливка, акцент отдан «+ Задаче» */
    .new-btn-split {
      display: flex; align-items: stretch; overflow: hidden;
      border-radius: 10px; cursor: pointer;
      /* Заливка только под курсором: в покое кнопка не спорит с содержимым */
      background: transparent;
      transition: background .12s;
    }
    .new-btn-split:hover { background: #d3ecef; }
    /* Шеврон стоит вплотную к подписи, а не у дальнего края кнопки */
    .new-btn-split .new-btn-main { padding-right: 2px; }
    .new-btn-split .nba-chev { padding: 0 10px 0 2px; }
    /* Подпись и «плюс» — циановые: подложка спокойная, а действие создающее */
    .new-btn-split .new-btn-main, .new-btn-split .nba-chev { color: #056470; }
    .new-btn-split .new-btn-ico { color: #056470; }
    .new-btn-split .new-btn-chev { color: #5fa8b2; }

    /* «+ Задача» — акцент строки рабочих пространств: тот же градиент, что был
       у сплит-кнопки; margin-left: auto прижимает её к правому краю строки */
    .task-btn {
      height: 32px; padding: 0 14px; gap: 7px; margin-left: auto; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; border-radius: 10px; cursor: pointer; white-space: nowrap;
      font: inherit; font-size: 12.5px; font-weight: 600; color: #16345c;
      background: linear-gradient(135deg, #c2ebdd 0%, #bfe1f0 48%, #cfd7f4 100%);
      box-shadow: 0 2px 6px rgba(0,120,150,.14), 0 0 0 1px rgba(0,152,166,.30);
      transition: filter .12s, box-shadow .12s;
    }
    .task-btn:hover { filter: brightness(1.04); box-shadow: 0 3px 9px rgba(0,120,150,.22), 0 0 0 1px rgba(0,152,166,.36); }
    .task-btn .new-btn-ico { color: #0098a6; }
    .new-btn-main { flex: 1 1 auto; gap: 7px; padding: 0 13px; }
    .nba-chev { flex: 0 0 auto; padding: 0 9px; }   /* разделителя между частями кнопки нет */
    .new-btn-main:hover, .nba-chev:hover { background: transparent; }
    .new-btn-ico {
      flex-shrink: 0; color: #0098a6;
      display: flex; align-items: center; justify-content: center;
    }
    .new-btn-chev { flex-shrink: 0; color: #3f6d84; transition: transform 0.15s; }
    .new-btn-wrap.open .new-btn-chev { transform: rotate(180deg); }

    .new-menu {
      display: none;
      position: absolute; top: calc(100% + 6px); right: 0; left: auto;
      min-width: 210px; white-space: nowrap;
      background: #fff; border-radius: 10px;
      box-shadow: 0 10px 28px rgba(15,30,60,0.16), 0 0 0 1px rgba(0,0,0,0.05);
      padding: 5px 0; z-index: 60;
      animation: fadeIn 0.15s ease both;
    }
    .new-btn-wrap.open .new-menu, .new-menu.floating { display: block; }
    /* Кнопки создания в топбаре — компактный горизонтальный вид */
    /* «+ Задача» стоит справа, за иконками поиска и ИИ (breadcrumb с flex:1 прижимает кластер вправо) */
    .topbar .new-btn-wrap { order: 2; margin: 0 0 0 12px; }
    /* В таб-баре кнопка уезжает вправо, но левее служебных кнопок таба */
    /* Правая группа таб-бара: кнопка создания и служебные кнопки в одну строку */
    /* Группа кнопок не липнет к линии таб-бара — 6px воздуха снизу */
    .tab-bar > .tab-bar-actions { margin-left: auto; display: flex; align-items: center; gap: 4px; flex-shrink: 0; margin-bottom: 6px; align-self: flex-end; }
    .tab-bar > .tab-bar-actions > .new-btn-wrap.in-tabs { margin: 0 4px 0 0; }
    /* Служебные кнопки группы — квадратные 30×30: во флексе они перестали
       растягиваться по высоте и подложка стала полоской */
    .tab-bar-actions > :is(.tab-more, .more-btn, .hint-toggle) {
      width: 32px; height: 32px; padding: 0; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      margin-left: 0 !important;
    }
    /* Пока карточка подсказки видна, кнопка «i» не нужна — правило группы
       перебивало базовое .hint-toggle { display: none } */
    .tab-bar-actions > .hint-toggle:not(.show) { display: none; }
    /* Кнопка не должна тянуть таб-бар вверх: компактная высота 32px */
    .new-btn-ico svg { width: 15px; height: 15px; }
    .topbar .new-btn-split { border-radius: 10px; }
    .topbar .new-btn-main, .topbar .nba-chev { font-size: 12px; }
    .topbar .new-btn-main { padding: 0 13px; gap: 6px; }
    .topbar .nba-chev { padding: 0 9px; }
    .topbar .new-btn-ico svg { width: 15px; height: 15px; }
    .new-menu-item {
      display: flex; align-items: center; gap: 10px;
      padding: 9px 14px; cursor: pointer;
      font-size: 13px; color: #16345c;
      transition: background 0.12s;
    }
    .new-menu-item:hover { background: #f3f6fa; }
    .new-menu-item svg { flex-shrink: 0; color: #7f8ea3; }
    .new-menu-item:hover svg { color: #16345c; }
    .new-menu-sep { height: 1px; background: #eef1f6; margin: 5px 0; }

    .logo {
      /* gap 10px: имя и подпись отбиты от знака пространства — на 6px текст
         почти касался квадрата с буквой */
      /* Высота ровно 60px — столько же, сколько у шапки потока */
      display: flex; align-items: center; gap: 10px;
      height: 60px; padding: 0 14px;
      /* Линия снизу отделяет шапку пространства от навигации */
      border-bottom: 1px solid var(--border);
      /* заливка снимается в такт со сворачиванием разделов, иначе она моргает в конце */
      transition: background .16s ease, border-color .16s ease;
    }
    .logo-icon {
      width: 32px; height: 32px; border-radius: 8px;
      background: transparent;
      display: flex; align-items: center; justify-content: center;
      flex-shrink: 0;
    }
    /* Знак пространства — буква в скруглённом квадрате, оформление как у .ws-pill сверху */
    .logo-mark {
      width: 32px; height: 32px; border-radius: 10px;
      display: flex; align-items: center; justify-content: center;
      font-size: 13px; font-weight: 700; color: #fff;
      background: linear-gradient(145deg,#3a5e94,#23436f);
      box-shadow: 0 2px 5px rgba(40,55,80,0.18), inset 0 1px 0 rgba(255,255,255,0.18);
    }
    .logo-name { font-size: 15.5px; font-weight: 600; color: #111; line-height: 1.25; margin-bottom: 3px; }
    .logo-sub  { font-size: 9px; color: #aaa; text-transform: uppercase; letter-spacing: 1.2px; }

    /* Единый вид полос прокрутки для всех областей, у которых нет своего правила.
       Частные правила (скрытые полосы таб-бара и диаграммы) имеют выше специфичность. */
    * { scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent; }
    *::-webkit-scrollbar { width: 5px; height: 5px; }
    *::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    *::-webkit-scrollbar-thumb:hover { background: #b9b6d4; }
    *::-webkit-scrollbar-track { background: transparent; }
    *::-webkit-scrollbar-button { display: none; height: 0; width: 0; }

    .nav-section { padding: 10px 10px 2px; }
    .nav-section + .nav-section { margin-top: 14px; }
    /* Счётчики раздела выровнены со счётчиками чатов ниже (там правее стоит звезда) */
    .exec-section .nav-item > .nav-badge.count { margin-right: 0; }
    /* «Выполнение» оформлено как «Управление»: те же размеры иконок, вес и яркость текста */
    .exec-section .nav-item { gap: 6px; font-weight: 400; }
    .exec-section .nav-item > svg { width: 13px; height: 13px; color: #9aa6b6; }
    .exec-section .nav-item:hover > svg { color: #6b7a8f; }
    .exec-section + .nav-section { margin-top: 6px; }             /* блоки ближе друг к другу */
    /* Порядок пунктов раздела задаём стилями, а не разметкой: список бывшего
       «Контроля» остаётся отдельным узлом (на нём держится режим избранного),
       а display:contents пускает его пункты в общий поток, чтобы «Результаты работы»
       и «Инструкции» могли встать между «Исполнителями» и «Активностью» */
    .exec-section { display: flex; flex-direction: column; }
    .nav-section.exec-section .dash-list { display: contents; }   /* перебивает display:flex у .dash-section .dash-list ниже */
    .exec-section > .nav-item { order: 1; }                                      /* Задания */
    /* Инструкции и результаты работы — сразу за «Работами»: тот же order, что у «Потоков
       работ», порядок между ними задаёт разметка сайдбара. Оба пункта обёрнуты
       в .tree-node — у них свои раскрывающиеся списки */
    .exec-section > .tree-node:has(> .nav-item[data-page="instructions"]),
    .exec-section > .tree-node:has(> .nav-item[data-page="artifacts"]) { order: 2; }
    .exec-section .dash-list > .tree-node:has([data-dash="svodka"])   { order: 2; }   /* Потоки работ — сразу под «Моими заданиями» */
    .exec-section .dash-list > .perf-node                             { order: 4; }   /* Исполнители — за потоками работ */
    .exec-section > .config-node                                      { order: 9; }   /* Конфигурация — замыкает блок сущностей */
    .exec-section .dash-list > .tree-node:has([data-dash="activity"]) { order: 10; }
    .exec-section > .dir-node                                         { order: 10; }  /* Направления — перед «Активностью» */
    .exec-section > .pin-node                                         { order: 10; }  /* Закреплённые — сразу за направлениями */
    .exec-section > .act-node                                         { order: 10; }
    .exec-section > .chat-node                                        { order: 11; }  /* Чаты — последними в разделе */
    .exec-section > .nav-label { margin-bottom: 10px; }           /* нижний отступ как у «Управления» */
    .nav-label {
      font-size: 9px; font-weight: 600; letter-spacing: 1.1px;
      text-transform: uppercase; color: #bbb; margin-bottom: 2px; padding: 0 6px;
    }
    /* Статический заголовок группы в сайдбаре: та же подпись, что у .nav-label,
       плюс стрелка сворачивания. Ни подложки, ни перехода — это не пункт */
    .sidebar .nav-head {
      display: flex; align-items: center; gap: 4px;
      margin: 10px 0 2px; padding: 0 6px;
      font-size: 9px; font-weight: 600; letter-spacing: 1.1px;
      text-transform: uppercase; color: #bbb;
      cursor: pointer; user-select: none; background: none;
    }
    .sidebar .nav-head:hover { color: #9aa3b2; background: none; }
    .sidebar .nav-head > .tree-arrow { width: 10px; }
    .tree-node.open > .nav-head > .tree-arrow { transform: rotate(90deg); }

    .nav-item {
      display: flex; align-items: center; gap: 8px;
      height: 30px; padding: 0 8px; border-radius: 7px;
      color: #8b95a5; cursor: pointer;
      font-size: 13px; font-weight: 500; transition: background 0.12s;
    }
    .nav-item svg { color: #8b95a5; flex-shrink: 0; }
    /* Пункт «внимание»: текст и иконка обычного цвета — на внимание работает
       только счётчик, бледный с тёмной цифрой (красный пункт спорил с ним) */
    .nav-item:hover { background: var(--sidebar-hover); }
    .nav-item.active {
      color: #111; background: #eef2f8; font-weight: 600;
    }
    .nav-item.active svg { color: #2a4d7f; }
    /* Пункт над/под деревом «Структуры»: иконку выравниваем по иконкам дерева ниже
       (у элементов дерева иконка сдвинута стрелкой раскрытия на 16px) */
    .nav-item.ni-tree { padding-left: 24px; gap: 6px; }
    /* Иконка того же размера, что у дерева (13px) — центры совпадают */
    .nav-item.ni-tree svg { width: 13px; height: 13px; }
    /* Цвет как у элементов дерева (бирюзовый), кроме accent-пункта и активного */
    .nav-item.ni-tree:not(.attn):not(.active),
    .nav-item.ni-tree:not(.attn):not(.active) svg { color: #0098a6; }
    /* «Выполнение» как лист дерева, но с красным акцентом */
    .proj-subs > .tree-node > .tree-item.tree-accent,
    .proj-subs > .tree-node > .tree-item.tree-accent .tree-ico { color: #d9534f; }
    /* Остальные пункты «Структуры» (кроме акцентного «Выполнение») — серым текстом
       и иконкой; активность отмечается фоном-подсветкой, цвет остаётся серым */
    .struct-nav .proj-subs > .tree-node > .tree-item:not(.tree-accent),
    .struct-nav .proj-subs > .tree-node > .tree-item:not(.tree-accent) .tree-ico { color: #8b95a5; }
    .nav-item.attention { color: #e07a73; }
    .nav-item.attention svg { color: #e07a73; }
    .nav-item.attention:hover { background: rgba(224,122,115,0.08); }
    /* Приглушённый кирпичный вместо алого #e74c3c: счётчиков в сайдбаре много,
       и яркий красный кричал на весь список */
    .nav-item.attention .nav-badge, .nav-badge.count {
      background: #c96a62; color: #fff;
      min-width: 18px; height: 18px; padding: 0;
      display: flex; align-items: center; justify-content: center;
      border-radius: 50%; line-height: 1;
    }
    .nav-badge.count.gray  { background: #e2e5ea; color: #6b7a8f; }
    .nav-badge.count.alert-outline { background: #fde5e5; color: #6b7a8f; }
    .nav-badge.count.green { background: var(--teal); color: #fff; font-weight: 400; }
    .nav-badge.count.blue     { background: #3b82f6; color: #fff; }
    .nav-badge.count.red-soft   { background: #fde5e5; color: #c23a35; }
    .nav-badge.count.green-soft { background: #d4f0eb; color: #0f7a63; }
    .nav-badge {
      margin-left: auto; background: #e8e8e8; color: #555;
      font-size: 10px; font-weight: 600; padding: 1px 7px;
      border-radius: 20px; line-height: 1.6;
    }
    /* Зелёная точка «непрочитано» — сразу после названия */
    .nav-unread-dot {
      flex-shrink: 0; margin-left: -2px;
      width: 7px; height: 7px; border-radius: 50%; background: var(--teal);
    }
    /* Кружок «прочитанного состояния» — слева от счётчика */
    .nav-readdot {
      margin-left: auto; flex-shrink: 0;
      width: 9px; height: 9px; border-radius: 50%; background: #c7ccd6;
    }
    /* Счётчик «Всех задач» окрашен как счётчик отстающего проекта в Ганте
       (.gantt-group.behind-project .count-chip): белый фон, красноватая рамка,
       красный текст. Размер и шрифт — базовые, как у остальных бейджей меню. */
    /* Один в один со счётчиком колонки «Требует решения» в канбане */
    .nav-item.attn .nav-badge.count {
      background: #f9d3cf; color: #a3302b; font-size: 11px;
      box-shadow: none;
    }

    /* Счётчик «Моих заданий»: фон светлее, рамка темнее. Кольцо внутренней тенью —
       чтобы не влияло на размеры, как и у счётчика «Плана работ» выше. */
    .nav-item .nav-badge.count.gray {
      background: #f1f4f9; color: #6b7a8f;
      box-shadow: inset 0 0 0 1px #c2cad6;
    }

    .nav-readdot + .nav-badge { margin-left: 6px; }
    .nav-badge + .nav-badge { margin-left: 6px; }

    .sidebar-spacer { flex: 1; min-height: 6px; }
    /* Прокручиваемая nav-область (логотип закреплён сверху) */
    .sidebar-scroll {
      flex: 1; min-height: 0; position: relative;
      display: flex; flex-direction: column;
      overflow-y: auto; overflow-x: hidden;
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
    }
    /* тень сверху при прокрутке nav-области */
    .sidebar-scroll::before {
      content: ''; display: block; flex-shrink: 0; position: sticky; top: 0; z-index: 5;
      height: 11px; margin: 0 0 -11px 0;
      background: linear-gradient(to bottom, rgba(5,28,60,0.17), rgba(5,28,60,0));
      opacity: 0; transition: opacity 0.15s;
      pointer-events: none;
    }
    .sidebar-scroll.is-scrolled::before { opacity: 1; }
    .sidebar-scroll::-webkit-scrollbar { width: 5px; }
    .sidebar-scroll::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .sidebar-scroll::-webkit-scrollbar-thumb:hover { background: #b9b6d4; }
    .sidebar-scroll::-webkit-scrollbar-track { background: transparent; }
    .team-section { flex: 1; overflow-y: auto; padding: 4px 10px 6px; }
    .team-section::-webkit-scrollbar { width: 5px; }
    .team-section::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .team-label { font-size: 9px; font-weight: 600; letter-spacing: 1.1px; text-transform: uppercase; color: #bbb; padding: 10px 8px 3px 16px; }

    .team-header {
      display: flex; align-items: center; gap: 8px;
      height: 30px; padding: 0 8px; border-radius: 7px; cursor: pointer;
      color: #8b95a5; font-weight: 600; font-size: 13px;
      transition: background 0.12s; margin-top: 1px;
    }
    .team-header:hover { background: var(--sidebar-hover); }
    .team-header.open { color: #2b3340; }
    .team-chevron { margin-left: auto; opacity: 0.4; transition: transform 0.2s; color: #888; }
    .team-header.open .team-chevron { transform: rotate(180deg); }

    .team-avatar {
      width: 20px; height: 20px; border-radius: 5px;
      display: flex; align-items: center; justify-content: center;
      font-size: 10px; font-weight: 700; color: #fff; flex-shrink: 0;
    }
    .ta-purple, .ta-teal, .ta-orange { background: linear-gradient(135deg,#0098a6,#2ab4a0); border-radius: 6px; }

    .team-children { padding-left: 8px; padding-top: 4px; padding-bottom: 4px; }
    .team-child {
      display: flex; align-items: center; gap: 8px;
      height: 30px; padding: 0 8px; border-radius: 7px;
      cursor: pointer; color: #8b95a5;
      font-size: 12.5px; font-weight: 500; transition: background 0.12s;
    }
    .team-child:hover { background: var(--sidebar-hover); }
    .team-child.active {
      color: #111;
      background: #eef2f8;
      font-weight: 600;
      padding-left: 11px;
      border-left: 3px solid #2a4d7f;
    }

    .team-child.page { color: #8b95a5; font-size: 11px; font-weight: 600; letter-spacing: 0.7px; text-transform: uppercase; }
    .team-child.page:hover { background: var(--sidebar-hover); color: #333; }
    .team-child.page svg { opacity: 0.6; }
    /* Разделитель после «Конфигурации» — она замыкает блок сущностей пространства */
    .sidebar .config-node { border-bottom: 1px solid var(--border); padding-bottom: 6px; margin-bottom: 6px; }

    /* Вложенные итемы (проекты и их разделы) выделяются только подложкой —
       левая полоска на этом уровне лишняя */
    .proj-nav-list .team-child.active,
    .proj-subs .team-child.active { border-left: none; padding-left: 8px; }
    .team-child.page.active { color: #2a4d7f; }
    .team-child.page.active svg { opacity: 1; color: #2a4d7f; }
    .logo.active { background: #eef2f8; }

    .team-divider { height: 1px; background: #ebebeb; margin: 4px 8px; }
    .dot { width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0; background: #ccc; }
    .team-child.active .dot { background: #111; }
    .proj-icon {
      width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0;
      background: #8b97a8; color: #fff;
      display: flex; align-items: center; justify-content: center;
      font-size: 9px; font-weight: 700;
    }
    .team-child.active .proj-icon { background: #2a4d7f; }
    /* Иконка типа вместо цветного кружка-буквы (у вложенных «процессов») */
    .proj-icon.proj-icon-type { background: none; color: #9aa3b2; }
    .proj-icon.proj-icon-type svg { width: 14px; height: 14px; }
    .team-child.active .proj-icon.proj-icon-type { background: none; color: #2a4d7f; }

    /* Projects nav section */
    .proj-team-tag {
      margin-left: auto; flex-shrink: 0;
      font-size: 9.5px; font-weight: 600; letter-spacing: .2px;
      color: #aeb6c2; background: #f7f9fc;
      padding: 2px 6px; border-radius: 5px;
    }
    .team-child.active .proj-team-tag { background: #dbe4f0; color: #6b82a3; }
    /* Название команды у проекта — не более трети ширины строки, с многоточием */
    .proj-nav-nested .proj-team-tag { max-width: 33%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    /* Раскрывающийся проект */
    .proj-group { display: flex; flex-direction: column; }
    .proj-expand {
      display: inline-flex; align-items: center; justify-content: center;
      width: 16px; height: 16px; border-radius: 4px;
      color: #a4adbb; cursor: pointer; flex-shrink: 0;
      margin-right: 2px;
      transition: color .12s, background .12s, transform .15s;
    }
    .proj-expand:hover { color: #1a1d35; background: rgba(0,0,0,0.06); }
    /* Только у своего проекта (прямой потомок), иначе внешняя обёртка
       .proj-group.open вращала бы все шевроны разом */
    .proj-group.open > .proj-toggle > .proj-expand { transform: rotate(90deg); color: #1a1d35; }
    /* Отступ шеврон→иконка у проектов — как у пункта «План работ» (.tree-item gap 6px) */
    .proj-nav-nested .proj-toggle { gap: 6px; }
    /* Шеврон проекта — как обычные (.tree-arrow): узкий, без коробки/hover-фона,
       не темнеет при раскрытии (остаётся #b2bac6, только поворачивается). */
    /* Стрелка мелкая, но нажимается вся её клетка — иначе в 10px попасть трудно */
    .proj-nav-nested .proj-expand { width: 18px; height: 22px; margin-right: -3px; border-radius: 4px; color: #b2bac6; }
    .proj-nav-nested .proj-expand:hover { background: none; color: #7a8698; }
    .proj-nav-nested .proj-group.open > .proj-toggle > .proj-expand { color: #b2bac6; }
    .proj-chevron { flex-shrink: 0; color: #b2bac6; margin-left: 6px; transition: transform .15s; }
    .proj-group.open .proj-chevron { transform: rotate(90deg); }
    .proj-subs {
      display: none; padding: 3px 0 5px 20px;
      flex-direction: column; gap: 1px;
    }
    .proj-group.open > .proj-subs { display: flex; }
    /* «Структура» — дерево верхнего уровня: без отступа проекта, корни в один уровень с проектами */
    .struct-nav .proj-subs { padding-left: 0; }
    .proj-sub {
      display: block; padding: 6px 10px;
      font-size: 12px; color: #8b95a5;
      text-decoration: none; border-radius: 6px;
      transition: background .12s, color .12s;
    }
    .proj-sub:hover { background: var(--sidebar-hover); color: #333; }
    .proj-sub.active { background: #eef2f8; color: #111; font-weight: 600; }

    /* Разделы проекта — дерево папок */
    .tree-node { display: flex; flex-direction: column; }
    .tree-item {
      display: flex; align-items: center; gap: 6px;
      height: 30px; box-sizing: border-box; padding: 0 8px; border-radius: 6px; white-space: nowrap;
      font-size: 13px; color: #8b95a5; cursor: pointer;
      transition: background .12s, color .12s;
    }
    /* Саб-итемы — на ступень мельче родителей (12px/26px против 13px/30px):
       уровень вложенности читается не только по отступу, но и по весу строки,
       и в раскрытом дереве влезает заметно больше пунктов */
    .tree-children .tree-item,
    .chat-list .tree-item,
    .proj-nav-nested .tree-item,
    .proj-nav-nested .proj-toggle {
      height: 26px; font-size: 12px;
    }
    /* Пункт дерева «внимание» — обычного цвета, отличает его только счётчик */
    .tree-item.attn .nav-badge.count {
      background: #fff; color: #c23a35; box-shadow: inset 0 0 0 1px #f2b8b4;
    }
    /* Корни дерева (Инструкции, Сценарии) — акцентный цвет */
    .proj-subs > .tree-node > .tree-item { color: #0098a6; font-weight: 500; }
    .proj-subs > .tree-node > .tree-item .tree-ico { color: #0098a6; }
    .proj-subs > .tree-node > .tree-item.active { font-weight: 600; }
    /* Проекты, вложенные в пункт «Pipelines» — сохраняем «проектный» вид, а не серый struct-nav */
    .struct-nav .proj-nav-nested .proj-subs { padding-left: 20px; }
    /* Вложенные проекты — обычный вес, не полужирный (жирным остаётся только активный) */
    .proj-nav-nested .proj-toggle:not(.active) { font-weight: 400; }
    /* Имя — в одну строку с многоточием; тег команды прячет JS, когда не помещается */
    .proj-nav-nested .proj-toggle { flex-wrap: nowrap; }
    .proj-nav-nested .proj-name {
      flex: 1 1 auto; min-width: 0;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .struct-nav .proj-nav-nested .proj-subs > .tree-node > .tree-item:not(.tree-accent),
    .struct-nav .proj-nav-nested .proj-subs > .tree-node > .tree-item:not(.tree-accent) .tree-ico { color: #0098a6; }

    /* ── Избранное для Pipelines ─────────────────────────────── */
    /* Звёзды выровнены по правому краю (одна вертикаль) абсолютным позиционированием */
    /* Звезда-переключатель режима на шапке каждой группы с вложенными пунктами
       («Воркфлоу», «Исполнители», «Результаты работы», «Инструкции», «Чаты») */
    .nav-item:has(> .pipe-favmode),
    .tree-item:has(> .pipe-favmode) { position: relative; padding-right: 32px; }
    .pipe-favmode {
      position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
      flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      width: 22px; height: 22px; padding: 0;
      background: none; border: none; border-radius: 5px; cursor: pointer;
      color: #cbd1db;                    /* светлая рамка — избранное скрыто */
    }
    .pipe-favmode svg { fill: none; color: inherit; } /* color:inherit — иначе .nav-item svg красит звезду в серый */
    .pipe-favmode:hover { background: rgba(0,0,0,.05); color: #9aa3b2; }
    .pipe-favmode.on { color: #2a4d7f; } /* включённый режим — синяя звезда, как иконка активного пункта */

    /* Звезда-признак избранного у проекта */
    .pipe-node .proj-toggle { position: relative; }
    .proj-fav {
      position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
      flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      width: 20px; height: 20px; padding: 0;
      background: none; border: none; border-radius: 5px; cursor: pointer;
      color: #cbd1db;
    }
    .proj-fav svg { fill: none; }
    .proj-fav:hover { background: rgba(0,0,0,.05); color: #9aa3b2; }
    .proj-fav.active { color: #9aa3b2; }               /* избран — тот же серый, что у остальных иконок */
    .proj-fav.active svg { fill: none; }                 /* контуром, без заливки */

    /* Видимость проектов под «Pipelines»: зависит от раскрытия и режима избранного */
    .pipe-node > .tree-children { display: flex; }                                   /* контейнер всегда в потоке */
    .pipe-node .proj-nav-nested > .proj-group { display: none; }                     /* свёрнуто, режим выкл — всё скрыто */
    .pipe-node.open .proj-nav-nested > .proj-group { display: flex; }                /* раскрыто — все процессы */
    /* Дерево потоков под «Выполнением»: свёрнуто, пока пункт не раскрыли стрелкой.
       Контейнер .tree-children тут всегда в потоке (правило выше), поэтому прячем
       сам список — иначе клик по стрелке ничего не менял */
    .pipe-node > .tree-children > .flow-nav-list { display: none; }
    .pipe-node.open > .tree-children > .flow-nav-list { display: flex; flex-direction: column; }

    /* ── Избранное для «Хранилища» (та же механика, что у «Выполнение») ── */
    .res-node > .tree-item { position: relative; }
    .res-node > .tree-children .tree-item { position: relative; }
    .res-node > .tree-children { display: flex; }                                    /* контейнер всегда в потоке */
    .res-node > .tree-children > .tree-node { display: none; }                        /* свёрнуто, режим выкл — скрыто */
    .res-node.open > .tree-children > .tree-node { display: flex; }                   /* раскрыто — все хранилища */
    .res-node:not(.open) > .tree-children.fav-visible > .tree-node.is-fav { display: flex; } /* свёрнуто + режим вкл — только избранные */

    /* ── Раздел «Чаты»: список чатов со счётчиком непрочитанных и избранным ── */
    /* Сворачивание — как у остальных групп: контейнер остаётся на месте, прячутся
       сами строки. Без этих правил работал базовый `.tree-children{display:none}`,
       и при включении режима избранного (он сворачивает раскрытое) исчезал весь
       список — вместе с избранными, которые он должен был показать.
       Уровней здесь на один больше: список лежит в .chat-list внутри
       .tree-children, и fav-visible висит на самом списке */
    .chat-node > .tree-children { display: flex; }
    .chat-node:not(.open) > .tree-children > .chat-list > .tree-node { display: none; }
    .chat-node:not(.open) > .tree-children > .chat-list.fav-visible > .tree-node.is-fav { display: flex; }
    /* Селектор с двумя классами — иначе `.nav-section + .nav-section` выше
       перебивает по специфичности и возвращает свои 14px */
    .nav-section + .chat-section { margin-top: 0; }
    .chat-section > .nav-label { position: relative; margin-bottom: 10px; }
    .chat-section .chat-list { display: flex; flex-direction: column; }
    .chat-section .chat-list .tree-item { position: relative; }
    /* Раскрытый узел показывает все чаты — режим избранного работает только на
       свёрнутом (правила .chat-node:not(.open) выше): он ужимает список до
       избранного, а не фильтрует раскрытый */
    .chat-section .chat-list > .tree-node { display: flex; }
    .chat-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Счётчик непрочитанных — бледно-зелёная подложка с тёмной цифрой (тона
       .nav-badge.count.green-soft): плотная заливка рябила в длинном списке.
       Отступ — чтобы не налезал на звезду избранного */
    .chat-section .chat-list .tree-item .nav-badge.count {
      background: #d4f0eb; color: #0f6e56; font-weight: 600;
    }

    /* ── Команды под «Исполнителями»: избранное как у «Хранилища» ── */
    .perf-node > .tree-item { position: relative; }
    .perf-node > .tree-children .tree-item { position: relative; }
    .perf-node > .tree-children { display: flex; }
    .perf-node > .tree-children > .tree-node { display: none; }
    .perf-node.open > .tree-children > .tree-node { display: flex; }
    .perf-node:not(.open) > .tree-children.fav-visible > .tree-node.is-fav { display: flex; }

    /* ── Избранное для «Конфигурации»: разделы = вкладки её страницы ── */
    .config-node > .nav-item { position: relative; }
    .config-node > .tree-children .tree-item { position: relative; }
    .config-node > .tree-children { display: flex; }
    .config-node > .tree-children > .tree-node { display: none; }
    .config-node.open > .tree-children > .tree-node { display: flex; }
    .config-node:not(.open) > .tree-children.fav-visible > .tree-node.is-fav { display: flex; }

    /* ── Раздел «Управление»: избранное прямо в секции ── */
    /* Отступ снизу подобран так, чтобы звезда режима шла с тем же шагом, что звёзды пунктов */
    .dash-section > .nav-label { position: relative; margin-bottom: 10px; }
    .dash-section .dash-list { display: flex; flex-direction: column; }
    .dash-section .dash-list .tree-item { position: relative; }
    .dash-section .dash-list > .tree-node { display: flex; }                       /* режим выкл — все пункты */
    .dash-section .dash-list.fav-visible > .tree-node { display: none; }           /* режим вкл — только избранные */
    .dash-section .dash-list.fav-visible > .tree-node.is-fav { display: flex; }
    /* У «Задач» есть счётчик — сдвигаем его левее звезды избранного */
    .dash-section .dash-list .tree-item.attn .nav-badge.count { margin-right: 0; }

    /* Пин строки «Материалов»: у правого края, проявляется при наведении;
       закреплённая строка держит его видимым и подсвеченным */
    .item-pin {
      margin-left: 6px; flex-shrink: 0; width: 22px; height: 22px;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; border-radius: 6px;
      color: #b2bac6; cursor: pointer; opacity: 0; transition: opacity .12s, color .12s, background .12s;
    }
    .item-row:hover > .item-pin, .item-pin:focus-visible { opacity: 1; }
    .item-pin:hover { background: rgba(0,0,0,.05); color: #6b7a8f; }
    .item-pin.on { opacity: 1; color: #2a4d7f; }

    /* ── Неактивные звёзды скрыты, появляются только при наведении на строку ── */
    .proj-fav { opacity: 0; transition: opacity .12s, background .12s, color .12s; }
    .proj-fav.active { opacity: 1; }
    .proj-toggle:hover .proj-fav,
    .tree-item:hover .proj-fav { opacity: 1; }
    /* Включённая звезда видна всегда: она показывает состояние режима (зелёная
       рамка, см. .pipe-favmode.on выше) — спрятанная, она скрывала бы и сам факт
       «избранное сейчас включено». Выключенная — только по наведению на строку,
       иначе пять серых звёзд шумят в свёрнутом сайдбаре */
    .pipe-favmode { opacity: 1; transition: background .12s, color .12s, opacity .12s; }
    .pipe-favmode:not(.on) { opacity: 0; }
    .nav-item:hover > .pipe-favmode,
    .tree-item:hover > .pipe-favmode,
    .pipe-favmode:focus-visible { opacity: 1; }

    /* Длинные заголовки со звездой режима — не залезать под звезду; «..» дорисовывает JS */
    .pipe-node > .tree-item { padding-right: 8px; }
    .tree-item .node-name { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; }
    /* Звезда избранного абсолютная (right: 8px) и ширины в строке не занимает,
       поэтому место под неё резервирует сам пункт — иначе длинное имя уезжало
       бы под звезду, а .node-name считал бы, что всё поместилось */
    .tree-item:has(> .proj-fav) { padding-right: 32px; }

    .tree-item:hover { background: var(--sidebar-hover); color: #333; }
    .tree-item.active { background: #eef2f8; color: #111; font-weight: 600; }
    .tree-item.active .tree-ico { color: #111; }   /* иконка активного пункта — тоже чёрная */
    /* Активный пункт в разделе «Управление» — как в «Выполнение»: тёмный текст + синяя иконка
       (перебиваем серый цвет struct-nav, у которого выше специфичность) */
    .struct-nav .proj-subs > .tree-node > .tree-item.active { color: #111; }
    .struct-nav .proj-subs > .tree-node > .tree-item.active .tree-ico,
    .struct-nav .proj-subs > .tree-node > .tree-item.active .tree-arrow { color: #2a4d7f; }
    /* ── Начертание сайдбара: без полужирного, контраст выше ──
       Веса 400 на всех уровнях, вложенные строки 12.5px (ровнее с пунктами),
       цвет #4a5a72 вместо бледного #8b95a5, antialiased — текст тоньше и резче.
       Активному пункту хватает подложки и тёмного цвета, поэтому 500, а не 600 */
    .sidebar { -webkit-font-smoothing: antialiased; }
    .sidebar .nav-item { font-weight: 400; color: #4a5a72; }
    .sidebar .tree-item,
    .sidebar .team-child { font-size: 12.5px; font-weight: 400; color: #4a5a72; }
    /* Активный и наведённый пункты остаются тёмными: правила выше перебиты
       базовым цветом этого блока, поэтому повторяем их здесь */
    .sidebar .nav-item.active,
    .sidebar .tree-item.active,
    .sidebar .team-child.active { font-weight: 500; color: #111; }
    /* Иконка и шеврон выбранного пункта — тоже чёрные */
    .sidebar .nav-item.active > svg,
    .sidebar .nav-item.active .tree-ico,
    .sidebar .tree-item.active .tree-ico,
    .sidebar .tree-item.active .tree-arrow,
    .sidebar .team-child.active .tree-ico { color: #111; }
    .sidebar .tree-item:hover,
    .sidebar .team-child:hover { color: #333; }
    .sidebar .item-row.unread .item-name,
    .sidebar .tree-item.unread { font-weight: 500; }
    /* ── Корневые пункты сайдбара — тем же шрифтом, что вкладки страниц ──
       «Работы», «Потоки работ», «Исполнители», «Конфигурация» — первый уровень
       навигации: 13px/500, активный 600 (ровно как .tab и .tab.active), против
       12.5px/400 у вложенных строк. Пункты живут в разных обёртках (nav-item и
       tree-item, часть — под .dash-list с display:contents), отсюда перечисление. */
    .sidebar .exec-section > .nav-item,
    .sidebar .exec-section > .tree-node > .nav-item,
    .sidebar .exec-section > .tree-node > .tree-item,
    .sidebar .exec-section > .dash-list > .tree-node > .nav-item,
    .sidebar .exec-section > .dash-list > .tree-node > .tree-item { font-size: 13px; font-weight: 500; }
    .sidebar .exec-section > .nav-item.active,
    .sidebar .exec-section > .tree-node > .nav-item.active,
    .sidebar .exec-section > .tree-node > .tree-item.active,
    .sidebar .exec-section > .dash-list > .tree-node > .nav-item.active,
    .sidebar .exec-section > .dash-list > .tree-node > .tree-item.active { font-weight: 600; }

    .tree-arrow {
      width: 10px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      color: #b2bac6; transition: transform .15s;
    }
    .tree-arrow.empty { visibility: hidden; }
    /* Шеврон со своим обработчиком — самостоятельная кнопка, а не указатель:
       под курсором показываем её клетку заливкой, иначе не видно, куда именно
       нажимать. Клетку рисуем тенью-подложкой, а не полем: поле раздвинуло бы
       соседей в строке */
    .tree-arrow[onclick] { cursor: pointer; }
    /* Зона клика у стрелок сайдбара уже расширена накладкой ::after ниже —
       её и красим под курсором: иначе не видно, куда именно нажимать */
    body .sidebar .tree-arrow[onclick]:hover { color: var(--text-primary); }
    body .sidebar .tree-arrow[onclick]:hover::after {
      background: rgba(15, 30, 60, .08); border-radius: 6px;
    }
    .tree-node.open > .tree-item > .tree-arrow { transform: rotate(90deg); }
    .tree-node.open > .nav-item > .tree-arrow { transform: rotate(90deg); }
    .tree-ico { display: flex; flex-shrink: 0; color: #9aa6b6; }
    /* Пункты раздела «Выполнение» выглядят как «Конфигурация»: тот же цвет шеврона
       и та же толщина обводки — иконки там нарисованы тоньше (1.8) и казались бледнее */
    .exec-section .dash-list > .tree-node > .tree-item > .tree-arrow { color: #8b95a5; }
    .exec-section .dash-list > .tree-node > .tree-item > .tree-ico > svg { stroke-width: 2; }
    .tree-item:hover .tree-ico { color: #6b7a8f; }
    .tree-children { display: none; flex-direction: column; padding-left: 14px; }
    .tree-node.open > .tree-children { display: flex; }
    /* Под статическим заголовком («Направления», «Чаты») список плоский: отступ
       вложенности убираем, чтобы иконки строк встали в колонку с иконками
       корневых пунктов, а не уезжали правее */
    .sidebar :is(.dir-node, .pin-node, .chat-section) > .tree-children { padding-left: 0; }

    /* ws-nav: пункты-строки — .nav-item со стрелкой раскрытия; стрелка-слот
       выравнивает иконки всех пунктов по одному левому отступу */
    .ws-nav .tree-node.open > .nav-item > .tree-arrow { transform: rotate(90deg); }
    .ws-nav .tree-arrow svg { color: #b2bac6; }
    .ws-nav .ws-sub {
      padding: 6px 10px 6px 34px; font-size: 12px; color: #8b95a5;
      cursor: pointer; border-radius: 6px; white-space: nowrap;
      transition: background .12s, color .12s;
    }
    .ws-nav .ws-sub:hover { background: var(--sidebar-hover); color: #333; }
    .ws-nav .ws-sub.active { background: #eef2f8; color: #111; font-weight: 600; }
    /* Активный кейс под разделом и его библиотеки — вложенные уровни */
    .ws-nav .ws-case {
      padding: 5px 10px 5px 48px; font-size: 12px; color: #8b95a5;
      cursor: pointer; border-radius: 6px; white-space: nowrap;
      transition: background .12s, color .12s;
    }
    .ws-nav .ws-case:hover { background: var(--sidebar-hover); color: #333; }
    .ws-nav .ws-case.active { background: #eef2f8; color: #111; font-weight: 600; }
    .ws-nav .ws-sublib {
      padding: 5px 10px 5px 62px; font-size: 12px; color: #8b95a5;
      cursor: pointer; border-radius: 6px; white-space: nowrap;
      transition: background .12s, color .12s;
    }
    .ws-nav .ws-sublib:hover { background: var(--sidebar-hover); color: #333; }

    .ws-pills-bar {
      padding: 10px 12px 10px;
      display: flex; flex-direction: column; gap: 8px;
    }
    .ws-pills {
      /* Отступ справа — чтобы «В работу» не липла к «+» и на узкой панели
         честно переносилась на вторую строку, а не жалась к пилюлям */
      display: flex; align-items: center; gap: 8px; margin-right: 10px;
    }
    /* Имя пространства — подпись справа от выбранной пилюли; selectWsRail()
       держит её за активной. Длинное имя режется многоточием, полное — в title */
    .ws-pill-label {
      font-size: 14px; font-weight: 500; color: #111;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      min-width: 0; margin: 0 2px; cursor: pointer;
    }
    /* Топбар компактнее: пилюли пространств мельче, а имя пространства убрано
       только из хлебных крошек — значок-дом остаётся, имя у пилюль живо */
    #mainTopbar { font-size: 12px; }
    #mainTopbar .ws-pill { width: 28px; height: 28px; font-size: 11px; border-radius: 9px; }
    #mainTopbar .breadcrumb .bc-home { font-size: 0; gap: 0; }
    .ws-pill {
      position: relative; flex-shrink: 0;
      width: 32px; height: 32px; border-radius: 10px;
      display: flex; align-items: center; justify-content: center;
      font-size: 12px; font-weight: 700; color: #fff;
      cursor: pointer; flex-shrink: 0;
      background: linear-gradient(145deg,#9ba7b8,#7c8a9e);
      transition: transform 0.16s ease, box-shadow 0.16s ease;
      box-shadow: 0 2px 5px rgba(40,55,80,0.18), inset 0 1px 0 rgba(255,255,255,0.18);
    }
    .ws-pill:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 13px rgba(40,55,80,0.26), inset 0 1px 0 rgba(255,255,255,0.22);
    }
    .ws-pill.active {
      background: linear-gradient(145deg,#3a5e94,#23436f);
      box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px rgba(58,94,148,0.5),
                  0 3px 9px rgba(35,67,111,0.4), inset 0 1px 0 rgba(255,255,255,0.25);
    }
    .ws-pill.active:hover { transform: translateY(-2px); }
    .ws-pill-badge {
      position: absolute; top: -5px; right: -5px;
      background: var(--red); color: #fff;
      font-size: 8px; font-weight: 700; padding: 1px 4px;
      border-radius: 10px; line-height: 1.5;
      border: 2px solid #fff;
      box-shadow: 0 1px 2px rgba(0,0,0,0.2);
    }
    .ws-pill-add {
      background: transparent !important;
      color: #97a3b4; box-shadow: none;
      border: 1.5px dashed rgba(70,90,120,0.3);
    }
    .ws-pill-add:hover {
      background: rgba(58,94,148,0.08) !important;
      border-color: rgba(58,94,148,0.55); color: #3a5e94;
      box-shadow: none; transform: translateY(-1px);
    }

    .sidebar-user {
      display: flex; align-items: center; gap: 10px;
      padding: 12px 16px; min-height: 64px; box-sizing: border-box;
      margin-top: 8px;
      background: #fff; border-radius: 14px; cursor: pointer;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
      transition: background 0.12s, box-shadow 0.12s;
    }
    .sidebar-user:hover { background: var(--sidebar-hover); }

    /* Режим работы — три пилюли под панелью. Плашка оформлена как карточка
       учётки под ней: та же белая подложка, скругление и тень */
    .mode-pills {
      display: flex; gap: 4px; flex-shrink: 0;
      margin-top: 8px; padding: 4px; box-sizing: border-box;
      background: #fff; border-radius: 14px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
    }
    .mode-pill {
      /* Равные доли ширины: на узкой панели длинная «Конфигурация» ужимается
         многоточием, а не выталкивает соседей */
      flex: 1; min-width: 0; padding: 7px 4px;
      border: none; background: transparent; border-radius: 10px;
      font: inherit; font-size: 11.5px; font-weight: 600; color: #6b7689;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      cursor: pointer; transition: background 0.12s, color 0.12s;
    }
    .mode-pill:hover  { background: #eff2f7; color: #33415a; }
    .mode-pill.active { background: #e7eaf0; color: #23436f; }
    .user-avatar {
      width: 36px; height: 36px; border-radius: 50%;
      background: linear-gradient(135deg,#2a4d7f,#ec4899);
      display: flex; align-items: center; justify-content: center;
      font-size: 12px; font-weight: 700; color: #fff; flex-shrink: 0;
    }
    .user-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0; }
    .user-name-row { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
    .user-name  { font-size: 13px; font-weight: 600; color: #1a1d35; line-height: 1.2; flex-shrink: 0; }
    .user-email { font-size: 11px; color: #8a94a6;
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
    .user-plan-row  { display: flex; align-items: center; gap: 6px; margin-top: 2px; }
    .user-plan-chip { font-size: 9.5px; font-weight: 700; letter-spacing: .3px;
                      background: #eaf1ff; color: #3b82f6;
                      padding: 2px 6px; border-radius: 5px; }
    .user-plan-note { font-size: 10.5px; color: #8a94a6; }
    .user-status { font-size: 11px; color: #999; }
    .status-dot  { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #34d399; margin-right: 4px; }

    /* ────────────────── MAIN ────────────────── */
    .content-col { flex: 1; display: flex; flex-direction: column; gap: 10px; overflow: visible; min-width: 0; }
    /* Скругление карточки — как у полосы слева (.lb-rail), панели читаются одним рядом */
    .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: var(--bg); border-radius: 10px; }

    /* Topbar */
    .topbar {
      background: #f8fafc; border-bottom: 1px solid #e8edf4;
      padding: 0 24px;
      display: flex; align-items: center; gap: 12px; flex-shrink: 0;
      /* Первая строка шапки: пространства, путь, поиск и «В работу». Когда путь
         перестаёт помещаться, он переносится целиком под неё */
      flex-wrap: wrap; row-gap: 4px;
    }
    .breadcrumb {
      display: flex; align-items: center; gap: 6px;
      font-size: 13px; color: var(--text-secondary);
      /* Не растягиваем и не сжимаем: не влез — уходит на следующую строку шапки.
         Поиск и «В работу» держатся справа сами (margin-left: auto ниже) */
      flex: 0 1 auto;
    }
    .topbar > .topbar-search { margin-left: auto; }
    /* Шапка отбита снизу: путь липнул к верхней рамке областей. Поле у самой
       шапки, а не у крошек — иначе они съезжали бы вверх относительно пилюль */
    body:has(> #mainTopbar) > #mainTopbar { padding-bottom: 6px; }
    /* Узкая шапка: путь уходит целиком под первую строку, а пространства, поиск
       и «В работу» остаются наверху */
    @media (max-width: 1000px) {
      /* padding-left = отступ иконки внутри бутерброда: домик в пути встаёт
         ровно под неё, а не левее */
      .topbar > .breadcrumb { order: 3; flex: 1 0 100%; margin-left: 0; padding-left: 7px; }
    }
    .breadcrumb a { color: #93a4ba; text-decoration: none; display: flex; align-items: center; gap: 5px; }
    .breadcrumb a:hover { color: var(--purple); }
    /* Корень крошки — пространство. Не ссылка: своей страницы у него больше нет,
       по клику в сайдбаре только раскрывается список разделов */
    .bc-home { color: #93a4ba; display: flex; align-items: center; gap: 5px; }
    .bc-sep { color: #c2cedd; }
    .bc-cur { color: #7f93ab; font-weight: 500; }
    /* Узкий топбар: крошки не переносятся и не сжимаются — левые уходят в «…»
       (bcCollapse), по клику на неё показываются меню */
    /* overflow оставляем видимым — иначе строка режет меню кнопки «…»;
       обрезает себя только последняя крошка (правило ниже) */
    /* Не хватило ширины — весь путь целиком уходит на вторую строку шапки
       (см. flex-wrap у .topbar), а сами крошки внутри не переносятся и не прячутся */
    .breadcrumb { min-width: 0; flex-wrap: nowrap; }
    .breadcrumb > * { flex-shrink: 0; white-space: nowrap; }
    .bc-hidden { display: none !important; }
    /* Последняя крошка всё же может не влезть в свою строку — обрезаем многоточием.
       overflow: clip с запасом по вертикали: hidden срезал чип типа (.proj-id),
       который выше строки текста */
    .breadcrumb > *:last-child {
      flex-shrink: 1; min-width: 0; text-overflow: ellipsis;
      overflow: clip; overflow-clip-margin: 6px;
    }
    .bc-more-wrap { position: relative; display: none; align-items: center; }
    .bc-more-wrap.show { display: flex; }
    .bc-more {
      border: none; background: transparent; color: #93a4ba; font: inherit; font-size: 15px;
      line-height: 1; padding: 2px 5px; border-radius: 5px; cursor: pointer; letter-spacing: 1px;
    }
    .bc-more:hover { background: rgba(15,30,60,.06); color: var(--purple); }
    .bc-more-dd { left: 0; right: auto; min-width: 180px; }
    .bc-more-wrap.open .bc-more-dd { display: block; }
    .bc-more-dd .new-menu-item.bc-more-plain { color: #7f93ab; cursor: default; }
    .bc-more-dd .new-menu-item.bc-more-plain:hover { background: none; }

    .topbar-search {
      display: flex; align-items: center; gap: 7px;
      border: 1px solid var(--border); border-radius: 7px;
      padding: 10px 12px; color: var(--text-muted);
      font-size: 12.5px; background: var(--bg);
      min-width: 248px; cursor: text; transition: border-color 0.15s;
    }
    .topbar-search:hover { border-color: var(--border-mid); }
    .topbar-search svg { flex-shrink: 0; }
    .ts-input {
      flex: 1; min-width: 0; border: none; outline: none; background: transparent;
      font: inherit; font-size: 12.5px; color: var(--text-primary); padding: 0;
    }
    .ts-input::placeholder { color: var(--text-muted); }
    .ts-clear {
      display: none; flex-shrink: 0; width: 18px; height: 18px; padding: 0;
      border: none; border-radius: 50%; background: transparent; color: var(--text-muted);
      cursor: pointer; align-items: center; justify-content: center;
      transition: background 0.12s, color 0.12s;
    }
    .ts-clear:hover { background: #eef1f6; color: var(--red); }
    /* Активный поиск: крошки скрыты, поле на всю ширину, справа крестик */
    .topbar.search-active .breadcrumb { display: none; }
    .topbar.search-active .topbar-search {
      flex: 1; min-width: 0; border-color: var(--purple-mid); background: #fff;
    }
    .topbar.search-active .ts-clear { display: inline-flex; }
    /* Мало места: поиск сворачивается в квадратную кнопку-лупу (клик разворачивает) */
    .topbar.search-collapsed .topbar-search {
      min-width: 0; width: 38px; height: 38px; padding: 0;
      justify-content: center; cursor: pointer;
      /* кнопка-лупа держит размер: в узком топбаре её сплющивало в овал */
      flex: 0 0 38px;
    }
    .topbar.search-collapsed .topbar-search .ts-input { display: none; }
    .topbar.search-collapsed .topbar-search:hover { background: #fff; }

    /* Content scroll area */
    .content { flex: 1; overflow-y: auto; background: var(--bg); }
    .content::-webkit-scrollbar { width: 5px; }
    .content::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .inner { padding: 16px 12px; background: #ffffff; }

    /* Project header row */
    .proj-header {
      display: flex; align-items: center; gap: 10px;
      margin-bottom: 0; padding-bottom: 0; width: 100%;
    }
    /* Кнопка «назад» живёт в начале хлебных крошек — там строка мелкая,
       поэтому уменьшаем её и подгоняем по базовой линии текста крошек */
    .breadcrumb > .back-btn { width: 32px; height: 32px; margin-right: 2px; flex-shrink: 0; }
    .breadcrumb > .back-btn svg { width: 13px; height: 13px; }
    .back-btn {
      width: 32px; height: 32px; border-radius: 8px;
      border: none; background: transparent;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; color: var(--text-secondary); transition: background .15s, color .15s; flex-shrink: 0;
    }
    /* Подложка по наведению — тёмная, без рамки */
    .back-btn:hover { background: rgba(15,30,60,.12); color: var(--text-primary); }

    /* Код — служебная подпись рядом с названием: мелкий, нежирный, но текст
       контрастный (читается, а не угадывается). Фон — тот же токен, что у
       подложек, чтобы чип не выделялся плашкой сильнее самого названия */
    .proj-id {
      font-size: 11.5px; font-weight: 500; color: #6b7a8f;
      background: rgba(15,30,60,.05); border: none;   /* полупрозрачно: чип всегда на тон темнее своего фона */
      padding: 3px 9px; border-radius: 4px; white-space: nowrap;
    }
    .proj-title { font-size: 19px; font-weight: 700; color: var(--text-primary); letter-spacing: -0.2px; }
    /* Длинный заголовок задачи сжимается с многоточием — карандаш и кнопка
       смены статуса всегда остаются видны справа. */
    #taskTitle { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .proj-header > .edit-icon { flex-shrink: 0; }
    .edit-icon { color: var(--text-muted); cursor: pointer; display: flex; align-items: center; transition: color 0.15s; }
    .edit-icon:hover { color: var(--purple); }

    .proj-header-right { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
    /* Статус переносит placeAddBtn() в строку заголовка — прижимаем его
       к правому краю, как и остальную правую группу шапки */
    .proj-header > .vibe-status-wrap { margin-left: auto; }
    /* Если рядом уже стоит правая группа, поле забирает она — статус встаёт
       вплотную перед ней */
    .proj-header > .vibe-status-wrap ~ .proj-header-right { margin-left: 8px; }
    /* Пустая группа справа (её наполняет placeAddBtn, и не на всех страницах)
       всё равно занимала место: свой отступ плюс зазор шапки отодвигали кнопку
       статуса от края на 18px. Проверяем именно детей-элементы — внутри
       остаётся комментарий, и :empty не сработал бы */
    .proj-header > .proj-header-right:not(:has(*)) { display: none; }
    .btn-status {
      display: flex; align-items: center; gap: 7px;
      height: 32px; box-sizing: border-box;                 /* как кнопка создания */
      background: #1aa966;                          /* плоская заливка, без градиента */
      color: #fff; border: none;
      border-radius: 10px; padding: 0 16px;
      font-size: 13px; font-weight: 600; cursor: pointer;
      transition: all 0.2s;
      box-shadow: 0 2px 6px rgba(24,160,96,.28), 0 1px 2px rgba(15,30,60,.12);
      letter-spacing: 0.1px;
    }
    .btn-status:hover {
      background: #159a5c;                          /* на тон темнее, без градиента */
      box-shadow: 0 3px 10px rgba(21,154,92,.34), 0 1px 2px rgba(15,30,60,.16);
      transform: translateY(-1px);
    }
    .more-btn {
      width: 28px; height: 28px; border-radius: 6px;
      border: 1px solid transparent; background: transparent;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; color: var(--text-secondary); transition: all 0.15s;
    }
    .more-btn:hover { background: var(--bg); border-color: var(--border); }

    /* User popup */
    .user-menu {
      display: none;
      position: absolute; inset: 0;
      background: #fff;
      border-radius: 14px;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
      overflow: hidden;
      z-index: 50; flex-direction: column;
      animation: slideUp 0.2s ease both;
    }
    .user-menu.open { display: flex; }

    @keyframes slideUp {
      from { opacity:0; transform: translateY(12px); }
      to   { opacity:1; transform: translateY(0); }
    }

    .um-header {
      padding: 20px 16px 16px;
      background: var(--sidebar-bg);
      display: flex; align-items: center; gap: 10px; flex-shrink: 0;
    }
    .um-avatar {
      width: 40px; height: 40px; border-radius: 50%;
      background: linear-gradient(135deg,#2a4d7f,#ec4899);
      display: flex; align-items: center; justify-content: center;
      font-size: 14px; font-weight: 700; color: #fff; flex-shrink: 0;
    }
    .um-name  { font-size: 13.5px; font-weight: 700; color: #102a4d; }
    .um-email { font-size: 11px; color: #93a4ba; margin-top: 1px; }
    .um-plan  {
      margin-left: auto; font-size: 10px; font-weight: 700;
      color: var(--purple); background: var(--purple-light);
      padding: 2px 8px; border-radius: 10px; white-space: nowrap;
    }

    .um-body { flex: 1; overflow-y: auto; }

    .um-section { padding: 6px 0; border-bottom: 1px solid #f1f4f9; }
    .um-section:last-child { border-bottom: none; }

    .um-item {
      display: flex; align-items: center; gap: 12px;
      padding: 11px 18px; cursor: pointer;
      font-size: 13px; font-weight: 500; color: #16345c;
      transition: background 0.12s;
    }
    .um-item:hover { background: #f3f6fa; }
    .um-item svg { flex-shrink: 0; opacity: 0.55; }
    .um-item:hover svg { opacity: 1; }
    .um-item.danger { color: #d05050; }
    .um-item.danger:hover { background: #fff5f5; }

    .um-badge {
      margin-left: auto; font-size: 10px; font-weight: 700;
      color: #fff; background: var(--red);
      padding: 2px 7px; border-radius: 10px;
    }

    .um-close {
      display: flex; align-items: center; gap: 10px;
      padding: 12px 16px; min-height: 64px; box-sizing: border-box;
      cursor: pointer;
      font-size: 13px; font-weight: 500; color: #7f93ab;
      border-top: 1px solid #e9eef5;
      transition: background 0.12s; flex-shrink: 0;
    }
    .um-close:hover { background: #f3f6fa; color: var(--purple); }

    /* Sticky header wrapper */
    .sticky-header { position: sticky; top: 0; z-index: 20; }

    /* Header panel — flat, no backing card (all pages) */
    /* Заголовок страницы — боковой отступ как у содержимого страницы */
    .head-card {
      margin: 0 0 10px;
      background: transparent;
      flex-shrink: 0;
    }
    /* Снизу вдвое меньше, чем сверху (8px вместо 16px): название и таб-бар —
       части одной шапки, и полный отступ разрывал их на два блока */
    .head-card .inner { padding-left: 24px; padding-right: 24px; padding-bottom: 8px; }
    .head-card .inner,
    .head-card .toolbar-wrap { background: transparent; }
    .head-card .toolbar-wrap { border-bottom: none; box-shadow: none; }
    /* «Конфигурация»: таб-бар лежит в шапке, а не в контенте — выравниваем его
       по заголовку и даём такой же отступ сверху, как на других страницах */
    body[data-page="config"] .head-card .sticky-header { padding: 22px 24px 0; }
    /* «Конфигурация»: таб-бар в шапке отбит слева, чтобы не липнуть к краю карточки */
    body[data-page="workdata"] .head-card .sticky-header { padding-left: 8px; }
    /* Направления идут плоским списком (без групп по типу — тип виден чипом
       в самой карточке), поэтому воздух между карточками задаём здесь */
    /* Список направлений — не шире 600: строка короткая, во всю ширину области
       имя отрывалось от чипов. Строку фильтров над ним не ограничиваем —
       её пилюли и выпадайки должны стоять в один ряд, поэтому потолок в 480
       снимаем со всей миниапки, а 600 ставим только списку */
    body .vibe-feed #mini-exec:has(#ws-processes) { max-width: none; }
    #ws-processes > .flows-list {
      display: flex; flex-direction: column; gap: 10px;
      max-width: 600px;
    }
    /* Потоки лежат внутри секций — там воздух между карточками задаёт сама секция */
    #ws-flows .section-body { display: flex; flex-direction: column; gap: 10px; }

    /* Title + tabs on one row */
    /* Своего левого поля у таб-бара нет: от заголовка его отбивает gap самой
       шапки, а когда заголовок скрыт (во фрейме он дублировал бы заголовок
       области), табы встают ровно по её левому краю */
    .proj-header > .tab-bar { margin: 0; min-width: 0; flex: 1; }
    .proj-header > .proj-title { flex-shrink: 0; }
    /* Приставка к заголовку: страница показывает не саму сущность, а её срез —
       автоматизацию или состав исполнителей. Псевдоэлементом на самом
       заголовке, а не отдельным span: чип типа страницы скрипт вставляет
       перед заголовком уже после загрузки, и статичная приставка оставалась бы
       от имени по другую сторону чипа. Текст заголовка app.js переписывает,
       содержимое ::before это не задевает */
    body[data-kind="auto"] .proj-header > .proj-title::before,
    body[data-page="team-workspace"] .proj-header > .proj-title::before {
      color: var(--text-muted); font-weight: 700;
    }
    body[data-kind="auto"] .proj-header > .proj-title::before { content: 'Автоматизация — '; }
    /* Возврат к сущности — стрелкой слева от заголовка: страница показывает
       её срез, и уйти к самой сущности нужно чаще, чем куда-либо ещё */
    .page-back {
      width: 28px; height: 28px; flex-shrink: 0; margin: 0 2px 0 -4px; padding: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; border-radius: 8px; background: transparent;
      color: var(--text-muted); cursor: pointer; transition: background .12s, color .12s;
    }
    .page-back:hover { background: #eceff4; color: var(--text-primary); }
    /* Выполнение на страницах автоматизации не считают — полосы прогресса нет.
       Она же была нижней границей шапки, поэтому линию возвращаем обычную */
    body[data-kind="auto"] .vibe-sticky > .head-exec-prog { display: none; }
    body[data-kind="auto"] .vibe-sticky { border-bottom: 1px solid var(--border); }
    body[data-page="team-workspace"] .proj-header > .proj-title::before { content: 'Исполнители — '; }

    /* Trash view */
    .trash-overlay {
      display: none; position: absolute; inset: 0;
      background: var(--bg); z-index: 30; flex-direction: column;
      animation: fadeIn 0.15s ease both;
    }
    .trash-overlay.open { display: flex; }

    .trash-header {
      background: #fff; border-bottom: 1px solid var(--border);
      padding: 12px 24px; display: flex; align-items: center; gap: 10px;
      flex-shrink: 0;
    }
    .trash-title { font-size: 14px; font-weight: 600; color: var(--text-primary); }
    .trash-count {
      font-size: 11px; font-weight: 600; color: var(--text-secondary);
      background: var(--bg); border: 1px solid var(--border);
      padding: 1px 8px; border-radius: 12px;
    }
    .trash-close {
      margin-left: auto; display: flex; align-items: center; gap: 6px;
      font-size: 12.5px; color: var(--text-secondary);
      cursor: pointer; padding: 5px 10px; border-radius: 6px;
      border: 1px solid transparent; transition: all 0.15s;
      background: transparent;
    }
    .trash-close:hover { border-color: var(--border); background: var(--bg); color: var(--text-primary); }

    .trash-body { flex: 1; overflow-y: auto; padding: 16px 24px; }
    .trash-body::-webkit-scrollbar { width: 5px; }
    .trash-body::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .trash-section-label {
      font-size: 10px; font-weight: 700; letter-spacing: 1px;
      text-transform: uppercase; color: #93a4ba;
      margin: 12px 0 6px; display: flex; align-items: center; gap: 8px;
    }
    .trash-section-label::after {
      content: ''; flex: 1; height: 1px; background: #e9edf4;
    }

    .trash-item {
      display: flex; align-items: center; gap: 10px;
      padding: 9px 12px; background: #fff;
      border: 1px solid var(--border); border-radius: var(--r);
      margin-bottom: 3px; transition: all 0.15s;
    }
    .trash-item:hover { border-color: var(--border-mid); }
    .trash-item-id {
      font-size: 11.5px; font-weight: 600; color: #9ca3af;
      background: #eaedf4; padding: 2px 8px; border-radius: 4px; flex-shrink: 0;
    }
    .trash-item-name { font-size: 13px; color: #9ca3af; flex: 1; text-decoration: line-through; }
    .trash-item-date { font-size: 11px; color: #b3c1d4; flex-shrink: 0; }
    .trash-restore {
      display: flex; align-items: center; gap: 4px;
      font-size: 11.5px; font-weight: 500; color: var(--purple);
      cursor: pointer; padding: 4px 8px; border-radius: 5px;
      border: 1px solid transparent; background: transparent;
      transition: all 0.15s; flex-shrink: 0;
    }
    .trash-restore:hover { border-color: var(--purple); background: var(--purple-light); }
    .trash-delete {
      display: flex; align-items: center;
      font-size: 11.5px; color: #d09090;
      cursor: pointer; padding: 4px 8px; border-radius: 5px;
      border: 1px solid transparent; background: transparent;
      transition: all 0.15s; flex-shrink: 0;
    }
    .trash-delete:hover { border-color: var(--red); color: var(--red); background: #fff5f5; }

    .trash-empty-btn {
      display: flex; align-items: center; gap: 6px;
      font-size: 12.5px; font-weight: 500; color: var(--red);
      cursor: pointer; padding: 6px 14px; border-radius: 6px;
      border: 1px solid transparent; background: transparent;
      transition: all 0.15s; margin-left: 6px;
    }
    .trash-empty-btn:hover { border-color: var(--red); background: #fff5f5; }

    /* Logo clickable */
    .logo { cursor: pointer; }
    /* Наведение — тем же цветом, что у карточек быстрых действий на дашборде */
    .logo:hover { background: #e4e9f1; }

    /* Шеврон справа в блоке логотипа — раскрывает разделы пространства */
    .ws-nav-toggle {
      margin-left: auto; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      width: 22px; height: 22px; padding: 0;
      border: none; background: none; border-radius: 6px;
      color: #b6bfcc; cursor: pointer;
      transition: background .12s, color .12s, transform .2s;
    }
    /* Подсветка — оттенок фона выделения (#eef2f8 у активных пунктов), на тон темнее */
    .ws-nav-toggle:hover { background: #e3e9f3; color: #46536e; }
    .ws-nav-toggle.open { transform: rotate(180deg); }
    /* Сами разделы: Проекты · Рабочие потоки · Исполнители · Конфигурация.
       Левый отступ 44px = иконка пункта встаёт ровно под «Рабочее пространство»
       (14 паддинг логотипа + 32 иконка + 6 gap − 8 внутренний паддинг пункта). */
    .ws-nav { display: none; }
    /* Раскрытый список тонирован: так видно, что это отдельный уровень навигации.
       Боковые отступы — 10px, как у остальных секций меню, плашка такая же скруглённая. */
    .ws-nav.open {
      display: block; padding: 4px 10px 8px;
      background: #f0f3f9; border-bottom: 1px solid #e0e6f0;
      /* overflow + переходы нужны для сворачивания по высоте перед уходом на страницу.
         min-height:0 разрешает flex ужимать список; overflow-y:auto тогда даёт
         вертикальный скролл вместо обрезки нижних пунктов на низком экране. */
      min-height: 0; overflow-x: hidden; overflow-y: auto;
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
      transition: height .16s ease, padding-top .16s ease, padding-bottom .16s ease;
    }
    .ws-nav.open::-webkit-scrollbar { width: 5px; }
    .ws-nav.open::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .ws-nav.open::-webkit-scrollbar-thumb:hover { background: #b9b6d4; }
    .ws-nav.open::-webkit-scrollbar-track { background: transparent; }
    .ws-nav .nav-item { padding: 0 8px; }
    .ws-nav .nav-item:hover { background: #e5ebf5; }
    .ws-nav .nav-item.active { background: #dee5f2; }
    /* Клик по логотипу раскрывает разделы пространства сразу на всю высоту сайдбара:
       ws-nav занимает всё оставшееся место, а секции ниже прячутся. */
    .ws-nav.open { flex: 1 1 auto; border-bottom: none; }
    .ws-nav.open ~ .nav-section,
    .ws-nav.open ~ .sidebar-scroll { display: none; }
    /* Группы: кто работает · над чем · и как за этим следим */
    .ws-nav-sep { height: 1px; background: #e0e6f0; margin: 5px 8px; }
    /* Разделитель уезжает под разделы — иначе он режет раскрытый список пополам.
       Блок пространства тонируется заодно со списком: раскрытое пространство
       и его разделы читаются как один блок. */
    .sidebar:has(.ws-nav.open) .logo {
      border-bottom-color: transparent;
      background: #e6ebf4;
    }
    .sidebar:has(.ws-nav.open) .logo:hover { background: #dfe6f1; }
    .logo .logo-sub { display: flex; align-items: center; gap: 4px; }
    .logo .logo-sub svg { transition: transform 0.2s; }

    /* Team switcher overlay */
    .team-switcher {
      display: none;
      position: absolute; inset: 0;
      background: #fff;
      z-index: 60; flex-direction: column;
      animation: slideUp 0.2s ease both;
    }
    .team-switcher.open { display: flex; }

    .tsw-header {
      padding: 16px; display: flex; align-items: center; gap: 8px;
      border-bottom: 1px solid var(--border); flex-shrink: 0;
      font-size: 13px; font-weight: 700; color: var(--text-primary);
    }
    .tsw-body { flex: 1; overflow-y: auto; padding: 8px 10px; }
    .tsw-body::-webkit-scrollbar { width: 5px; }
    .tsw-body::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .tsw-ws {
      display: flex; align-items: center; gap: 8px;
      padding: 10px 8px 4px; font-size: 10px; font-weight: 700;
      letter-spacing: 0.8px; text-transform: uppercase; color: #93a4ba;
    }
    .tsw-ws-logo {
      width: 18px; height: 18px; border-radius: 5px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      font-size: 9px; font-weight: 700; color: #fff;
    }

    .tsw-team {
      display: flex; align-items: center; gap: 9px;
      padding: 8px 10px; border-radius: 6px; cursor: pointer;
      font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
      transition: all 0.12s;
    }
    .tsw-team:hover { background: var(--bg); color: var(--text-primary); }
    .tsw-team.active { background: var(--purple-light); color: var(--purple); font-weight: 600; }
    .tsw-team .team-avatar { width: 24px; height: 24px; font-size: 11px; }
    .tsw-check { margin-left: auto; color: #0098a6; display: none; }
    .tsw-team.active .tsw-check { display: flex; }

    .tsw-footer {
      border-top: 1px solid var(--border); flex-shrink: 0; padding: 6px 10px;
    }
    .tsw-action {
      display: flex; align-items: center; gap: 9px;
      padding: 9px 10px; border-radius: 6px; cursor: pointer;
      font-size: 12.5px; font-weight: 500; color: var(--text-secondary);
      transition: all 0.12s;
    }
    .tsw-action:hover { background: var(--bg); color: var(--text-primary); }

    /* Views */
    .view { display: none; flex: 1; flex-direction: column; overflow: hidden; }
    .view.active { display: flex; }

    /* Страница пространства */
    .ws-topbar {
      background: var(--card); border-bottom: 1px solid var(--border);
      padding: 0 24px; height: 50px;
      display: flex; align-items: center; gap: 12px; flex-shrink: 0;
    }
    .ws-title { font-size: 18px; font-weight: 700; color: var(--text-primary); }

    .ws-content { flex: 1; overflow-y: auto; padding: 24px; background: var(--bg); }
    .ws-content::-webkit-scrollbar { width: 5px; }
    .ws-content::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .ws-section-label {
      font-size: 11px; font-weight: 700; letter-spacing: 1px;
      text-transform: uppercase; color: #93a4ba; margin-bottom: 10px;
    }

    .ws-teams-grid {
      display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
      /* Отступ сверху — карточки не липнут к линии таб-бара */
      gap: 12px; margin: 12px 0 24px;
    }

    .ws-team-card {
      background: #fff; border-radius: 12px;
      border: 1.5px solid var(--border);
      padding: 16px 18px; cursor: pointer;
      transition: all 0.15s; display: flex; flex-direction: column; gap: 12px;
    }
    .ws-team-card:hover { border-color: var(--purple); box-shadow: 0 4px 16px rgba(5,28,59,0.1); transform: translateY(-1px); }
    .ws-team-card.active { border-color: var(--purple); background: #ffffff; }

    .ws-card-head { display: flex; align-items: center; gap: 12px; }
    .ws-card-avatar {
      width: 40px; height: 40px; border-radius: 10px;
      display: flex; align-items: center; justify-content: center;
      font-size: 16px; font-weight: 700; color: #fff; flex-shrink: 0;
    }
    .ws-card-name { font-size: 14px; font-weight: 700; color: #102a4d; }
    .ws-card-role { font-size: 11px; color: #93a4ba; margin-top: 2px; }

    .btn-card-add {
      margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
      background: #eef4f5; color: #0098a6; border: 1px solid #cbe6e9;
      border-radius: 6px; padding: 4px 9px; font-size: 12px; font-weight: 600;
      cursor: pointer; transition: all 0.15s; flex-shrink: 0;
    }
    .btn-card-add:hover { background: #0098a6; color: #fff; border-color: #0098a6; }

    /* Пространство — сводный дашборд */
    .ws-dash-grid {
      display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
      gap: 14px; align-items: start;
    }
    .dash-card {
      background: #fff; border: 1px solid var(--border); border-radius: 14px;
      padding: 15px 17px; display: flex; flex-direction: column;
    }
    .dash-card-head {
      display: flex; align-items: center; gap: 8px;
      font-size: 14px; font-weight: 700; color: #16345c; margin-bottom: 6px;
    }
    .dash-card-head .dash-ic { color: #7f93ab; flex-shrink: 0; }
    .dash-card-head .dash-count { margin-left: auto; font-size: 11.5px; color: #a0abbb; font-weight: 500; }
    .dash-task {
      display: flex; align-items: center; gap: 9px; padding: 8px 0;
      border-top: 1px solid #f0f2f5; font-size: 13px; color: #3d4655;
    }
    .dash-task-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .dot-st { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: #c2cad6; }
    .dot-st.work { background: #f0a04b; }
    .dot-st.open { background: #2a4d7f; }
    .dot-st.done { background: #2ab46a; }
    .dash-more { font-size: 12px; color: #0098a6; text-decoration: none; font-weight: 600; margin-top: 10px; }
    .dash-more:hover { text-decoration: underline; }

    .dash-act { display: flex; gap: 10px; padding: 9px 0; border-top: 1px solid #f0f2f5; }
    .dash-act:first-of-type { border-top: none; }
    .dash-av {
      width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      color: #fff; font-size: 10px; font-weight: 700;
    }
    .dash-act-text { font-size: 12.5px; color: #3d4655; line-height: 1.4; }
    .dash-act-text b { font-weight: 600; color: #16345c; }
    .dash-act-time { font-size: 11px; color: #a9b4c2; margin-top: 2px; }

    .perf-skill { padding: 4px 0 8px; }
    .perf-skill:last-child { padding-bottom: 2px; }
    .perf-skill-label { margin-bottom: 4px; }
    .dash-panel, .dash-fin-wrap {
      background: #fff; border: 1px solid var(--border); border-radius: 12px;
      padding: 10px 17px;
    }
    .dash-fin-wrap { padding: 15px 17px; }
    .dash-perf-head {
      display: flex; align-items: center; gap: 10px; padding: 2px 0 6px;
      font-size: 11px; color: #a0abbb; font-weight: 600; text-transform: uppercase; letter-spacing: 0.4px;
    }
    .dash-perf-head .dash-perf-name { color: #a0abbb; }
    .perf-col-eff { flex: 1; }
    .perf-col-cost { width: 70px; text-align: right; }
    .dash-perf-cost { width: 70px; text-align: right; font-size: 12px; color: #16345c; font-weight: 700; }
    .dash-perf { display: flex; align-items: center; gap: 10px; padding: 7px 0; }
    .dash-perf-name { font-size: 12.5px; color: #3d4655; width: 120px; flex-shrink: 0; }
    .dash-bar { flex: 1; height: 6px; background: #eef1f5; border-radius: 4px; overflow: hidden; }
    .dash-bar-fill { height: 100%; background: linear-gradient(90deg,#2a4d7f,#5a7db0); border-radius: 4px; }
    .dash-perf-val { font-size: 12px; color: #6b7a8f; font-weight: 700; width: 22px; text-align: right; }

    .dash-fin-top { display: flex; justify-content: space-between; align-items: flex-end; margin: 4px 0 12px; }
    .dash-fin-label { font-size: 11.5px; color: #93a4ba; margin-bottom: 3px; }
    .dash-fin-big { font-size: 20px; font-weight: 700; color: #16345c; }
    .dash-fin-row { display: flex; justify-content: space-between; font-size: 12px; color: #6b7a8f; margin-top: 7px; }
    .dash-fin-row .muted-fin { color: #a0abbb; }
    .dash-fin-list { margin-top: 12px; border-top: 1px solid #f0f2f5; padding-top: 4px; }
    .dash-fin-item { display: flex; justify-content: space-between; font-size: 12.5px; color: #3d4655; padding: 6px 0; }
    .dash-fin-item b { color: #16345c; font-weight: 600; }

    .dash-fin-projects { margin-top: 14px; border-top: 1px solid #f0f2f5; padding-top: 12px; display: flex; flex-direction: column; gap: 14px; }
    .dash-fin-proj-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
    .dash-fin-proj-name { font-size: 13px; font-weight: 600; color: #16345c; }
    .fin-ready { font-size: 11.5px; font-weight: 600; color: #2a4d7f; background: #eef2f8; padding: 2px 8px; border-radius: 10px; }
    .dash-fin-proj-money { display: flex; justify-content: space-between; font-size: 12px; color: #6b7a8f; margin-top: 6px; }
    .dash-fin-proj-money b { color: #16345c; font-weight: 600; }
    .dash-fin-proj-money b.fin-up { color: #2ab46a; }
    .dash-fin-proj-money b.fin-down { color: #d9534f; }

    .ws-card-stats { display: flex; gap: 16px; }
    .ws-stat { font-size: 12px; color: #7f93ab; }
    .ws-stat strong { color: #16345c; font-weight: 700; display: block; font-size: 18px; }

    .ws-card-badge {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 11px; font-weight: 600; color: #fff;
      background: var(--red); padding: 2px 8px; border-radius: 20px;
      width: fit-content;
    }

    .ws-new-card {
      background: transparent; border-radius: 12px;
      border: 2px dashed #b9c8db;
      padding: 16px 18px; cursor: pointer;
      transition: all 0.15s; display: flex; align-items: center;
      justify-content: center; gap: 8px; min-height: 100px;
      color: #93a4ba; font-size: 13px; font-weight: 500;
    }
    .ws-new-card:hover { border-color: var(--purple); color: var(--purple); background: #f7f9fc; }

    /* Tabs — flat underline (all pages) */
    .tab-bar {
      display: flex;
      gap: 2px;
      margin: 0 12px;
      border-bottom: 1px solid var(--border);
      overflow-x: auto;
      scrollbar-width: none;
    }
    .tab-bar::-webkit-scrollbar { display: none; }
    /* Табам тесно — переносятся на следующую строку, а не ужимаются в кашу */
    .tab-bar.no-scroll { overflow: visible; flex-wrap: wrap; row-gap: 4px; }
    .tab {
      display: inline-flex; align-items: center; white-space: nowrap;
      /* Вес одинаковый у всех вкладок: от смены 500 → 600 у активной менялась
         ширина её текста, и соседние вкладки прыгали при переключении.
         Активную отличают цвет и линия снизу */
      padding: 9px 14px; font-size: 13px; font-weight: 600;
      cursor: pointer; color: var(--text-secondary);
      border-radius: 0; transition: all 0.15s;
      background: transparent; border: none;
      border-bottom: 2px solid transparent; margin-bottom: -1px;
      flex-shrink: 0;
    }
    .tab:hover { color: var(--text-primary); }
    .tab.active {
      background: transparent; color: #1e2a3a;
      box-shadow: none;
      border-bottom-color: #3b82f6;
    }
    /* «Чат» — не таб содержимого, а закладка колонки. Живёт в заголовке страницы
       слева от кода и названия: в таб-баре её обрезал бы скролл вкладок */
    .sticky-header:has(> .tab[onclick*="chat-panel"]) { display: flex; align-items: stretch; }
    /* Таб-бар занимает всю оставшуюся ширину — иначе кнопки справа съезжают к табам */
    .sticky-header:has(> .tab[onclick*="chat-panel"]) > .tab-bar { flex: 1; min-width: 0; }
    /* Заголовок с закладкой: сам заголовок тянется на всю оставшуюся ширину */
    .head-card > .inner > .tab[onclick*="chat-panel"] ~ .proj-header { flex: 1; min-width: 0; }
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"] {
      align-self: center; margin-right: 12px; padding: 4px 10px; gap: 4px;
      background: #d3ecef; color: #056470;
      /* Слева рамки нет: закладка упирается в границу области.
         Пока чат скрыт, рамки нет вовсе — закладка не спорит с табами */
      border: 1px solid transparent; border-left: 0;
      border-radius: 0 8px 8px 0;
    }
    /* Закладка начинается от левой границы карточки — гасим отступ шапки,
       а внутренним отступом слева отводим иконку от самого края */
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"] {
      margin-left: -20px; padding-left: 14px;
    }
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"]:hover { background: #c2e4e8; }
    /* Непрочитанные показываем числом внутри иконки чата, а не кружком рядом */
    .chat-cnt { position: relative; display: inline-flex; color: #4d939c; }
    .chat-cnt > svg { display: block; }
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"] .count-chip {
      position: absolute; left: 0; right: 0; top: 0; bottom: 5px;
      margin: 0; padding: 0; background: none; border-radius: 0;
      display: flex; align-items: center; justify-content: center;
      font-size: 9.5px; font-weight: 700; color: #4d939c;
    }
    /* Шеврон показывает, куда уедет колонка: влево — открыть, вправо — закрыть.
       Стоит после иконки и красится в её цвет */
    .chat-chev { display: none; }   /* закладка обходится одной иконкой чата */
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on .chat-chev { transform: rotate(180deg); }
    /* Открытый чат — подложка цвета фона страницы, закрытый — вовсе без неё */
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on {
      background: #c2e4e8; color: #056470;
    }
    /* Есть непрочитанные — закладка в бледно-зелёном, как непрочитанное везде */
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"]:not(.no-unread),
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"]:not(.no-unread).chat-on { background: #d3ecef; }
    /* Открытый чат — иконка со счётчиком чёрные, закрытый — светло-серые */
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on .chat-cnt,
    :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on .count-chip { color: #044f5a; }
    /* Вкладка с проблемами планирования: о проблемах говорит только счётчик,
       сам заголовок идёт обычным цветом — красный текст спорил с соседями */
    .tab-alert-count {
      display: inline-flex; align-items: center; justify-content: center;
      min-width: 16px; height: 16px; padding: 0 4px; margin-left: 7px;
      border-radius: 8px; background: #efa39d; color: #fff;
      font-size: 10px; font-weight: 600; line-height: 1;
    }
    .tab.tab-alert.active .tab-alert-count { background: #e74c3c; }
    .tab-bar > .tab-more { margin-bottom: -1px; width: 32px; height: 32px; padding: 0; flex-shrink: 0; }
    .tab-more {
      position: relative;
      margin-left: auto; background: transparent; border: none;
      color: #8b95a5; cursor: pointer; border-radius: 50%; box-sizing: border-box;
      display: flex; align-items: center; justify-content: center;
      padding: 0 8px; transition: all 0.15s;
    }
    .tab-more:hover { color: #333; background: rgba(0,0,0,0.06); }
    /* Кнопка без таб-бара (страница без вкладок) — размеры и подсказку берём те же,
       что у кнопок внутри .tab-bar, иначе она мельче и подсказка вылезает за край */
    .proj-header > .tab-more { width: 32px; height: 32px; padding: 0; flex-shrink: 0; }
    .proj-header > .tab-more[data-tip]:hover::after { left: auto; right: 0; transform: none; }
    .tab-more.tab-add { color: #0098a6; margin-left: auto; display: none; }
    .tab-more.tab-add:hover { color: #00838f; background: rgba(0,152,166,0.08); }
    /* Плюс показываем только на вкладке «Выполнение»; тогда же убираем
       авто-отступ у три-точек, чтобы они шли вплотную к плюсу.
       Без .has-add три-точки сохраняют margin-left:auto и остаются справа. */
    .tab-bar.has-add .tab-more.tab-add { display: flex; }
    .tab-bar.has-add .tab-more.tab-add + .tab-more { margin-left: 0; }

    /* Меню по три-точкам (лежит в .sticky-header, вне overflow таб-бара) */
    .more-menu {
      display: none;
      /* Начинается от линии таб-бара: у .sticky-header снизу свой отступ,
         из-за него меню повисало ниже линии */
      position: absolute; top: calc(100% - 10px); right: 12px;
      min-width: 200px;
      background: #fff; border-radius: 10px;
      box-shadow: 0 10px 28px rgba(15,30,60,0.16), 0 0 0 1px rgba(0,0,0,0.05);
      padding: 5px 0; z-index: 60;
      animation: fadeIn 0.15s ease both;
    }
    .more-menu.open { display: block; }
    .new-menu-item.danger, .new-menu-item.danger svg { color: #d9534f; }
    .new-menu-item.danger:hover { background: #fbe9e9; }
    .new-menu-item.danger:hover svg { color: #d9534f; }

    /* ── Правка названия на месте заголовка ── */
    .proj-title.editable { cursor: text; border-radius: 6px; padding: 0 4px; margin-left: -4px; transition: background .12s; }
    .proj-title.editable:hover { background: rgba(15,30,60,.06); }
    /* В режиме правки заголовок и кнопка статуса уходят: поле занимает всю строку */
    .title-edit { display: none; }
    .proj-header.editing > .proj-title,
    .proj-header.editing > .proj-header-right { display: none; }
    .proj-header.editing > .title-edit { display: flex; flex: 1; align-items: center; gap: 8px; min-width: 0; }
    .title-edit-box { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; }
    .title-edit-input {
      width: 100%; height: 34px; box-sizing: border-box;
      padding: 0 32px 0 11px;
      border: 1px solid var(--border-mid); border-radius: 8px; background: #fff;
      font-family: inherit; font-size: 17px; font-weight: 600; color: var(--text-primary);
      letter-spacing: -.2px;
    }
    .title-edit-input:focus { outline: none; border-color: #0098a6; }
    /* Крестик очистки — внутри поля у правого края, поэтому у input padding-right */
    .title-edit-clear {
      position: absolute; right: 7px; display: inline-flex; align-items: center; justify-content: center;
      width: 20px; height: 20px; padding: 0; border: none; border-radius: 5px;
      background: none; color: var(--text-muted); cursor: pointer; transition: background .12s, color .12s;
    }
    .title-edit-clear:hover { background: rgba(15,30,60,.08); color: var(--text-primary); }
    /* Действия — только иконки: подписи в такой строке лишний шум */
    .title-edit-btn {
      display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
      width: 32px; height: 32px; padding: 0; border-radius: 8px; cursor: pointer;
      border: 1px solid var(--border); background: #fff; color: #55647f;
      transition: background .12s, border-color .12s, color .12s, opacity .12s;
    }
    .title-edit-btn:hover { background: #f4f6fa; color: var(--text-primary); }
    .title-edit-btn.ok { border-color: transparent; background: var(--teal); color: #fff; }
    .title-edit-btn.ok:hover { background: #23a08f; }
    /* Пустое имя применить нельзя — кнопка гаснет и не реагирует */
    .title-edit-btn.ok:disabled { opacity: .4; cursor: default; background: var(--teal); }
    /* Код в таб-баре: выравниваем по центру строки табов и отбиваем от первого.
       Сам таб-бар прижимает содержимое к низу (border-bottom у табов),
       поэтому чипу нужен свой align-self, иначе он растянется по высоте */
    .tab-bar > .tab-id { align-self: center; margin-right: 12px; flex-shrink: 0; }
    /* «Объём работ» → «Точно»: поле ручного ввода выезжает справа от селекта.
       Прячем шириной, а не display — иначе выезда не будет, переход не анимируется */
    .vol-exact {
      display: inline-flex; align-items: center; gap: 4px; overflow: hidden;
      max-width: 0; opacity: 0; margin-left: 0;
      transition: max-width .2s ease, opacity .16s ease, margin-left .2s ease;
    }
    .vol-row.exact .vol-exact { max-width: 96px; opacity: 1; margin-left: 6px; }
    .vol-exact-input {
      width: 52px; height: 26px; box-sizing: border-box;
      border: 1px solid var(--border-mid); border-radius: 6px; background: #fff;
      padding: 0 7px; font-size: 12px; font-family: inherit; color: var(--text-body);
      text-align: right;
    }
    .vol-exact-input:focus { outline: none; border-color: #0098a6; }
    .vol-exact-unit { font-size: 11.5px; color: var(--text-muted); }
    /* Значок-подсказка у подписи поля: пояснение к смыслу параметра по ховеру */
    .label-tip {
      margin-left: 5px; flex-shrink: 0; vertical-align: -1px;
      color: var(--text-muted); cursor: help;
    }
    .label-tip:hover { color: #55647f; }
    /* Button tooltip */
    .btn-secondary[data-tip], .tab-more[data-tip], .pill-icon-btn[data-tip], .label-tip[data-tip] { position: relative; }
    /* Подсказку рисует tipShow() в body: как ::after её обрезал любой контейнер
       с overflow — колонки данных, таб-бар, сайдбар */
    .tip-float {
      position: fixed; display: none; z-index: 4000; max-width: 320px;
      background: #2b3340; color: #fff; font-size: 11px; font-weight: 500; line-height: 1.45;
      padding: 5px 9px; border-radius: 6px; pointer-events: none;
      box-shadow: 0 3px 10px rgba(0,0,0,0.2);
    }

    /* Plan — status filter bar (below header, on gray bg, sticky) */
    .plan-filter-bar {
      position: sticky; top: 0; z-index: 15;
      display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
      padding: 8px 12px; margin: 10px 0; border-radius: 9px;
      background: var(--area-bg); box-shadow: 0 0 0 6px var(--area-bg);
      transition: background-color .26s ease, box-shadow .26s ease;
    }
    /* Левый блок фильтр-бара: чекбокс «выбрать все» + счётчик итемов */
    .fbar-lead { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
    .plan-status-tabs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
    .pstab {
      padding: 4px 12px; font-size: 12px; font-weight: 500; white-space: nowrap;
      background: transparent; cursor: pointer; transition: all 0.15s;
      color: #93a4ba; border: 1px solid var(--border); border-radius: 20px;
    }
    .pstab:hover { color: #143258; border-color: var(--border-mid); }
    .pstab.active { color: #0f6e56; background: #e1f5ee; border-color: #9fe1cb; font-weight: 600; }
    .pstab.danger { color: #d9534f; }
    .pstab.danger:hover { color: #c0392b; border-color: #f0c0c0; }
    .pstab.danger.active { color: #b5302b; background: #fbe7e7; border-color: #f0c0c0; }

    /* Plan — table */
    .plan-table-wrap {
      background: #fff; border: 1px solid var(--border);
      border-radius: 12px; overflow-x: auto;
    }
    .plan-table-wrap::-webkit-scrollbar { height: 5px; }
    .plan-table-wrap::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .plan-table { width: 100%; border-collapse: collapse; font-size: 13px; }
    .plan-table td:first-child, .plan-table th:first-child { padding-left: 10px; padding-right: 0; }
    .plan-table th {
      text-align: left; font-size: 12px; font-weight: 600; color: #5a6b80;
      padding: 11px 10px; background: #f7f8fb;
      border-bottom: 1px solid var(--border); white-space: nowrap;
    }
    .plan-table td {
      padding: 10px 10px; border-bottom: 1px solid #eef1f5;
      color: #3d4655; vertical-align: middle; white-space: nowrap;
    }
    .plan-table tbody tr:last-child td { border-bottom: none; }
    .plan-table tbody tr:hover td { background: #fafbfd; }
    .plan-table .muted { color: #a9b4c2; }
    .col-check { width: 26px; }
    .plan-table td:first-child { width: 26px; }
    .plan-check {
      width: 16px; height: 16px; border: 2px solid var(--border-mid);
      border-radius: 4px; cursor: pointer;
    }
    .plan-name { display: flex; align-items: center; gap: 8px; font-weight: 500; color: var(--text-primary); }
    .plan-parent { cursor: pointer; }
    .plan-parent .plan-expand { transition: transform 0.15s; }
    .plan-warn-name { color: #e07a2e; }
    .plan-expand { color: #93a4ba; margin-left: 2px; }
    .plan-subrow td { background: #fbfcfd; }
    .plan-subrow:hover td { background: #f6f8fa !important; }
    .plan-subtask { display: flex; align-items: center; gap: 8px; padding-left: 20px; color: #7a8aa0; }
    .plan-subtask svg { color: #b3bccb; }
    .stage-chip {
      font-size: 11px; font-weight: 600; color: #6b7a8f;
      background: #eef0f4; padding: 2px 7px; border-radius: 4px;
    }
    .pstatus { display: flex; align-items: center; gap: 7px; }
    .pst-sq { width: 13px; height: 13px; border-radius: 3px; border: 1.5px solid #c2cad6; flex-shrink: 0; }
    .pst-sq.work { background: #f0a04b; border-color: #f0a04b; }
    .pst-sq.done { background: #2ab46a; border-color: #2ab46a; }
    .pst-ic.danger { color: #d9534f; flex-shrink: 0; }
    .plan-table .danger { color: #d9534f; font-weight: 500; }
    .plan-table .warn-text { color: #e07a2e; font-weight: 500; }
    .plan-note { font-style: normal; }

    /* Toolbar row */
    .toolbar-wrap {
      padding: 16px 12px;
      border-bottom: 1px solid var(--border);
      background: var(--card);
      display: flex; flex-direction: column; gap: 8px;
      box-shadow: 0 2px 8px rgba(5,28,59,0.04);
    }
    .toolbar-row { display: flex; align-items: center; gap: 10px; }
    .filters-row { display: flex; align-items: center; justify-content: space-between; padding-bottom: 2px; width: 100%; }
    .toolbar-check {
      width: 16px; height: 16px;
      border: 2px solid var(--border-mid); border-radius: 4px;
      cursor: pointer; flex-shrink: 0; transition: border-color 0.15s;
    }
    .toolbar-check:hover { border-color: var(--purple); }
    .toolbar-count { font-size: 13px; font-weight: 500; color: var(--text-secondary); }

    /* Направления — тулбар «чек / Добавить / счётчик» */
    .dir-toolbar {
      display: flex; align-items: center; gap: 10px;
      padding: 6px 12px 22px;
    }

    /* Дропдаун у кнопки Добавить */
    .add-dropdown { position: relative; }
    .add-menu {
      display: none; position: absolute;
      top: calc(100% + 4px); left: 0; z-index: 40;
      background: #fff; border-radius: 8px;
      box-shadow: 0 6px 20px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.05);
      min-width: 160px; padding: 4px;
    }
    .add-dropdown.open .add-menu { display: block; }
    .add-menu-item {
      padding: 8px 12px; font-size: 13px; color: var(--text-primary);
      border-radius: 5px; cursor: pointer;
      transition: background .12s;
    }
    .add-menu-item:hover { background: #eef2f8; }

    .btn-add {
      display: flex; align-items: center; gap: 6px;
      height: 29px; box-sizing: border-box; flex-shrink: 0;
      background: #0098a6; color: #fff; border: none;
      border-radius: 6px; padding: 0 14px; font-size: 13px; font-weight: 600;
      cursor: pointer; transition: all 0.18s; box-shadow: 0 1px 3px rgba(0,152,166,0.25);
    }
    .btn-add:hover { background: #00838f; transform: translateY(-1px); }

    .btn-secondary {
      display: flex; align-items: center; gap: 6px;
      height: 29px; box-sizing: border-box; flex-shrink: 0;
      background: #fff; color: #3d4655; border: 1px solid var(--border-mid);
      border-radius: 6px; padding: 0 14px; font-size: 13px; font-weight: 600;
      cursor: pointer; transition: all 0.18s;
    }
    .btn-secondary:hover { background: #f5f7fa; border-color: #9aa6b8; }
    .btn-secondary svg { color: #6b7a8f; }

    .filter-group { display: flex; align-items: center; gap: 6px; }
    .filter-btn {
      padding: 4px 12px; font-size: 12px; font-weight: 500;
      cursor: pointer; transition: all 0.15s; white-space: nowrap;
      background: transparent; color: #93a4ba;
      border: 1px solid var(--border); border-radius: 20px;
    }
    .filter-btn:hover { color: #143258; border-color: var(--border-mid); }
    .filter-btn.active {
      color: #0f6e56; background: #e1f5ee;
      border-color: #9fe1cb; font-weight: 600;
    }

    .collapse-btn {
      width: 26px; height: 26px; border-radius: 5px;
      border: 1px solid transparent; background: transparent;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; color: var(--text-muted); margin-left: 6px; transition: all 0.15s;
    }
    .collapse-btn:hover { background: var(--bg); border-color: var(--border); color: var(--text-primary); }
    /* «Свернуть все» в правой группе вкладок — как остальные значки там */
    .tab-bar .collapse-btn.tab-more {
      width: 32px; height: 32px; margin: 0; padding: 0; border: none;
      border-radius: 50%; background: transparent; color: #8b95a5;
    }
    .tab-bar .collapse-btn.tab-more:hover { background: rgba(0, 0, 0, .06); color: #333; }
    /* В «Канбане» сворачивать нечего — кнопка только в списке */
    .asg-tabs:not(:has(.tab[data-view="list"].active)) .asg-collapse { display: none; }

    /* Body area */
    .body-area { padding: 0 24px 6px; background: var(--bg); }

    /* Section */
    /* Свёрнутая секция списка — как свёрнутая секция карточки и шапка группы на
       диаграмме: заголовок на подложке, линии снизу нет */
    .section { margin-bottom: 0; border-bottom: none; }
    .section:not(.expanded) > .section-head { background: var(--backdrop); }
    .section:not(.expanded) > .section-head:hover { background: #e4e8f2; }
    .section-head {
      display: flex; align-items: center; gap: 8px;
      /* 50px держит одну высоту у шапок с кнопками и без них */
      min-height: 50px; box-sizing: border-box;
      padding: 9px 10px; width: 100%;
      border: none;
      border-radius: var(--r); background: transparent;
      cursor: pointer; user-select: none; transition: all 0.15s;
    }
    .section-head:hover { background: #f1f4f9; border-radius: var(--r); }

    .sec-check {
      width: 16px; height: 16px; border: 2px solid var(--border-mid);
      border-radius: 4px; cursor: pointer; flex-shrink: 0; transition: border-color 0.15s;
    }
    .sec-check:hover { border-color: var(--purple); }

    /* Название секции — одной строкой и во всю ширину текста: перенос ломал
       высоту шапки, а сжатие резало имя, хотя место рядом занимал чип
       сценария. Ужимается он (flex-shrink ниже), имя не жмётся вовсе */
    .sec-label {
      font-size: 13.5px; font-weight: 600; color: var(--text-primary);
      white-space: nowrap; flex-shrink: 0;
    }

    .count-chip {
      font-size: 12px; font-weight: 600; color: var(--text-secondary);
      background: #eef1f6; border: none;        /* рамку убрали — держится заливкой */
      padding: 1px 8px; border-radius: 12px;
    }
    /* Общий счётчик списка в фильтр-баре — без подложки, это просто число */
    .plan-filter-bar .fbar-lead > .count-chip,
    .fbar .fbar-lead > .count-chip { background: none; padding: 1px 2px; }
    /* Чип-подпись в шапке страницы («по проектам») — не счётчик, а пояснение,
       поэтому обычным начертанием: рядом крупный заголовок, спорить с ним не нужно */
    .proj-header .count-chip { font-weight: 400; }
    /* Счётчик в табе («Мои 8») — отступ от названия */
    .tab .count-chip { margin-left: 6px; }
    /* Счётчик «требуют внимания» в табе — как счётчик колонки «Требует решения»:
       розовая заливка, тёмно-красная цифра (плотный красный кружок спорил с заголовком) */
    .tab .nav-badge.count { margin-left: 6px; background: #f9d3cf; color: #a3302b; font-size: 11px; }
    /* Непрочитанных не осталось — счётчик в табе убираем */
    .tab.no-unread .count-chip.tab-cnt-green { display: none; }
    /* Непрочитанные в табе «Чат» — тот же кружок, что у чатов в сайдбаре:
       бледно-зелёная заливка, тёмная цифра, круг 18px */
    .tab .count-chip.tab-cnt-green {
      min-width: 18px; height: 18px; padding: 0; border: none; border-radius: 50%;
      display: inline-flex; align-items: center; justify-content: center;
      background: #d4f0eb; color: #0f6e56; font-size: 10px; font-weight: 600; line-height: 1;
    }
    .tab .count-chip.tab-cnt-attn  { background: #fff; border-color: #f2b8b4; color: #c23a35; }
    /* Невыполненные работы/задачи в табе — тот же кружок, но спокойного цвета:
       это остаток дел, а не непрочитанное */
    .tab .count-chip.tab-cnt-work {
      min-width: 18px; height: 18px; padding: 0; border: none; border-radius: 50%;
      display: inline-flex; align-items: center; justify-content: center;
      background: #e9edf4; color: #47566e; font-size: 10px; font-weight: 600; line-height: 1;
    }
    .tab .count-chip.tab-cnt-work:empty { display: none; }
    /* На выбранном табе у кружка белый фон: серый сливался с подложкой таба */
    .tab.active .count-chip.tab-cnt-work { background: #fff; }
    /* То же для обычного счётчика раздела в табе («Знания», «Бизнес процессы») */
    .tab.active > .count-chip { background: #fff; }
    /* Слева ленте чата добавляем столько же, сколько справа съедает полоса
       прокрутки, — иначе переписка выглядит сдвинутой к левому краю */
    body .vibe-chat-feed { padding-left: 30px; }
    /* «Полученное»: строки без рамок, отступ между ними 6px */
    #viewInbox .item-row, #viewInbox .item-row:hover { border-color: transparent; }
    #viewInbox .items-list { gap: 5px; }
    /* Шеврон — просто значок слева от названия, не кнопка: сворачивает клик по
       всей строке заголовка, поэтому своя рамка и ховер только запутывали */
    .sec-chevron {
      order: -1;
      color: var(--text-muted); display: flex; align-items: center; transition: transform 0.2s;
    }
    .sec-expand {
      order: 2; margin-left: auto; flex-shrink: 0; align-self: center;
      width: 26px; height: 26px; border-radius: 5px; flex-shrink: 0;
      border: 1px solid transparent; background: transparent;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; color: var(--text-muted); transition: all 0.15s;
    }
    /* Наведение — как у кнопок в правой части таб-бара (.tab-more): серая
       подложка и потемневший значок, без синей рамки и заливки */
    .sec-expand:hover { border-color: transparent; color: #333; background: rgba(0,0,0,0.06); }
    .sec-team {
      margin-left: auto; flex-shrink: 0;
      font-size: 11.5px; font-weight: 500; color: var(--text-muted);
      background: #f7f9fc; padding: 2px 8px; border-radius: 5px;
    }
    .sec-team + .sec-expand { margin-left: 4px; }

    /* Items */
    .items-list { padding: 3px 0 2px; display: flex; flex-direction: column; gap: 5px; }
    /* Строки списков плоские: уровень и наведение показывает рамка, не тень */
    .items-list > .item-row,
    .items-list > .item-group.work-group { box-shadow: none; }
    .items-list > .item-row:hover { box-shadow: none; }

    .item-row {
      display: flex; align-items: center; gap: 10px;
      padding: 9px 10px;
      border: 1px solid var(--border); border-radius: var(--r);
      background: var(--card); cursor: pointer;
      transition: all 0.15s;
      flex-wrap: wrap;
    }
    /* Наведение подсвечиваем только рамкой: заливка перекрашивала бы строку под
       чипами и кодом задачи, и они начинали бы с ней сливаться.
       Цвет рамки один на весь интерфейс — #9aa7bf */
    .item-row:hover { border-color: #9aa7bf; }
    /* Обычная строка списка 40px, составная (группа, вложенный сценарий) 50px */
    .items-list > .item-row,
    .items-list .item-subrow { min-height: 40px; box-sizing: border-box; }
    .items-list > .item-row.item-row-parent,
    .work-group > .item-row-parent { min-height: 50px; box-sizing: border-box; }
    /* Разделы в инструкциях и библиотеки в сценариях — фон как у составной задачи */
    .item-row.lib-row { background: #f4f6fd; border-color: #dfe2f5; }
    .item-row.lib-row:hover { border-color: #9aa7bf; }
    .item-row.selected { border-color: #0098a6; background: #ffffff; }
    /* «Задачи»: без рамок у строк (прозрачная рамка — без сдвига раскладки) */
    #viewWorkTasks #wt-all .item-row { border-color: transparent; }
    /* Наведение на строку задачи — только рамка ярче, фон не меняем */
    #viewWorkTasks #wt-all .item-row:hover { border-color: #9aa7bf; background: var(--card); }
    #viewWorkTasks #wt-all .item-row:has(.item-name.danger):hover { background: #fde8e6; border-color: #9aa7bf; }
    #wt-all .work-group:hover { border-color: #9aa7bf; }
    /* Групповая задача: при наведении только рамка (на work-group), фон не меняем */
    #viewWorkTasks #wt-all .item-row-parent:hover { background: #e2e9f8; }
    /* «Задачи»: больше воздуха между строками */
    #wt-all .items-list { gap: 5px; }
    /* Задачи: панель фильтров и шапка колонок закреплены сверху; список скроллится по
       вертикали, а при нехватке ширины — по горизонтали (скролл внизу видимой области).
       Правая часть строки не переносится. */
    :is(#viewWorkTasks, #wt-all) .item-row, :is(#viewWorkTasks, #wt-all) .item-head { flex-wrap: nowrap; }
    .content:has(> .body-area > #wt-all) { overflow: hidden; display: flex; flex-direction: column; }
    .content:has(> .body-area > #wt-all) > .body-area { flex: 1; min-height: 0; display: flex; flex-direction: column; }
    #wt-all { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }
    #wt-all > .plan-filter-bar { flex-shrink: 0; }
    /* Строка фильтров «Прогресса выполнения» начинается сразу под вкладками,
       а справа кончается по краю списка — своих полей ей там не нужно */
    :is(#wt-tree, #wt-all) > .plan-filter-bar { margin-top: 0 !important; padding-right: 0; }
    #wt-all > .items-list {
      flex: 1; min-height: 0; overflow: auto; padding: 3px 6px 4px;
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
    }
    #wt-all > .items-list::-webkit-scrollbar { width: 5px; height: 5px; }
    #wt-all > .items-list::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    #wt-all > .items-list::-webkit-scrollbar-thumb:hover { background: #b9b6d4; }
    #wt-all > .items-list::-webkit-scrollbar-track { background: transparent; }
    /* Шапка колонок закреплена по вертикали, едет по горизонтали вместе со списком */
    #wt-all .items-list > .item-head { position: sticky; top: 0; z-index: 6; }
    #wt-all .items-list > .item-head,
    #wt-all .items-list > .item-row,
    #wt-all .items-list > .item-group { min-width: 900px; }
    /* Список — flex-колонка со скроллом: элементы не сжимаются по вертикали (иначе
       группа с overflow:hidden схлопывается при переполнении по высоте). */
    #wt-all > .items-list > * { flex-shrink: 0; }

    .item-check {
      width: 16px; height: 16px; border: 1.5px solid #d5dae4;
      border-radius: 4px; cursor: pointer; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
    }
    .item-check:hover { border-color: #0098a6; }
    .item-check.checked { background: #0098a6; border-color: #0098a6; }
    /* Выбранная строка — её чекбокс включён (класс .checked навешивает syncSelectedChecks) */
    .item-check.checked::after {
      content: ''; width: 8px; height: 5px;
      border: 2px solid #fff; border-top: none; border-right: none;
      /* сдвиг до поворота — иначе галочка уезжает по диагонали и не по центру */
      transform: translateY(-1px) rotate(-45deg); display: block;
    }
    /* Выполненная — приглушена, но читается: зачёркивание оставлено только корзине */
    .item-row.done .item-name { color: var(--text-muted); }
    .item-row.trashed .item-name { text-decoration: line-through; color: var(--text-muted); }

    /* Код — полупрозрачная подложка: чип всегда на тон темнее своей строки,
       какого бы цвета она ни была, поэтому переопределений по строкам нет.
       Текст один во всех контекстах: 11.5px/500 #6b7a8f */
    .item-id {
      font-size: 11.5px; font-weight: 500;
      padding: 2px 8px; border-radius: 4px; flex-shrink: 0;
      color: #6b7a8f; background: rgba(15,30,60,.05); border: none;
    }
    .item-name { font-size: 13px; font-weight: 500; color: var(--text-primary); flex: 1; min-width: 160px; }
    /* Шеврон за именем — признак перехода: строка открывает свою страницу.
       Тихий серый, под курсором темнеет вместе со строкой */
    .row-go { color: #b2bac6; margin-left: 6px; vertical-align: -2px; flex-shrink: 0; }
    .item-row:hover .row-go { color: #6b7a8f; }
    /* Названия инструкций — обычным начертанием */
    .item-row[onclick*="openRequirement"] .item-name { font-weight: 400; }
    /* «Задачи»: жирным выделяется только составная задача, обычные — регулярным */
    #wt-all .items-list .item-row:not(.item-row-parent) .item-name { font-weight: 400; }
    /* Незапланированная задача: сроков и исполнителя нет — вытягиваем описание в одну
       строку по свободной области этих колонок, а не переносим под именем. */
    #wt-all .item-row:has(.ichip-status.st-unplanned) .item-name { white-space: nowrap; min-width: 0; }
    .item-desc { font-weight: 400; color: var(--text-muted); }
    .item-name.danger { color: var(--red); }
    /* «Все задачи»: проблемную задачу подсвечиваем фоном строки, имя — обычным цветом */
    :is(#viewWorkTasks, #wt-all) .item-name.danger { color: var(--text-primary); }
    /* Тона те же, что у отстающего от базы процесса на диаграмме: подложка
       #fde8e6, имя чёрное, код — белёсый чип с тёмно-красным текстом */
    :is(#viewWorkTasks, #wt-all) .item-row:has(.item-name.danger) { background: #fde8e6; border-color: #f3d4d1; }
    :is(#viewWorkTasks, #wt-all) .item-row:has(.item-name.danger):hover { border-color: #9aa7bf; }
    /* Код на цветной строке своих правил не требует: подложка полупрозрачная */
    /* Непрочитанное во всём интерфейсе бирюзовое — точка в навигации, счётчики чатов;
       строка списка держится того же цвета, чтобы признак читался как один и тот же */
    /* Непрочитанное держим одной заливкой: точка перед именем дублировала
       и полосу слева, и сам тон строки. Заливку взяли на тон плотнее —
       без точки признак должен читаться сам */
    .item-row.unread { background: #d5efe1; box-shadow: inset 3px 0 0 var(--teal); }
    .item-row.unread .item-name { font-weight: 700; }
    /* Строка непрочитанного тонирована, а нейтральные чипы и код задачи заливаются
       почти тем же светлым тоном и на ней растворяются — здесь делаем их белыми.
       Цветные статусы (отклонён, приостановлен и т.п.) не трогаем: у них своя
       заливка, с фоном строки она не совпадает */
    .item-row.unread .ichip-dates,
    .item-row.unread .ichip-hours,
    .item-row.unread .ichip-skill,
    .item-row.unread .ichip-status.progress,
    .item-row.unread .ichip-status:not([class*="st-"]):not(.progress):not(.deferred) {
      background: #fff;
    }
    /* «Сигналы исполнителей» — текст красный (сигнал требует внимания) */
    .section-signals .item-name { color: #c23a35; }
    .section-signals .item-name .item-desc { color: #d78a86; }
    .item-dates { font-size: 12px; color: var(--text-muted); flex-shrink: 0; white-space: nowrap; margin-left: 12px; }
    /* Исполнитель в строке задачи: аватар + краткое имя */
    .item-assignee { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; margin-left: 12px; font-size: 12px; color: var(--text-secondary); white-space: nowrap; }
    .item-assignee .mini-ava { width: 20px; height: 20px; font-size: 8px; }

    /* План работ — имитация колонок в правой части строки */
    :is(#viewWorkTasks, #wt-all) .item-chevron { margin-left: 0; }
    /* Когда строка не помещается, перенесённый хвост прижимается вправо. На первой
       строке это незаметно: .item-name с flex:1 съедает весь свободный запас. */
    :is(#viewWorkTasks, #wt-all) .item-row { justify-content: flex-end; }
    /* Подпись колонок списка задач: строчными, серым, без фона — чтобы не спорила
       со строками. Паддинг 11px = 10px строки + её рамка, иначе колонки не совпадут. */
    :is(#viewWorkTasks, #wt-all) .item-head {
      display: flex; align-items: center; gap: 10px;
      padding: 2px 11px 6px;
      position: sticky; z-index: 6;
      background: var(--bg);
      font-size: 11px; font-weight: 500; color: #a0abbb;
    }
    /* Исполнитель или бейдж заданий — фиксированная колонка, выключка влево */
    :is(#viewWorkTasks, #wt-all) .item-who {
      width: 150px; flex-shrink: 0; display: flex; align-items: center; justify-content: flex-start;
      gap: 6px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
      font-size: 12px; color: var(--text-secondary);
    }
    :is(#viewWorkTasks, #wt-all) .item-wf { width: 126px; flex-shrink: 0; display: flex; align-items: center; overflow: hidden; order: 1; }
    /* Сроки — чипом, текст внутри выровнен вправо; пустые остаются без фона */
    :is(#viewWorkTasks, #wt-all) .item-dates { width: 118px; flex-shrink: 0; margin-left: 0; text-align: center; box-sizing: border-box; }
    :is(#viewWorkTasks, #wt-all) .item-row .item-dates:not(:empty) {
      background: #eef1f6; border-radius: 6px;
      padding: 3px 8px; font-size: 11.5px; color: #5c6b80;
    }
    /* На лавандовом фоне составной задачи серый чип сливается — темнее */
    :is(#viewWorkTasks, #wt-all) .item-row-parent .item-dates:not(:empty) { background: #dde3f4; color: #4d5a80; }
    :is(#viewWorkTasks, #wt-all) .item-hours { width: 36px; flex-shrink: 0; font-size: 12px; color: var(--text-muted); white-space: nowrap; text-align: left; }
    :is(#viewWorkTasks, #wt-all) .item-chips { width: 118px; flex-shrink: 0; margin-left: 0; justify-content: center; flex-wrap: nowrap; }
    /* Статус — последняя колонка списка (в разметке он идёт вторым) */
    :is(#viewWorkTasks, #wt-all) .item-row .item-chips,
    :is(#viewWorkTasks, #wt-all) .item-head .item-chips { order: 9; }
    /* Чипы статуса — одинаковой ширины во всю колонку, текст по центру;
       высота (паддинг/шрифт) как у чипа-кода и срока в строке */
    :is(#viewWorkTasks, #wt-all) .item-row .item-chips > .ichip-status {
      display: flex; width: 100%; box-sizing: border-box;
      align-items: center; justify-content: center;
      padding: 3px 8px; font-size: 11.5px; line-height: normal;
    }

    /* Ячейки заголовка — строго после правил колонок: у .item-who и .item-hours свои
       шрифт и цвет, и при равной специфичности побеждает то, что объявлено ниже */
    :is(#viewWorkTasks, #wt-all) .item-head > * { font-size: 11px; font-weight: 500; color: inherit; }
    :is(#viewWorkTasks, #wt-all) .item-head .item-check { visibility: hidden; }
    /* Код в заголовке — обычный текст, без плашки строки */
    :is(#viewWorkTasks, #wt-all) .item-head .item-id { background: none; border: none; padding: 0; }
    .wf-chip {
      display: inline-block; max-width: 100%; box-sizing: border-box;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      /* Полупрозрачное затемнение — чип на тон темнее фона своей строки, каким бы он ни был */
      background: rgba(0,0,0,.06); color: #55647f;
      font-size: 11.5px; font-weight: 600; padding: 2px 8px; border-radius: 4px;
    }

    /* Раскрывающаяся задача (с подработами) */
    .item-group { display: flex; flex-direction: column; gap: 5px; }
    .item-chevron {
      color: #b2bac6; margin-left: auto; flex-shrink: 0;
      transition: transform .15s;
    }
    /* Шеврон переворачивается только у своей строки: у вложенного сценария он
       показывал раскрытие, когда открыт был лишь внешний */
    .item-group.open > .item-row .item-chevron { transform: rotate(180deg); }
    .item-row-parent .item-chips { margin-left: 0; }
    .item-subrows {
      display: none; flex-direction: column; gap: 3px;
      padding-left: 22px; margin-top: 3px;
    }
    /* Раскрывается только свой уровень: без `>` открытая внешняя группа заодно
       разворачивала вложенный в неё сценарий (как было с шевроном выше) */
    .item-group.open > .item-subrows { display: flex; }
    .item-subrow { background: #fafbfd; }
    .item-subrow .subrow-ico { color: #8b95a5; flex-shrink: 0; }
    .res-ico { display: inline-flex; align-items: center; color: #8b95a5; flex-shrink: 0; margin-right: 2px; }
    /* Звезда избранного справа от имени хранилища */
    .fav-star {
      background: none; border: none; cursor: pointer; padding: 2px; margin-left: 8px;
      color: #ccd2de; flex-shrink: 0; display: inline-flex; align-items: center;
      transition: color 0.12s;
    }
    .fav-star:hover { color: #0f6e56; }
    .fav-star.active { color: #72c1a4; }             /* избран — приглушённо-зелёная */
    .fav-star.active svg { fill: none; }             /* контуром, без заливки */

    /* Выделение задач с несколькими работами от разных исполнителей.
       Составные итемы держим в голубом тоне — так они читаются как «папка»,
       а не как обычная строка списка */
    .item-row-parent {
      background: #e9effc;
      box-shadow: inset 3px 0 0 #6e79d6;
    }
    .item-row-parent:hover { border-color: #9aa7bf; }

    /* Вкладка «Результаты работы» потока — генерируемые результаты работы */
    .art-hint {
      display: flex; align-items: flex-start; gap: 8px;
      background: #eff5ff; color: #3f5b86; border-radius: 8px;
      padding: 10px 12px; margin: 4px 0 14px; font-size: 12.5px; line-height: 1.5;
    }
    .art-hint svg { flex-shrink: 0; margin-top: 1px; color: #6c8fc7; }
    /* Балон с описанием экрана — как .art-hint, но с крестиком справа */
    /* Вариант «белая карточка с акцентной полосой слева» */
    .screen-hint {
      display: flex; align-items: flex-start; gap: 10px;
      /* Подложка — цвет фона страницы: подсказка не спорит с содержимым */
      background: var(--bg); color: #55647f;
      border-left: 3px solid var(--teal); border-radius: 0 8px 8px 0;
      box-shadow: 0 1px 2px rgba(16,32,64,.06), 0 2px 6px rgba(16,32,64,.07);
      padding: 11px 12px; margin: 10px 0; font-size: 12.5px; line-height: 1.5;
      flex-shrink: 0;
    }
    .screen-hint > svg { flex-shrink: 0; margin-top: 2px; color: var(--teal); }
    .screen-hint > span { flex: 1; min-width: 0; }
    .screen-hint-x {
      flex-shrink: 0; width: 22px; height: 22px; margin: -2px -4px 0 0; padding: 0;
      display: flex; align-items: center; justify-content: center;
      border: none; border-radius: 5px; background: transparent; color: #6c8fc7;
      cursor: pointer; transition: background .12s, color .12s;
    }
    .screen-hint-x:hover { background: rgba(15,30,60,.08); color: #3f5b86; }
    .screen-hint-x { color: #9aa6b6; }
    .hint-toggle { display: none; }
    .hint-toggle.show { display: inline-flex; }
    .art-card {
      border: 1px solid var(--border); border-radius: 10px;
      margin-bottom: 8px; overflow: hidden; background: #fff;
    }
    .art-top { display: flex; align-items: center; gap: 10px; padding: 11px 14px; cursor: pointer; }
    .art-top:hover { background: #fafbfd; }
    .art-top .req-name { flex: 1; font-weight: 500; color: var(--text-primary); }
    .art-status { font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 20px; flex-shrink: 0; }
    .art-status.ready { background: #fff; color: #0f6e56; }
    .art-status.wait { background: #eef1f6; color: #8a94a6; }
    .art-meta {
      display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
      padding: 9px 14px; border-top: 1px dashed var(--border);
      background: #fafbfd; font-size: 12px; color: var(--text-secondary);
    }
    .art-src b { color: var(--text-primary); font-weight: 600; }
    .art-store { display: flex; align-items: center; gap: 6px; margin-left: auto; }
    .art-store-label { color: var(--text-muted); }
    /* У созданного результата работы место хранения уже не выбирают — вместо списка
       та же по весу плашка, но статичная */
    .art-store-val {
      background: #eef1f6; color: #55647f; border-radius: 6px;
      padding: 2px 8px; white-space: nowrap;
    }

    /* Подменю кнопки «Прикрепить» в шапках секций */
    /* Меню возврата параметра в «Планировании» выглядит так же, как меню скрепки */
    .attach-menu, .param-add-menu {
      position: absolute; top: calc(100% + 6px); right: 0; z-index: 50;
      background: #fff; border: 1px solid var(--border); border-radius: 9px;
      box-shadow: var(--shadow-md); padding: 5px; min-width: 168px;
      display: flex; flex-direction: column;
    }
    .attach-item {
      display: flex; align-items: center; gap: 8px;
      padding: 7px 10px; border-radius: 6px; cursor: pointer;
      font-size: 13px; font-weight: 400; color: var(--text-primary); white-space: nowrap;
      transition: background 0.12s;
    }
    .attach-item:hover { background: #f1f4f9; }
    .attach-item svg { color: var(--text-muted); flex-shrink: 0; }
    .attach-plus { color: var(--teal); font-weight: 700; margin: 0 -4px 0 -2px; }
    /* Дерево доступных инструкций: группы — заголовками, листья с отступом */
    .attach-menu.attach-tree { min-width: 268px; max-height: 300px; overflow-y: auto; }
    .attach-group {
      padding: 7px 10px 3px; font-size: 10.5px; font-weight: 700; letter-spacing: .6px;
      text-transform: uppercase; color: #9aa6b6;
    }
    .attach-leaf { padding-left: 20px; font-size: 12.5px; color: var(--text-body); }

    /* Групповая карточка задачи с несколькими работами.
       Фон чуть светлее страницы (#f6f7fa) плюс тонкая рамка: на подложке
       --backdrop группа сливалась с фоном области */
    /* Вся группа на подложке корневой строки (#eef1f6) — тогда и отступы вокруг
       вложенных строк залиты тем же цветом, а не белым */
    .work-group {
      background: #eef1f6; border: 1px solid var(--border); border-radius: 8px;
      gap: 0; overflow: hidden;
    }
    .work-group .item-row-parent { background: transparent; box-shadow: none; border: none; border-radius: 0; }
    .work-group .item-row-parent:hover { background: #e2e9f8; }
    .work-group .item-row-parent .item-name { display: flex; align-items: center; gap: 8px; }
    /* Чипы на тонированной строке (составная задача, вложенный сценарий, вызов
       сценария) красим полупрозрачным затемнением: оттенок строки сохраняется,
       а чип всегда на тон темнее её — со светлыми заливками он сливался */
    /* Статусы сюда не входят: у них своя палитра, и затемнение её съедало */
    .item-row.item-row-parent > .item-chips .ichip.ichip.ichip.ichip:not(.ichip-status),
    .item-row.item-row-parent .item-name > .work-badge { background-color: rgba(15,30,60,.07); }
    /* Бледные статусы на тонированной строке — на тон светлее подложки, чтобы
       не сливались: обводки у статусов больше нет нигде */
    .item-row.item-row-parent .ichip-status.st-waiting,
    .item-row.item-row-parent .ichip-status.st-trashed { background: #fff; }
    /* Пометки «вложенный сценарий» / «вызов сценария» — к правому краю строки,
       в одну колонку с остальными чипами */
    :is(#flow-scenario, .scenario-list) .item-row-parent .item-name { display: flex; align-items: center; gap: 8px; }
    :is(#flow-scenario, .scenario-list) .item-row-parent .item-name > .work-badge { margin-left: auto; }
    /* Бэйдж — такой же чип строки, как остальные: пока он лежал внутри имени,
       имя жалось в две строки, а чипы оставались на первой. display:contents
       отдаёт бэйдж в поток строки — переносится на вторую строку вместе с чипами */
    :is(#flow-scenario, .scenario-list) .item-row-parent > .item-name:has(> .work-badge) { display: contents; }
    :is(#flow-scenario, .scenario-list) .item-row-parent > .item-name:has(> .work-badge) > .flow-open-link { flex: 1 1 0; min-width: 160px; }
    /* Пометка вида строки — тем же чипом, что значение параметра */
    .item-row .item-name > .work-badge {
      background-color: #d3ecef; color: #056470;
      font-size: 11.5px; padding: 3px 11px; border-radius: 6px;
    }
    /* Раздел — тот же итем, что вызов сценария в потоке: серая подложка, стрелка
       после имени, бэйдж у правого края. Синей полосы из списка задач не надо */
    .folder-row.item-row-parent {
      background: #e3ebf9; box-shadow: none;
    }
    .folder-row.item-row-parent:hover { border-color: #9aa7bf; }
    .folder-row .item-name { display: flex; align-items: center; gap: 8px; }
    .folder-row .item-name > .work-badge { margin-left: auto; }
    /* Вызов сценария — отдельная строка без вложенных задач, но выглядит так же,
       как строка вложенного сценария: та же подложка, рамка и радиус группы */
    /* .item-row.item-row-parent — специфичность выше правила #viewFlow, которое
       гасит рамку у строк списка потока */
    #flow-scenario .items-list > .item-row.item-row-parent {
      background: #eef1f6; box-shadow: none;
      border: 1px solid var(--border); border-radius: 8px;
    }
    /* Наведение — только рамка, фон не меняем. Цвет рамки тот же, что у остальных
       строк списка потока (#9aa7bf) */
    #flow-scenario .items-list > .item-row.item-row-parent:hover { background: #eef1f6; border-color: #9aa7bf; }
    #flow-scenario .work-group:hover { border-color: #9aa7bf; }
    #flow-scenario .work-group .item-row-parent:hover { background: transparent; }
    .work-group .item-subrows { padding: 0 8px 6px 8px; margin-top: 0; }
    .work-group .item-subrow { background: #fff; }

    /* Имя вложенного потока — ссылка внутрь потока; раскрытие — кликом по остальной строке */
    .flow-open-link { cursor: pointer; }
    .flow-open-link:hover { text-decoration: underline; }

    .work-badge {
      display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
      background: #e7eafb; color: #5560c9;
      font-size: 11px; font-weight: 500; padding: 2px 10px 2px 4px; border-radius: 20px;
    }
    .work-badge .work-avas { display: inline-flex; }
    .work-badge .mini-ava { width: 18px; height: 18px; font-size: 8px; border: 2px solid #e7eafb; }
    .work-badge .mini-ava + .mini-ava { margin-left: -7px; }


    /* Chips inside task list items */
    .item-chips { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; margin-left: auto; min-width: 0; }
    .ichip {
      font-size: 10.5px; font-weight: 400; line-height: 1;
      padding: 3px 8px; border-radius: 5px; white-space: nowrap;
    }
    .sec-empty { padding: 9px 14px; color: #9aa3b2; font-size: 13px; }
    /* Вкладка «Участники» от 1200px: слева «Сотрудники» и «Агенты», справа «Профили».
       Вторая колонка нужна только когда третья секция есть — иначе список во всю ширину. */
    @media (min-width: 1200px) {
      #exec-members:has(> .section:nth-child(4)) { display: grid; grid-template-columns: 2fr 1fr; column-gap: 8px; align-items: start; }
      #exec-members:has(> .section:nth-child(4)) > .plan-filter-bar { grid-column: 1 / -1; }
      #exec-members:has(> .section:nth-child(4)) > .section:nth-child(2) { grid-column: 1; grid-row: 2; }  /* Сотрудники */
      #exec-members:has(> .section:nth-child(4)) > .section:nth-child(3) { grid-column: 1; grid-row: 3; }  /* Агенты */
      #exec-members:has(> .section:nth-child(4)) > .section:nth-child(4) { grid-column: 2; grid-row: 2 / span 2; }  /* Профили */
    }
    /* «Профили»: две колонки при наличии места, иначе одна (container-query по ширине тела секции) */
    #exec-members .section-body:has(.profiles-grid) { container-type: inline-size; }
    #exec-members .flows-list.profiles-grid { display: grid; grid-template-columns: 1fr; gap: 10px 14px; align-content: start; }
    @container (min-width: 740px) { #exec-members .flows-list.profiles-grid { grid-template-columns: 1fr 1fr; } }
    /* Профиль — шаблон роли, а не человек: тот же вид карточки, но аватар со значком */
    .prof-ava { background: linear-gradient(135deg,#7b86a8,#9aa6c4); }
    .prof-ava svg { color: #fff; }
    .ichip-status { font-weight: 600; }
    .ichip-status.open    { background: #e8f0fe; color: #2563b8; }
    .ichip-status.closed  { background: #eceef2; color: #6b7a8f; }
    .ichip-status.done    { background: #e3f5ec; color: #1f9d63; }
    .ichip-status.planned  { background: #eef0f6; color: #5a6b86; }
    .ichip-status.deferred { background: #fdf0e0; color: #b5751f; }
    .ichip-status.progress { background: #e3f5ec; color: #1f9d63; }

    /* Палитра статусов задачи. Один вид на весь интерфейс — тот, что сложился
       на вкладке «Задачи»: плоская бледная заливка, обводок нет, начертание
       обычное. Состояние различает цвет, а не оформление; рядом с именем
       задачи обводка читалась как вторая рамка строки.
       Объявлена после .progress, иначе та перебьёт фон у «Выполняется». */
    .ichip-status {
      display: inline-flex; align-items: center; height: 18px;
      /* Верхний отступ сдвигает надпись вниз: у прописных нет нижних выносных,
         и при точном центрировании текст читается прижатым кверху */
      padding: 2px 8px 0; box-shadow: none; font-weight: 400;
    }
    .ichip-status.st-deferred  { background: #f1f3f7; color: #8b95a5; }
    .ichip-status.st-unplanned { background: #f7c3bf; color: #8f2f2b; }
    .ichip-status.st-waiting   { background: #e7eaf0; color: #58637a; }
    .ichip-status.st-todo      { background: #dff3e0; color: #2f8f4e; }
    /* «Выполняется» — самый частый рабочий статус, текст плотнее остальных */
    .ichip-status.st-doing     { background: #c9edcf; color: #0f5f30; }
    /* Завершившиеся: белая заливка на белой строке пропадала — берём серую */
    .ichip-status.st-aborted   { background: #e9ecf3; color: #d98324; }
    .ichip-status.st-rejected  { background: #e9ecf3; color: #d13b34; }
    .ichip-status.st-done      { background: #e9ecf3; color: #2563b8; }
    /* Закрытые остаются плотными: закрытость читается пятном, а не оттенком */
    .ichip-status.st-closed-no { background: #8b95a5; color: #fff; }
    .ichip-status.st-closed-ok { background: #1f6fe0; color: #fff; }
    .ichip-status.st-trashed   { background: #f1f4f9; color: #9ca3af; text-decoration: line-through; }
    /* Статусы прочих сущностей (не палитра задач) остаются нейтральными */
    .ichip-status:not([class*="st-"]):not(.progress):not(.deferred) {
      background: #eef0f6; color: #5a6b86; box-shadow: none;
    }
    .ichip-status.deferred {
      background: #f1f3f7; color: #8b95a5; box-shadow: inset 0 0 0 1px #dfe3ea;
    }
    .ichip-skill { background: #eef0f4; color: #50607a; }
    .ichip-vol.vol-min    { background: #eef6ee; color: #4a8c5a; }
    .ichip-vol.vol-small  { background: #f1f6e3; color: #6f8c1f; }
    .ichip-vol.vol-medium { background: #fdf6e3; color: #b07d12; }
    .ichip-vol.vol-large  { background: #fceede; color: #c4691a; }
    .ichip-vol.vol-huge   { background: #fce8e6; color: #c0392b; }
    .ichip-dates { background: #eef0f4; color: #50607a; display: inline-flex; align-items: center; gap: 4px; }
    /* Иконка календаря маской — красится в цвет текста чипа */
    .ichip-dates::before {
      content: ''; width: 10px; height: 10px; flex-shrink: 0; background: currentColor;
      -webkit-mask: var(--ico-cal) center / contain no-repeat;
              mask: var(--ico-cal) center / contain no-repeat;
    }
    :root {
      --ico-cal: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'%3E%3Crect x='3' y='4.5' width='18' height='17' rx='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='7'/%3E%3Cline x1='8' y1='2' x2='8' y2='7'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E");
      --ico-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9.5'/%3E%3Cpolyline points='12 6.5 12 12 16 14'/%3E%3C/svg%3E");
    }
    .ichip-hours { background: #eef0f4; color: #50607a; display: inline-flex; align-items: center; gap: 4px; }
    .ichip-hours::before {
      content: ''; width: 10px; height: 10px; flex-shrink: 0; background: currentColor;
      -webkit-mask: var(--ico-clock) center / contain no-repeat;
              mask: var(--ico-clock) center / contain no-repeat;
    }

    /* Kanban board */
    .kanban {
      display: grid; grid-template-columns: repeat(3, 1fr);
      gap: 12px; align-items: start; padding-top: 4px;
    }
    @media (max-width: 900px) { .kanban { grid-template-columns: 1fr; } }
    .kanban-col {
      /* Подложка колонки — фон окна страницы: область под ней снова белая
         карточка, и отдельный, более тёмный серый на ней только шумел */
      background: var(--bg); border-radius: 12px;
      /* Тень та же, что у строк списков — колонки читаются плашками */
      box-shadow: 0 1px 2px rgba(16,32,64,.06), 0 2px 6px rgba(16,32,64,.07);
      padding: 10px; display: flex; flex-direction: column; gap: 9px;
    }
    .kanban-col-head {
      display: flex; align-items: center; gap: 7px;
      font-size: 12.5px; font-weight: 600; color: #3d4655;
      padding: 3px 5px 1px;
    }
    .kanban-col-head .k-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    /* Счётчик колонки — кружок как бейджи в сайдбаре и табах (был вытянутой пилюлей).
       min-width держит круг у однозначных, при двух цифрах чип аккуратно растёт */
    /* Счётчик стоит сразу за именем колонки, а не у правого края */
    .kanban-col-head .k-count {
      /* line-height: 0 — иначе флекс центрирует строку вместе с местом под
         выносные элементы, и цифра встаёт выше центра кружка */
      margin-left: 0; font-size: 11px; font-weight: 600; color: #8b95a5;
      background: #e2e6ee; border-radius: 50%; padding: 0 4px; line-height: 0;
      min-width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center;
    }
    /* Красный — только у «Требует решения»: там счётчик про внимание, а не про
       объём. Тона те же, что у бейджа .nav-badge.count.red-soft в сайдбаре */
    .kanban-col.col-attention .kanban-col-head .k-count { background: #f9d3cf; color: #a3302b; }
    /* Правая группа («Все», листалка) — к правому краю */
    .kanban-col-head .k-count ~ .ka-pager { margin-left: auto; }
    .kanban-col-head .k-all {
      margin-left: auto;
      font-size: 11px; font-weight: 600; color: #0098a6;
      padding: 1px 5px; border-radius: 5px; line-height: 1.6;
      cursor: pointer; transition: background 0.12s, color 0.12s;
    }
    .kanban-col-head .k-all:hover { background: rgba(0,152,166,0.12); color: #00838f; }
    .kanban-col.col-todo .k-dot { background: #8b95a5; }
    /* Цвета как у чипов статуса: «Выполняется» зелёный, «Выполнено» синий */
    .kanban-col.col-progress .k-dot { background: #1f9d63; }
    .kanban-col.col-done .k-dot { background: #2563b8; }
    .kanban-col.col-attention .k-dot { background: var(--red); }
    .kanban-col.col-fail .k-dot { background: #dc2626; }
    .kanban-col.col-break .k-dot { background: #f59e0b; }
    .kanban-col.col-signal .k-dot { background: #8b5cf6; }

    /* Моя активность — задачи: 2/3-колонки */
    .mt-view {
      display: grid; gap: 12px; align-items: start; padding-top: 4px;
    }
    .mt-view-current   { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .mt-view-attention { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    @media (max-width: 1100px) {
      .mt-view-current   { grid-template-columns: 1fr 1fr; }
      .mt-view-attention { grid-template-columns: 1fr; }
    }
    @media (max-width: 800px) {
      .mt-view-current   { grid-template-columns: 1fr; }
    }
    .mt-view .mt-col { display: flex; flex-direction: column; gap: 12px; }
    /* Доска с полосой «Выполнены недавно». Пока три колонки не помещаются, готовые
       уезжают под доску во всю ширину и раскладываются в несколько колонок; как только
       места хватает — встают третьей колонкой, как обычная колонка доски. Меряем
       ширину области контента, а не окна: сайдбар пользователь двигает сам */
    #viewAssignments .body-area { container-type: inline-size; }
    .mt-view.has-done-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .mt-view .mt-done {
      grid-column: 1 / -1;
      display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
      gap: 9px; align-content: start;
    }
    .mt-view .mt-done > .kanban-col-head,
    .mt-view .mt-done > .kanban-empty { grid-column: 1 / -1; }
    /* Не помещаются и две колонки (2 × 278 + зазор 12 = 568) — выкладываем всё
       в одну, в порядке движения задачи: в работе → на выполнение → отказы →
       прерывания → выполнены. Для этого .mt-col пропускает свои колонки в общий
       поток, иначе пары «на выполнение + отказы» и «в работе + прерывания»
       остались бы склеенными и вклинились бы друг в друга */
    @container (max-width: 567px) {
      .mt-view.has-done-row { grid-template-columns: 1fr; }
      .mt-view.has-done-row .mt-col      { display: contents; }
      .mt-view.has-done-row .col-progress { order: 1; }
      .mt-view.has-done-row .col-todo     { order: 2; }
      .mt-view.has-done-row .col-fail     { order: 3; }
      .mt-view.has-done-row .col-break    { order: 4; }
      .mt-view.has-done-row .mt-done      { order: 5; }
    }
    /* 3 × (карточка 258 + паддинги колонки 20) + 2 зазора по 12 = 858 */
    @container (min-width: 858px) {
      .mt-view.has-done-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
      .mt-view .mt-done {
        grid-column: auto;
        display: flex; flex-direction: column; gap: 9px;
      }
    }

    .kanban-card.mini {
      padding: 8px 10px; gap: 4px;
    }
    .kanban-card.mini .mini-top {
      display: flex; align-items: center; justify-content: space-between; gap: 6px;
    }
    .kanban-card.mini .kanban-card-name {
      font-size: 12.5px; line-height: 1.3;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .kanban-card.mini .kanban-ava { width: 18px; height: 18px; font-size: 9px; }

    /* Фильтры стоят слева, как во всех тулбарах; вправо уходит только переключатель
       вида. Кнопке «Свернуть все» возвращаем обычный отступ — до края она
       больше не тянется, справа от неё теперь переключатель */
    .plan-filter-bar > .asg-views { margin-left: auto; flex-shrink: 0; }
    #inbox-tasks .plan-filter-bar .collapse-btn { margin-right: 0; }
    /* Строка фильтров «Моих работ» — без боковых полей: её пилюли встают
       по левому краю области, вровень с содержимым списка под ней */
    #inbox-tasks > .plan-filter-bar { padding-left: 0; padding-right: 0; }
    /* Тулбар «Моих работ» прижат к вкладкам: своих внешних полей ему не нужно —
       воздух сверху даёт полоса вкладок, снизу — отступ первой секции */
    body #inbox-tasks > .plan-filter-bar { margin: 0 !important; }

    /* «Требует решения» — полоса над доской: сигналы из «Полученных», сведённые
       по задачам. Не колонка статуса, поэтому не в сетке .mt-view, а во всю ширину,
       а карточки внутри раскладываются рядами по мере наполнения */
    .kanban-attn { margin-bottom: 12px; }
    /* Карточки всегда в одну строку. Ширина карточки — 258px, но если в строку влезают
       все, свободное место делится между ними (1fr) и листать становится нечего.
       Страница карусели = видимая ширина, поэтому число страниц пересчитывается
       само при смене ширины окна и не завязано на количество карточек */
    .kanban-attn .ka-grid {
      display: grid; grid-auto-flow: column; grid-auto-columns: minmax(258px, 1fr); gap: 9px;
      overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
      scrollbar-width: none;
    }
    .kanban-attn .ka-grid::-webkit-scrollbar { display: none; }
    .kanban-attn .ka-grid > .kanban-card { scroll-snap-align: start; }
    /* Карточки в ряду тянутся до общей высоты, а списки нарушений у них разной длины —
       строку чипов прижимаем к низу, чтобы чипы и колокольчики стояли на одной линии */
    .kanban-attn .kanban-card-chips { margin-top: auto; }
    /* Листалка в заголовке полосы: стрелки + «n из N» */
    /* Листалка стоит левее «Все», поэтому теперь именно она прижимает правую
       группу к краю. Когда листать нечего, её скрывают (.one-page ниже) —
       и прижимать снова должна «Все», иначе группа съедет в начало строки */
    .ka-pager { display: inline-flex; align-items: center; gap: 3px; margin-left: auto; }
    .kanban-attn:not(.one-page) .kanban-col-head .k-all { margin-left: 0; }
    .ka-pos { font-size: 11px; font-weight: 600; color: #8b95a5; white-space: nowrap; padding: 0 2px; }
    .ka-arrow {
      width: 20px; height: 20px; flex-shrink: 0; padding: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; border-radius: 5px; background: transparent; color: #6b7a8f;
      cursor: pointer; transition: background 0.12s, color 0.12s;
    }
    .ka-arrow:hover:not(:disabled) { background: #e2e6ee; color: #3d4655; }
    .ka-arrow:disabled { opacity: .3; cursor: default; }
    /* Точки-страницы под полосой */
    .ka-dots { display: flex; justify-content: center; gap: 6px; padding-top: 3px; }
    .ka-dot {
      width: 6px; height: 6px; padding: 0; border: none; border-radius: 50%;
      background: #c3cbd9; cursor: pointer; transition: background 0.12s;
    }
    .ka-dot:hover { background: #a7b1c2; }
    .ka-dot.active { background: #6b7a8f; }
    /* Всё влезло в одну страницу — листать нечего */
    .kanban-attn.one-page .ka-pager,
    .kanban-attn.one-page .ka-dots { display: none; }
    /* Список сигналов задачи: у одной задачи их может накопиться несколько */
    .kc-signals { list-style: none; display: flex; flex-direction: column; gap: 5px; }
    .kc-signal {
      display: flex; align-items: baseline; gap: 7px;
      font-size: 12px; line-height: 1.4; color: #3d4655;
    }
    .kc-signal .sig-dot {
      width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
      background: #8b95a5; transform: translateY(-1px);
    }
    .kc-signal.sig-danger .sig-dot { background: var(--red); }
    .kc-signal.sig-warn   .sig-dot { background: #f59e0b; }
    .kc-signal .sig-who { color: var(--text-muted); }

    .kanban-empty {
      display: flex; flex-direction: column; align-items: center; justify-content: center;
      gap: 8px; padding: 24px 12px;
      color: var(--text-muted); font-size: 12px;
      border: 1px dashed #d4d8e0; border-radius: 10px;
      background: rgba(255,255,255,.5);
    }

    /* Drag & Drop канбан-карточек */
    #my-tasks .kanban-card { cursor: grab; }
    #my-tasks .kanban-card:active { cursor: grabbing; }
    #my-tasks .kanban-card.dragging { opacity: .35; }
    #my-tasks .kanban-col.drag-over {
      outline: 2px dashed #3b82f6;
      outline-offset: -3px;
      background: #eaf1ff;
    }
    .kanban-card {
      background: #fff; border: 1px solid var(--border); border-radius: 10px;
      padding: 11px 12px; cursor: pointer; display: flex; flex-direction: column; gap: 8px;
      transition: border-color 0.15s, box-shadow 0.15s;
    }
    .kanban-card:hover { border-color: var(--border-mid); box-shadow: 0 2px 8px rgba(0,0,0,0.07); }
    .kanban-col.col-done .kanban-card { background: #fff; border-color: #e9edf3; }
    .kanban-card-top { display: flex; align-items: center; gap: 8px; }
    /* Вариант B: статус — пилюлей справа в верхней строке, прогресс, счётчик объектов */
    .kanban-card-top .kc-status { margin-left: auto; flex-shrink: 0; }
    .kanban-card-top .kc-skill { margin-left: auto; flex-shrink: 0; }
    /* Имя — первой строкой слева: ряд чипов своей строки не занимает,
       а висит в правом верхнем углу карточки; имя отступает, чтобы не
       заезжать под чип */
    .kanban-card { position: relative; }
    .kanban-card > .kanban-card-top { position: absolute; top: 11px; right: 12px; }
    .kanban-card:has(> .kanban-card-top) > .kanban-card-name { padding-right: 92px; min-height: 18px; }
    /* Выполненные — светлее остальных: содержимое приглушено, под курсором оживает */
    .kanban-col.col-done .kanban-card { opacity: .65; transition: opacity .15s; }
    .kanban-col.col-done .kanban-card:hover { opacity: 1; }
    .kc-progress { display: flex; align-items: center; gap: 8px; }
    .kc-bar { flex: 1; min-width: 0; height: 4px; border-radius: 20px; background: #e9edf3; overflow: hidden; }
    .kc-bar > i { display: block; height: 100%; background: var(--teal); border-radius: 20px; }
    .kc-bar.done > i   { background: #1f9d63; }
    .kc-bar.paused > i { background: #f0a04b; }
    .kc-bar.idle       { background: #eceef2; }
    .kc-prog-label { font-size: 11px; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }
    .kc-objs {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 11px; font-weight: 500; color: #6b7a8f;
    }
    .kc-objs svg { opacity: .7; flex-shrink: 0; }
    .kanban-card-name { font-size: 13px; font-weight: 500; color: var(--text-primary); line-height: 1.35; }
    .kanban-card-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
    /* Счётчик объектов выполнения — такой же чип, как даты и часы, и стоит сразу
       за трудоёмкостью: правый край строки отдан колокольчику нарушений */
    .kanban-card-chips .kc-objs {
      flex-shrink: 0;
      background: #eef0f4; color: #50607a;
      font-size: 10.5px; padding: 3px 8px; border-radius: 5px; line-height: 1;
    }
    /* Колокольчик: есть только у задач с нарушениями, по клику раскрывает их список */
    .kc-bell {
      margin-left: auto; flex-shrink: 0;
      display: inline-flex; align-items: center; gap: 4px;
      border: none; padding: 3px 7px; border-radius: 5px; cursor: pointer;
      background: #fceceb; color: #c23a35;
      font-size: 10.5px; font-weight: 600; line-height: 1;
      transition: background 0.12s, color 0.12s;
    }
    .kc-bell:hover { background: #f8dbd9; }
    .kanban-card.signals-open .kc-bell { background: #c23a35; color: #fff; }
    /* Список нарушений под именем задачи — та же вёрстка, что в «Требует решения» */
    .kanban-card .kc-signals-fold { display: none; }
    .kanban-card.signals-open .kc-signals-fold { display: flex; }
    .kanban-card-foot { display: flex; align-items: center; gap: 6px; margin-top: 1px; }
    .kanban-assignee {
      display: flex; align-items: center; gap: 6px; margin-left: auto;
      font-size: 11px; color: #8b95a5;
    }
    .kanban-ava {
      width: 20px; height: 20px; border-radius: 50%;
      background: linear-gradient(135deg,#2a4d7f,#4a6d9f);
      color: #fff; font-size: 9px; font-weight: 700;
      display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    }

    /* Status bar */
    .statusbar {
      background: transparent; box-shadow: none; border-radius: 0; padding: 0;
      margin: 0 21px 0 16px; flex-shrink: 0;
      display: grid; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); gap: 10px;
    }
    /* Футер со статусами виден только на вкладке «Выполнение» задачи */
    body:not(.sb-visible) .statusbar { display: none; }
    /* Внутри .flow-main-col футер уже ограничен колонкой контента, поэтому
       отступ под чат ему не нужен — хватает выравнивания по краям области.
       Раскладка ступенями 4 → 2 → 1, а не auto-fit: тот проходил через 3
       колонки, и четвёртая плитка одиноко висела на второй строке */
    .content > .flow-main-col { container-type: inline-size; container-name: maincol; }
    .flow-main-col .statusbar {
      margin: 0 24px; padding-top: 8px;
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
    @container maincol (max-width: 700px) {
      .flow-main-col .statusbar { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
    }
    @container maincol (max-width: 340px) {
      .flow-main-col .statusbar { grid-template-columns: 1fr; }
    }
    .stat-card {
      background: #fff; border: 1px solid var(--border); border-radius: 12px;
      padding: 10px 15px; box-shadow: 0 1px 3px rgba(0,0,0,0.05);
    }
    .stat-label { font-size: 11px; color: #93a4ba; font-weight: 500; margin-bottom: 3px; }
    .stat-value { font-size: 18px; font-weight: 700; color: #16345c; line-height: 1.1; white-space: nowrap; }
    .stat-value.danger { color: #d9534f; }
    .stat-sub { font-size: 10.5px; color: #a0abbb; margin-top: 5px; white-space: nowrap; }
    .stat-sub.up { color: #2ab46a; }
    .stat-sub.down { color: #d9534f; }

    /* Task view — segmented control */
    .seg-ctrl {
      display: inline-flex;
      background: rgba(5,28,59,0.07);
      border-radius: 12px; padding: 3px; gap: 2px;
      margin: 14px 24px 0;
    }
    .seg-tab {
      padding: 6px 20px; border-radius: 9px;
      font-size: 13px; font-weight: 500; color: var(--text-secondary);
      cursor: pointer; transition: all 0.18s; user-select: none;
    }
    .seg-tab:hover { color: var(--text-primary); }
    .seg-tab.active {
      background: #fff; color: var(--text-primary); font-weight: 600;
      box-shadow: 0 1px 4px rgba(5,28,59,0.10), 0 2px 8px rgba(5,28,59,0.06);
    }
    /* Task panels */
    .task-panel { display: none; }
    .task-panel.active { display: block; }
    /* Operations list (Выполнение) */
    .op-list { display: flex; flex-direction: column; gap: 0; padding-bottom: 18px; }
    .op-item {
      display: flex; align-items: center; gap: 12px;
      padding: 11px 0; border-bottom: 1px solid var(--border);
      font-size: 13px; color: var(--text-primary); cursor: pointer;
      transition: background 0.12s;
    }
    .op-item:last-child { border-bottom: none; }
    .op-item:hover { background: rgba(255,255,255,0.5); border-radius: 8px; padding-left: 8px; }
    .op-check {
      width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0;
      border: 2px solid #c5d2e4; background: #fff; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
    }
    .op-check.done { background: #0098a6; border-color: #0098a6; }
    .op-check.done::after {
      content: ''; display: block;
      width: 5px; height: 8px; border: 2px solid #fff;
      border-top: none; border-left: none; transform: rotate(45deg) translate(-1px,-1px);
    }
    .op-name { flex: 1; }
    .op-name.done { text-decoration: line-through; color: var(--text-muted); }
    .op-meta { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; }
    .op-assignee {
      width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
      background: linear-gradient(135deg,#7f93ab,#a8b8cc);
      display: flex; align-items: center; justify-content: center;
      color: #fff; font-size: 9px; font-weight: 700;
    }
    /* Project Данные — accordion fields */
    /* Боковые отступы равны верхнему отступу заголовка (9px): секция не липнет
       к краю колонки ни слева, ни справа */
    .proj-data-section {
      margin-bottom: 10px; padding: 0 9px;
    }
    /* Заголовок секции — как у списочных секций (.section-head/.sec-label) */
    .proj-data-section-head {
      display: flex; align-items: center; gap: 8px;
      min-height: 44px; box-sizing: border-box;
      padding: 9px 10px; margin-top: 4px; cursor: pointer; user-select: none;
      border-radius: var(--r); transition: background 0.15s;
      font-weight: 600; font-size: 13.5px; color: var(--text-primary);
    }
    .proj-data-section-head:hover { background: #f1f4f9; }
    /* ведущий шеврон — приглушённый, слева от текста, поворот при сворачивании */
    .proj-data-section-head > svg:first-child { color: var(--text-muted); flex-shrink: 0; transition: transform 0.2s; }
    /* свёрнутая секция — только заголовок, и он на подложке, как шапки групп
       на диаграмме: так свёрнутые секции не сливаются в список заголовков */
    .proj-data-section.collapsed > *:not(.proj-data-section-head) { display: none; }
    /* Заголовок секции отбит от первого поля — и в раскрытом виде тоже */
    .proj-data-section > .proj-data-section-head { margin-bottom: 12px; }
    /* Свёрнутая секция — без заливки, отбита линией снизу. Линия на самой секции,
       иначе подсветка заголовка при наведении доходила до неё вплотную */
    .proj-data-section.collapsed { border-bottom: 1px solid var(--border); }
    .proj-data-section.collapsed > .proj-data-section-head {
      background: transparent; border-bottom: none; margin-bottom: 12px;
    }
    .proj-data-section.collapsed > .proj-data-section-head:hover { background: #f1f4f9; }
    /* На подложке шапки счётчик со своей полупрозрачной заливкой растворялся —
       делаем его белёсым, как чипы на цветных строках */
    /* Заголовок свёрнутой секции теперь без заливки, поэтому белый чип на белом
       пропадал — оставляем ту же серую подложку, что и в раскрытом виде */
    .proj-data-section.collapsed > .proj-data-section-head :is(.ichip-skill, .ichip-role, .item-id),
    .section:not(.expanded) > .section-head :is(.ichip-skill, .ichip-role, .item-id) {
      background: rgba(255,255,255,.8);
    }
    /* строка-ссылка на объект «Инструкция» */
    .req-field { cursor: pointer; }
    .req-field .req-name { flex: 1; min-width: 0; font-size: 13px; color: var(--text-primary);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .req-field .req-arrow { color: #b2bac6; flex-shrink: 0; }
    .req-field:hover .req-arrow { color: #0098a6; }
    /* Чип типа прикреплённого объекта — справа, перед стрелкой */
    .req-type {
      flex-shrink: 0; margin-left: 8px;
      font-size: 11px; font-weight: 500; line-height: normal;
      padding: 2px 8px; border-radius: 5px; white-space: nowrap;
      background: #eef1f6; color: #6b7a8f;
    }
    .req-type[data-t="art"] { background: #e1f0ea; color: #2b7a58; }
    .req-type[data-t="ins"] { background: #eaf1f6; color: #3f6d84; }
    .req-type[data-t="res"] { background: #e0f0f2; color: #0e7883; }
    .req-type[data-t="file"] { background: #eef1f6; color: #6b7a8f; }
    /* Прикреплённый объект в «Параметры» — карточка как обычное поле:
       сверху имя объекта + тип справа, ниже зелёный чип-ссылка с кодом */
    /* align-items:center, а не baseline: у крестика нет текстовой базовой линии,
       и по baseline он вставал выше чипа источника */
    .src-field .src-head { display: flex; align-items: center; gap: 8px; width: 100%; }
    /* Имя параметра из сценария — тем же тоном, что подписи обычных полей */
    .src-field .src-name { flex: 1; min-width: 0; font-size: 13px; color: var(--text-body);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* У шаблонных параметров (без крестика) чип остаётся в первой строке —
       место свободно; у удаляемых он уехал во вторую, чтобы не спорить с крестиком */
    .src-head > .src-type { margin-left: auto; }
    /* Чип источника у удаляемых параметров — во второй строке, у правого края */
    .src-field > .proj-data-val { justify-content: space-between; width: 100%; }
    /* font-style: normal — у пустого значения курсив задан инлайном на строке,
       и чип наследовал его */
    .src-field > .proj-data-val > .src-type { margin-left: auto; font-style: normal; }
    /* Тип источника — чипом: показывает, откуда пришёл параметр, и ведёт к источнику */
    /* Источник параметра — служебная подпись, а не значение: на белой карточке
       плотный чип #e2e7ef перетягивал внимание. Оставляем лёгкую заливку
       и приглушённый текст, вес обычный */
    .src-field .src-type {
      flex-shrink: 0; font-size: 11px; font-weight: 400; color: #7b8699;
      background: #e9edf4; border-radius: 5px; padding: 2px 8px; white-space: nowrap;
    }
    /* Курсор и подсветка — только у чипов со ссылкой, чтобы обычные не выглядели кликабельными */
    .src-field .src-type[onclick] { cursor: pointer; transition: background .12s, color .12s; }
    .src-field .src-type[onclick]:hover { background: #dde3ee; color: #55647f; }
    .proj-data-pill.pill-link {
      cursor: pointer; display: inline-flex; align-items: center; gap: 5px; max-width: 100%;
      transition: background 0.12s;
    }
    .proj-data-pill.pill-link:hover { background: #d5eff1; }
    /* Длинное имя хранилища переносится по строкам, а не обрезается многоточием:
       в карточке важнее прочитать значение целиком, места по высоте хватает */
    .proj-data-pill.pill-link .pl-val { white-space: normal; overflow-wrap: anywhere; min-width: 0; }
    /* Обрезка выше не срабатывала: у flex-элементов по цепочке до чипа минимум
       равен min-content, поэтому чип не сжимался, а распирал карточку.
       min-width: 0 разрешает сжатие — и текст наконец уходит в «…» */
    .proj-data-pills { min-width: 0; }
    .proj-data-pills > .proj-data-pill { min-width: 0; }
    .field-row { min-width: 0; max-width: 100%; }
    .field-row > .cs-wrap { min-width: 0; }
    .proj-data-pill.pill-link .pill-chev { flex-shrink: 0; opacity: 0.7; }
    .proj-data-field {
      display: flex; align-items: center;
      min-height: 40px; box-sizing: border-box;
      padding: 9px 16px; gap: 12px; margin-bottom: 6px;
      font-size: 13px; transition: box-shadow 0.15s;
      background: #fff; border-radius: 12px;
      /* Тень как у сайдбара: мягкое падение плюс тонкая обводка вместо
         двухслойного размытого свечения — карточки читаются как один материал */
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
    }
    .proj-data-field:hover { box-shadow: 0 2px 4px rgba(5,28,59,0.07), 0 6px 20px rgba(5,28,59,0.08); }
    .proj-data-label {
      /* Тот же цвет, что у текста «Описания» (#3b4a5e): подписи полей — такой же
         содержательный текст, а --text-primary делал их заметно чернее описания */
      color: var(--text-body); font-size: 13px; font-weight: 400;
      /* сжимается до самого длинного слова и переносится по словам,
         min-width: auto не даёт разорвать слово */
      flex-shrink: 1;
    }
    /* Подсказка вместо значения («Заполните значение») — тонкая и курсивом,
       чтобы не читалась как заполненное поле */
    /* Подсказка — служебный текст, поэтому мельче значения */
    .val-hint { color: var(--text-muted); font-style: italic; font-weight: 300; font-size: 12px; -webkit-font-smoothing: antialiased; }
    /* Красным подсказка горит только там, где значение реально ждут от исполнителя:
       параметр из сценария и поле-заполнение результата. В редакторе параметра
       (там есть чип ограничений и крестик) это просто описание поля */
    /* Бледный красный: это подсказка «здесь ждут значение», а не сообщение
       об ошибке — плотный красный читался как ругань формы */
    .proj-data-field.src-field > .val-hint,
    .proj-data-field.value-only > .val-hint { color: #e0a5a2; }
    .proj-data-val { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-left: auto; justify-content: flex-end; min-width: 0; }
    /* align-items:center — кнопки скрепки и плюса (17px) ниже значений (20px) и без
       этого вставали бы по верхнему краю строки, а не по её середине */
    .proj-data-pills { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; justify-content: flex-end; }
    /* «Кем управляется»: строки как у мультиполей — значение, справа крестик,
       у последней строки «+» открывает список. Своя система координат нужна
       выпадайке до её выноса в body */
    .who-pick { position: relative; }
    .who-picks > .field-row { justify-content: flex-end; }
    /* Скруглённый прямоугольник, а не пилюля: значение переносится по строкам, и
       на высоком чипе полукруглые торцы выглядели раздутыми */
    .proj-data-pill {
      background: #e7f6f7; color: #00727d; border-radius: 6px;
      padding: 3px 11px; font-size: 11.5px; font-weight: 500;
    }
    /* Значение — ссылка на хранилище или результат работы: другого значения у такого параметра
       не бывает, поэтому прикрепление и добавление там ни к чему. Само поле
       по-прежнему удаляется крестиком в строке названия */
    .proj-data-field:has(.proj-data-pill.pill-link) .pd-tools { display: none; }
    /* Иконка типа значения (файл, картинка) стоит по базовой линии текста, а не
       по верхнему краю строки — иначе она заметно выше подписи */
    .proj-data-pill > svg,
    .pill-val > svg { vertical-align: -1.5px; }
    /* Крестик внутри значения — убрать его из списка */
    .proj-data-pill.has-x { display: inline-flex; align-items: center; gap: 4px; padding-right: 5px; }
    /* Длинное значение переносится по строкам внутри пилюли, а не вылезает за
       карточку — одинаково у обычных значений и у ссылок на хранилище/результат работы */
    .proj-data-pill { max-width: 100%; min-width: 0; white-space: normal; }
    .proj-data-pill > .pill-val,
    .proj-data-pill.has-x > .pill-val { min-width: 0; overflow-wrap: anywhere; }
    /* Многострочное значение: крестик держим у первой строки, чтобы он
       не уезжал в середину высокой пилюли */
    .proj-data-pill.has-x { align-items: flex-start; }
    .proj-data-pill.has-x > .pill-x { margin-top: 1px; }
    /* Шеврон у значения-ссылки не рисуем: сама пилюля кликабельна и ведёт на объект */
    .proj-data-pill > .pill-chev { display: none; }
    /* Крестик по центру строки: при flex-start он прижимался к верху пилюли и
       у значений с иконкой заметно уезжал выше подписи */
    .pill-x { flex-shrink: 0; align-self: center; }
    .pill-x {
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; color: inherit; cursor: pointer;
      padding: 2px; border-radius: 50%; opacity: .6;
    }
    .pill-x:hover { opacity: 1; background: rgba(0,0,0,.08); }
    /* Пилюля-дата открывает календарь по клику */
    .proj-data-pill.date-pill { cursor: pointer; transition: background 0.12s; }
    .proj-data-pill.date-pill:hover { background: #d5eff1; }
    /* Кнопка удаления поля */
    .proj-data-del {
      margin-left: 8px; flex-shrink: 0;
      background: none; border: none; cursor: pointer;
      color: var(--text-muted);
      display: flex; align-items: center;
      padding: 2px; border-radius: 4px;
      transition: color 0.15s;
    }
    .proj-data-del:hover { color: #d9534f; }
    /* Навык без чипа специальности — одна строка: крестик прижат к правому краю,
       как чип у унаследованных навыков */
    #memberSkills .proj-data-field > .proj-data-del { margin-left: auto; }

    /* Строка инструкции: код чипом, имя, справа шеврон-переход и крестик */
    /* Чип кода — точно как .proj-id в заголовке страницы (те же размеры и тона) */
    .src-code {
      flex-shrink: 0; font-size: 11.5px; font-weight: 500; color: #6b7a8f;
      background: rgba(15,30,60,.05); border-radius: 4px; padding: 3px 9px; white-space: nowrap;
    }
    /* Шеврон стоит сразу за именем — так он читается как «открыть это»,
       а не как отдельная кнопка у правого края. Кликабельна вся строка */
    .instr-row { cursor: pointer; }
    .instr-chev { flex-shrink: 0; color: var(--text-muted); transition: color .15s; }
    .instr-row:hover .instr-chev { color: #0098a6; }
    /* Тот же шеврон у имени вызванного сценария в списке задач */
    .item-name > .instr-chev { cursor: pointer; }
    .item-name > .instr-chev:hover { color: #0098a6; }
    .instr-row > .proj-data-del { margin-left: auto; }
    /* Чип «Связанная» — у правого края, оформление как у чипа источника параметра.
       Крестик встаёт после него, поэтому auto-отступ переходит к чипу */
    .instr-row > .src-type {
      margin-left: auto; flex-shrink: 0; white-space: nowrap;
      font-size: 11px; font-weight: 400; color: #7b8699;
      background: #e9edf4; border-radius: 5px; padding: 2px 8px;
    }
    .instr-row:has(> .src-type) > .proj-data-del { margin-left: 8px; }

    /* Кнопка добавления значения в поле */
    .proj-data-add {
      margin-left: 8px; flex-shrink: 0;
      background: none; border: none; cursor: pointer;
      color: #0098a6;
      display: flex; align-items: center;
      padding: 2px; border-radius: 4px;
      transition: color 0.15s, background 0.12s;
    }
    .proj-data-add:hover { color: #00838f; background: rgba(0,152,166,0.1); }
    /* Строка значения, оканчивающаяся кнопкой (+ или ×).
       Кнопка внутри строки, а не карточки, — иначе к её отступу
       добавился бы gap карточки и значения встали бы левее. */
    .field-row { display: inline-flex; align-items: center; }
    /* Значения — колонкой; строки кончаются кнопкой,
       поэтому плюс и крестики выстраиваются в один столбец справа */
    .multi-list { flex-direction: column; align-items: flex-end; flex-wrap: nowrap; }
    /* Мульти-поле в две части: строка «имя + крестик удаления поля», значения ниже */
    .proj-data-field.mf-stacked { flex-direction: column; align-items: stretch; gap: 8px; }
    .mf-head-row { display: flex; align-items: center; gap: 8px; }
    .mf-head-row .proj-data-del,
    .mf-head-row .multi-head { margin-left: auto; }
    .proj-data-field.mf-stacked .multi-list { width: 100%; }
    /* Шапка мульти-поля (режим выполнения + «+») видна только при 2+ значениях.
       Одно значение: крестик спрятан, «+» стоит на его месте в строке.
       Состояние «не выбрано» (.mf-none) прячет все «+». */
    .multi-head { display: none; align-items: center; justify-content: flex-end; gap: 4px; }
    .multi-field:has(.multi-extra) .multi-head { display: flex; }
    .multi-field:not(:has(.multi-extra)) .field-row .proj-data-del { display: none; }
    .multi-field:has(.multi-extra) .mf-inline-add { display: none; }
    .multi-field.mf-none .proj-data-add { display: none; }
    /* «Кто управляет»: «Владелец» — обычное значение по умолчанию, а не «не выбрано»,
       поэтому «+» рядом с ним остаётся доступным */
    .multi-field[data-multi="manager"].mf-none .proj-data-add { display: inline-flex; }
    .multi-field[data-multi="manager"].mf-none:has(.multi-extra) .mf-inline-add { display: none; }
    /* Удаляемое двухстрочное поле («Начать после»): «+» всегда сверху,
       на строке всегда крестик — иначе, дойдя до одной задачи, поле уже не убрать.
       Переключатель режима при одной задаче не нужен. */
    .multi-field.mf-stacked .multi-head { display: flex; }
    .multi-field.mf-stacked:not(:has(.multi-extra)) .multi-mode { display: none; }
    .multi-field.mf-stacked .mf-inline-add { display: none; }
    .multi-field.mf-stacked .field-row .proj-data-del { display: inline-flex; }
    /* Порядок значений важен в режиме «последовательно», поэтому строки можно
       перетаскивать за ручку слева. Ручка появляется только при 2+ значениях */
    .mf-grip { display: none; align-items: center; padding: 0 1px; margin-right: 2px;
      color: var(--text-muted); cursor: grab; flex-shrink: 0; }
    .mf-grip:active { cursor: grabbing; }
    .multi-field:has(.multi-extra) .field-row > .mf-grip { display: inline-flex; }
    .field-row.mf-dragging { opacity: .45; }
    .field-row.mf-drop-before { box-shadow: 0 -2px 0 -1px var(--teal); }
    .field-row.mf-drop-after  { box-shadow: 0 2px 0 -1px var(--teal); }
    .multi-mode {
      display: inline-flex; align-items: center; gap: 5px;
      cursor: pointer; color: #0098a6; font-size: 11px; font-weight: 500;
      padding: 2px 5px; border-radius: 4px;
      transition: background 0.12s;
    }
    .multi-mode:hover { background: #e7f6f7; }
    .multi-field[data-mode="par"] .mm-seq { display: none; }
    .multi-field[data-mode="seq"] .mm-par { display: none; }

    /* Кнопка-пилюля в строке значений (например «Согласовать») */
    .pill-btn {
      border: none; cursor: pointer; flex-shrink: 0;
      background: #0098a6; color: #fff;
      font-size: 11px; font-weight: 500;
      padding: 6px 14px; border-radius: 20px;
      transition: background 0.12s;
    }
    .pill-btn:hover { background: #00838f; }
    /* «Согласовать» — под самим полем ввода, а не рядом с ним: строка значения
       раскладывается столбиком, обе части остаются у правого края */
    .proj-data-val:has(> .pill-btn) {
      flex-direction: column; align-items: flex-end; gap: 6px;
    }
    /* Остаток согласовывают только когда прогноз (затрачено + осталось) вышел
       за план: класс .over на поле остатка ставит hoursOverSync по тому же
       условию, поэтому кнопке хватает его */
    .proj-data-val:has(.hours-left:not(.over)) > .pill-btn { display: none; }
    /* В слитом блоке «Описание и вложения» текст отбит от параметров тем же
       зазором, что стоит между самими параметрами (.proj-data-field: 6px) */
    .vibe-desc:has(+ .stack-fields) { margin-bottom: 6px; }
    /* Описание в секции ленты отбито от её заголовка: и внешним отступом,
       и собственным полем — иначе текст-подсказка липнет к строке названия */
    body .vibe-feed .section-body > .desc-ph.vibe-desc {
      margin-top: 8px; margin-bottom: 8px; padding-top: 8px; padding-bottom: 8px;
    }
    /* Линия-разделитель внутри слитого блока: требуемый результат отчёркнут
       от параметров ниже */
    .field-sep { height: 1px; background: var(--border); margin: 8px 2px; }
    /* Строки «Проблем» создаёт сервис — вместо чекбокса значок предупреждения */
    .problem-ico {
      display: inline-flex; align-items: center; justify-content: center;
      flex-shrink: 0; color: #c23a35;
    }
    /* Секция с проблемами названа в цвет самих проблем: красным читается
       сразу, ещё до строк. Ищем по содержимому — отдельного класса у секции
       нет, а проблемы всюду помечены значком */
    .section:has(.problem-ico) > .section-head > .sec-label { color: #c23a35; }
    /* «Решено» на невыполненных пунктах — видна только при наведении на строку */
    .row-resolve { display: none; margin-left: auto; padding: 4px 12px; }
    .item-row:not(.done):hover > .row-resolve { display: inline-flex; }
    /* Решённый пункт помечен чипом; клик по нему возвращает пункт в работу */
    .row-done-chip { display: none; margin-left: auto; cursor: pointer; }
    .item-row.done > .row-done-chip { display: inline-flex; }
    /* Высота строк чек-листов с запасом под кнопку — при наведении не скачет */
    #task-exec .items-list .item-row,
    .vibe-colx .items-list .item-row { min-height: 40px; box-sizing: border-box; }

    /* Поле-пилюля с выбором значения */
    .data-select {
      appearance: none; -webkit-appearance: none;
      background-color: #e7f6f7; color: #00727d;
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%2300727d' stroke-width='2.5' viewBox='0 0 24 24'><polyline points='6 9 12 15 18 9'/></svg>");
      background-repeat: no-repeat; background-position: right 9px center; background-size: 9px;
      border: 1px solid transparent; border-radius: 20px;
      padding: 3px 25px 3px 11px;
      font-size: 11.5px; font-weight: 500; font-family: inherit;
      cursor: pointer; outline: none;
      min-width: 0; max-width: 100%; text-overflow: ellipsis;
      transition: border-color 0.12s;
    }
    .data-select:hover { border-color: #9fd8dd; }
    .data-select:focus { border-color: #0098a6; }

    /* Кастомный выпадающий список поля — вид как у фильтров тулбара.
       Нативный <select> спрятан, но остаётся источником значения и onchange. */
    .cs-wrap { position: relative; display: inline-flex; max-width: 100%; vertical-align: middle; }
    .cs-wrap > select.data-select { position: absolute; width: 1px; height: 1px; padding: 0; opacity: 0; pointer-events: none; }
    .cs-trigger { max-width: 100%; text-align: left; }
    .cs-trigger .cs-val { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .cs-wrap.open .cs-trigger { border-color: #0098a6; }
    .cs-dd { top: calc(100% + 5px); left: 0; right: auto; width: max-content; min-width: 100%; max-width: 260px; }
    .cs-wrap.open .cs-dd { display: flex; }
    .cs-opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 10px; }
    .cs-opt > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .cs-check { display: none; flex-shrink: 0; }
    .cs-opt.selected { color: #0098a6; font-weight: 600; background: #e7f6f7; }
    .cs-opt.selected .cs-check { display: block; }

    /* Страница «Триггеры»: условие → действие */
    .trg-cond {
      flex-shrink: 0; max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      font-size: 12px; color: #5c6b80; background: #eef1f6; border-radius: 6px; padding: 3px 9px;
    }
    .trg-arrow { color: #9aa6b6; margin: 0 3px 0 1px; }
    #viewTriggers .item-name { color: var(--text-secondary); }
    #viewTriggers .item-name b { color: var(--text-primary); font-weight: 600; }
    .ichip.trg-on { background: #e1f5ee; color: #0f6e56; }
    .ichip.trg-off { background: #eef1f6; color: #8a94a6; }
    .trg-run {
      display: inline-flex; align-items: center; gap: 5px;
      padding: 3px 10px 3px 8px; border-radius: 6px;
      border: 1px solid #9fe1cb; background: #e1f5ee; color: #0f6e56;
      font-size: 11.5px; font-weight: 600; font-family: inherit; cursor: pointer;
      transition: background .12s;
    }
    .trg-run:hover { background: #d0efe2; }
    .trg-run svg { flex-shrink: 0; }

    /* Редактируемое числовое поле (в том же стиле пилюли) */
    .data-input {
      width: 66px; text-align: right;
      background-color: #e7f6f7; color: #00727d;
      border: 1px solid transparent; border-radius: 20px;
      padding: 3px 11px; font-size: 11.5px; font-weight: 500; font-family: inherit;
      outline: none; transition: border-color 0.12s, background 0.12s;
    }
    .data-input:hover { border-color: #9fd8dd; }
    .data-input:focus { border-color: #0098a6; background: #fff; }
    .data-input::-webkit-inner-spin-button,
    .data-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

    /* Приписка «план» у значения поля */
    .plan-note { font-size: 11.5px; color: #8a94a6; white-space: nowrap; }

    /* Блок «только чтение»: данные пришли из другой сущности (у работы —
       из задачи). Ссылки на источники работают, правки — спрятаны */
    .ro-block .sec-expand,
    .ro-block .proj-data-del,
    .ro-block .pd-tools,
    .ro-block .tag-add,
    .ro-block .tag-chip > .x { display: none; }
    .ro-block :is(.proj-data-label, .proj-data-val.val-hint) { cursor: default; }
    /* Крестика в значениях там нет (syncPillX его не ставит) — возвращаем
       пилюле обычное правое поле, ужатое под кнопку */
    .ro-block .proj-data-pill.has-x { padding-right: 11px; }
    .ro-block :is(.data-input, .data-select, .cs-wrap) { pointer-events: none; }

    /* Секции исполнения — правая колонка вкладки «Выполнение» */
    .exec-role-area { min-width: 0; }
    /* readonly-поля (без select/input) — серые чипы значений. Часы правятся
       попапом, поля ввода в строке нет — но чип там редактируемый, цианом */
    #exec-roles .proj-data-field:not(:has(.data-select, .data-input, .hours-pill)) .proj-data-pill {
      background: #e3e6ee; color: #5a6b86;
    }

    /* Значения не влезли рядом с названием — параметр сам встаёт в две строки:
       название с крестиком, значения ниже (замер — fitDataField в app.js) */
    .proj-data-field.auto-stacked { flex-direction: column; align-items: stretch; gap: 6px; position: relative; }
    .proj-data-field.auto-stacked > .proj-data-del { position: absolute; top: 8px; right: 12px; margin: 0; }
    
    .proj-data-field.auto-stacked > .proj-data-val,
    .proj-data-field.auto-stacked > .proj-data-val > .proj-data-pills { justify-content: flex-start; }
    /* Инструменты параметра: «прикрепить» и «плюс». Без значений — в первой строке
       слева от крестика, со значениями — в общем ряду за последней пилюлей */
    .pd-tools { display: inline-flex; align-items: center; gap: 2px; }
    /* Инструменты и крестик показываем только под курсором: в покое параметр
       читается именем и значением, а ряд иконок у каждого поля рябил.
       Гасим прозрачностью, а не display — иначе строка прыгала бы по ширине.
       :focus-within оставляет их доступными с клавиатуры */
    /* Крестик ищем на любой глубине: у параметра-источника он лежит внутри
       .src-head, и прямой потомок его не ловил */
    .proj-data-field .pd-tools,
    .proj-data-field .proj-data-del { opacity: 0; transition: opacity .12s; }
    .proj-data-field:hover .pd-tools,
    .proj-data-field:focus-within .pd-tools,
    .proj-data-field:hover .proj-data-del,
    .proj-data-field:focus-within .proj-data-del { opacity: 1; }
    /* В строке значения (в том числе когда там только подсказка) — у правого края,
       так что «плюс» встаёт точно под крестиком строки названия */
    .proj-data-val:has(> .pd-tools) { display: flex; align-items: center; }
    .proj-data-val > .pd-tools,
    .proj-data-pills > .pd-tools { margin-left: auto; margin-right: -4px; }
    /* Контейнер значений тянем на всю строку — иначе margin-left: auto некуда двигать
       и кнопки липнут к последней пилюле вместо правого края */
    .proj-data-val > .proj-data-pills:has(> .pd-tools) { flex: 1; }
    /* Вплотную к крестику, на его же строке (top: 8px — как у самого крестика) */
    .proj-data-field.field-stacked > .pd-tools,
    .proj-data-field.auto-stacked > .pd-tools { position: absolute; top: 8px; right: 32px; }
    /* Значений нет — крестик по центру карточки, инструменты едут за ним */
    .proj-data-field.field-stacked:not(:has(> .proj-data-val)) > .pd-tools,
    .proj-data-field.auto-stacked:not(:has(> .proj-data-val)) > .pd-tools {
      top: 50%; transform: translateY(-50%);
    }
    /* Оформление как у «+» в мультиполях: тот же циан и та же подсветка */
    .pd-tool {
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; cursor: pointer; color: #0098a6;
      padding: 2px; border-radius: 4px; transition: color .15s, background .12s;
    }
    .pd-tool:hover { color: #00838f; background: rgba(0,152,166,0.1); }
    /* Обязательный параметр помечен звёздочкой в конце имени */
    .proj-data-field.lim-req > .proj-data-label::after,
    /* У параметра из источника имя лежит в .src-head — звёздочку ставим там же */
    .proj-data-field.lim-req > .src-head > .src-name::after { content: ' *'; color: #d9534f; }
    /* Чип ограничений результата: проявляется по наведению на итем, а если настройки
       отличаются от значений по умолчанию — виден всегда */
    /* Геометрия — как у чипа источника (.src-type): та же плашка со скруглением 5px,
       отличается только цветом */
    .lim-chip {
      display: none; position: absolute; top: 8px; right: 34px;
      border: none; background: rgba(15,30,60,.04); color: #9aa7bf;
      font-family: inherit; font-size: 11px; font-weight: 400;
      padding: 2px 8px; border-radius: 5px; white-space: nowrap; cursor: pointer;
    }
    .proj-data-field:hover > .lim-chip,
    .proj-data-field.lim-open > .lim-chip,
    .proj-data-field.lim-set > .lim-chip { display: inline-flex; }
    /* Пока открыт попап настроек, чип выглядит нажатым */
    .proj-data-field.lim-open > .lim-chip { background: rgba(15,30,60,.13); color: var(--text-primary); }
    /* Ограничения назначены — чип виден всегда и красится как значение параметра
       (.proj-data-pill): назначенное в карточке везде бирюзовое */
    .proj-data-field.lim-set > .lim-chip { background: #e7f6f7; color: #00727d; }
    .proj-data-field.lim-set > .lim-chip:hover { background: #d6eff1; color: #005b64; }
    .lim-chip:hover { background: rgba(15,30,60,.13); color: var(--text-primary); }
    /* Входной параметр сценария: чип не прячется по наведению — он не кнопка
       «настроить», а роль самого поля, и красится как назначенное значение */
    .proj-data-field.in-param > .lim-chip { display: inline-flex; background: #e7f6f7; color: #00727d; }
    .proj-data-field.in-param > .lim-chip:hover { background: #d6eff1; color: #005b64; }
    .lim-pop {
      position: fixed; z-index: 900;
      display: flex; flex-direction: column; gap: 8px; min-width: 280px;
      background: #fff; border: 1px solid var(--border); border-radius: 10px;
      padding: 10px 12px; box-shadow: 0 18px 44px rgba(10,18,32,.20);
    }
    .lim-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 12.5px; color: var(--text-secondary); }
    .lim-row .cs-wrap { flex-shrink: 0; }
    /* В «Требуемых результатах» и у входных параметров сценария это не основное
       действие — кнопки нейтральные */
    .res-section .pd-tool,
    .proj-data-field.in-param .pd-tool { color: var(--text-muted); }
    .res-section .pd-tool:hover,
    .proj-data-field.in-param .pd-tool:hover { color: var(--text-primary); background: #eef1f6; }
    /* Значение убрали — осталось одно название: держим его и крестик по центру карточки */
    .proj-data-field.field-stacked:not(:has(> .proj-data-val)),
    .proj-data-field.auto-stacked:not(:has(> .proj-data-val)) { justify-content: center; }
    .proj-data-field.field-stacked:not(:has(> .proj-data-val)) > .proj-data-del,
    .proj-data-field.auto-stacked:not(:has(> .proj-data-val)) > .proj-data-del {
      top: 50%; transform: translateY(-50%);
    }
    /* Значение-картинка открывает превью, текстовое — правится на месте */
    .proj-data-pill.pill-img { cursor: zoom-in; }
    .proj-data-pill.has-x:not(.pill-link):not(.pill-img) > .pill-val { cursor: text; }
    .pill-val.name-edit { outline: none; background: #fff; border-radius: 4px; padding: 0 2px; box-shadow: 0 0 0 1px var(--purple-mid, #9aa7bf); }
    .img-prev {
      position: fixed; inset: 0; z-index: 900; display: flex; align-items: center; justify-content: center;
      background: rgba(10,18,32,.55);
    }
    .img-prev-card {
      position: relative; background: #fff; border-radius: 12px; padding: 18px;
      box-shadow: 0 28px 80px rgba(10,18,32,.45); max-width: 420px;
    }
    .img-prev-frame {
      width: 340px; height: 200px; border-radius: 8px; background: #f1f4f9;
      display: flex; align-items: center; justify-content: center; color: #9aa7bf;
    }
    .img-prev-cap { margin-top: 10px; font-size: 13px; color: var(--text-secondary); text-align: center; }
    .img-prev-x {
      position: absolute; top: 8px; right: 8px; border: none; background: none; cursor: pointer;
      color: var(--text-muted); padding: 4px; border-radius: 6px;
    }
    .img-prev-x:hover { background: #f1f4f9; color: var(--text-primary); }

    /* Длинная подпись — в столбик: подпись сверху, значения снизу */
    .proj-data-field.field-stacked { flex-direction: column; align-items: stretch; gap: 6px; position: relative; }
    /* В колоночной раскладке крестик как обычный ребёнок уезжал под значения —
       поднимаем его на первую строку, к правому краю */
    .proj-data-field.field-stacked > .proj-data-del { position: absolute; top: 8px; right: 12px; margin: 0; }
    /* Крестик вынут из потока — оставляем под него место, иначе длинное название
       параметра заезжает прямо на него */
    .proj-data-field.field-stacked:has(> .proj-data-del) > .src-head { padding-right: 22px; }
    /* Подсветка правки должна обводить только текст имени, поэтому место под
       крестик и кнопки держим внешним отступом, а не паддингом внутри метки */
    .proj-data-field.field-stacked > .proj-data-label,
    .proj-data-field.auto-stacked > .proj-data-label { align-self: flex-start; width: max-content; max-width: 100%; }
    .proj-data-field.field-stacked:has(> .proj-data-del) > .proj-data-label,
    .proj-data-field.auto-stacked:has(> .proj-data-del) > .proj-data-label { margin-right: 22px; }
    .proj-data-field.field-stacked:has(> .pd-tools) > .proj-data-label,
    .proj-data-field.auto-stacked:has(> .pd-tools) > .proj-data-label { margin-right: 76px; }
    .proj-data-label.name-edit { width: auto; }
    /* У параметра нет имени — пустую строку названия не держим, значения встают
       на её место. Кликнуть по названию всё ещё можно: строка появится в правке */
    .proj-data-field.no-name > .proj-data-label { display: none; }
    /* Пока имя вводят, строка названия нужна: иначе в неё некуда поставить курсор */
    .proj-data-field.no-name.name-editing > .proj-data-label { display: block; min-width: 120px; }
    /* На этой же строке справа стоит крестик удаления (он вне потока) — отводим
       ему место, иначе скрепка с плюсом заезжают прямо под него */
    /* Селектор не через `>`: при непустом списке значений кнопки лежат внутри
       .proj-data-pills, а не прямо в строке значения */
    .proj-data-field.no-name .pd-tools { margin-right: 20px; }
    /* Крестик удаления рассчитан на строку названия и стоит на top:8px. Имени нет —
       ровняем его по первой строке значений: она начинается от внутреннего отступа
       поля (9px), высота строки — 20px, кнопка центрирует иконку сама */
    .proj-data-field.field-stacked.no-name > .proj-data-del { top: 9px; height: 20px; }
    .proj-data-field.field-stacked .proj-data-val { margin-left: 0; justify-content: flex-start; }
    .proj-data-field.field-stacked .proj-data-pills { justify-content: flex-start; }
    /* Входной параметр: чип роли стоит в потоке рядом с названием и переносится под
       него, когда не влезает, — абсолютным он наезжал на длинные названия. Порядок
       задаём стилями: в разметке строка-подсказка идёт между названием и чипом и
       разрывала бы их на разные строки. Правила ниже правил .field-stacked —
       специфичность та же, побеждает порядок */
    .proj-data-field.field-stacked.in-param { flex-flow: row wrap; align-items: center; column-gap: 8px; }
    .proj-data-field.field-stacked.in-param > .proj-data-label { margin-right: 0; order: 1; }
    /* margin-left:auto — чип уезжает к правому краю, вплотную к крестику удаления */
    .proj-data-field.field-stacked.in-param > .lim-chip { position: static; margin-left: auto; margin-right: 22px; order: 2; }
    .proj-data-field.field-stacked.in-param > .proj-data-val { flex: 1 1 100%; order: 3; }

    .task-grid { display: flex; gap: 18px; align-items: stretch; padding-bottom: 18px; }
    .task-card {
      background: #fff; border: none; border-radius: 16px;
      box-shadow: 0 1px 2px rgba(5,28,59,0.04), 0 6px 24px rgba(5,28,59,0.05);
      display: flex; flex-direction: column; min-height: 420px;
      overflow: hidden;
    }
    .task-card.tcl { flex: 1.3; }
    .task-card.tcr { flex: 1; }
    .tc-head {
      padding: 18px 20px 6px; font-weight: 700; font-size: 13.5px;
      color: var(--text-primary); display: flex; align-items: center; gap: 8px;
    }
    .tc-body { padding: 10px 20px 16px; font-size: 13px; color: #3b4a5e; line-height: 1.65; flex: 1; }
    .tc-foot {
      padding: 12px 20px 16px;
      display: flex; align-items: center; gap: 10px; font-size: 12px; color: var(--text-secondary);
    }
    /* Строка тегов — часть секции «Описание»: раскладка в классе, а не инлайном,
       иначе display:flex перебивал скрытие содержимого свёрнутой секции */
    .tag-row { display: flex; gap: 8px; flex-wrap: wrap; padding: 8px 4px 16px; }
    .tag-chip {
      display: inline-flex; align-items: center; gap: 7px;
      background: #eef1f6; border: none;
      border-radius: 20px; padding: 5px 13px; font-size: 12px; font-weight: 500; color: #3b4a5e;
      cursor: pointer; transition: background 0.15s;
    }
    .tag-chip:hover { background: #e4e9f0; }
    .tag-chip .x { color: var(--text-muted); cursor: pointer; }
    .tag-chip .x:hover { color: var(--red); }
    /* Кружок «+» — добавить новый тег */
    .tag-add {
      width: 25px; height: 25px; border-radius: 50%; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      background: #eef1f6; border: none; padding: 0;
      color: #6b7a8f; cursor: pointer;
      transition: background 0.15s, color 0.15s;
    }
    .tag-add:hover { background: #e4e9f0; color: #0098a6; }
    /* Ввод нового тега: та же механика, что у правки заголовка (Enter — применить,
       Esc — отмена, клик вне поля без изменений закрывает), но без кнопок
       «Применить/Отмена» и формой под чипы — круглое поле */
    .tag-edit { display: none; position: relative; align-items: center; }
    .tag-edit.open { display: inline-flex; }
    .tag-edit-input {
      width: var(--tag-edit-w, 33%); min-width: 120px; max-width: 100%;
      height: 25px; padding: 0 26px 0 13px;
      background: #fff; border: 1px solid var(--border-mid); border-radius: 20px;
      font-size: 12px; font-weight: 500; color: #3b4a5e; font-family: inherit;
    }
    .tag-edit-input:focus { outline: none; border-color: #0098a6; }
    .tag-edit-input::placeholder { color: #b9c2d0; }
    .tag-edit-clear {
      position: absolute; right: 6px; width: 16px; height: 16px; padding: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; border-radius: 50%; background: none;
      color: var(--text-muted); font-size: 14px; line-height: 1; cursor: pointer;
    }
    .tag-edit-clear:hover { color: var(--red); }
    /* Пока вводят тег, «+» не нужен — он же и открывает поле */
    .tag-edit.open + .tag-add { display: none; }
    /* Список похожих тегов под полем */
    .tag-dd {
      display: none; position: absolute; top: calc(100% + 5px); left: 0; z-index: 60;
      min-width: 100%; max-height: 232px; overflow-y: auto;
      padding: 5px; background: var(--card); border: 1px solid var(--border);
      border-radius: 10px; box-shadow: 0 10px 28px rgba(15,30,60,.13);
    }
    .tag-dd.show { display: block; }
    /* Нет места снизу — открываемся вверх (см. tagDdFlip) */
    .tag-dd.up { top: auto; bottom: calc(100% + 5px); }
    .tag-dd-item, .tag-dd-new, .tag-dd-empty {
      padding: 6px 10px; border-radius: 6px; font-size: 12px; white-space: nowrap;
      color: var(--text-body);
    }
    .tag-dd-item, .tag-dd-new { cursor: pointer; }
    .tag-dd-item:hover, .tag-dd-new:hover { background: #f1f4f9; color: var(--text-primary); }
    .tag-dd-new { color: #0f6e56; font-weight: 500; }   /* создание нового — акцентом */
    .tag-dd-empty { color: var(--text-muted); cursor: default; }

    .param-section {
      margin: 2px 8px; padding: 9px 12px; border-radius: var(--r);
      display: flex; align-items: center; gap: 8px;
      font-weight: 600; font-size: 13.5px; color: var(--text-primary);
      cursor: pointer; user-select: none; transition: all 0.15s;
    }
    .param-section:hover { background: #f1f4f9; }
    .param-icon-btn {
      width: 26px; height: 26px; border-radius: 5px;
      border: 1px solid transparent; background: transparent;
      display: flex; align-items: center; justify-content: center;
      cursor: pointer; color: var(--text-muted); transition: all 0.15s;
    }
    /* На ховере только подложка на тон темнее — рамка вокруг иконки 26×26
       читалась как отдельный элемент управления и шумела в шапках разделов */
    .param-icon-btn:hover { border-color: transparent; color: var(--purple); background: rgba(15,30,60,.08); }
    .param-row {
      margin: 3px 12px; padding: 10px 10px;
      display: flex; gap: 12px; align-items: flex-start;
      font-size: 12.5px; color: var(--text-primary);
      border-radius: 10px; transition: background 0.13s; cursor: default;
    }
    .param-row:hover { background: #f5f7fa; }
    .param-arrow {
      flex-shrink: 0; margin-top: 1px;
      width: 22px; height: 22px; border-radius: 7px;
      display: flex; align-items: center; justify-content: center;
      background: #e7f6f7; color: #0098a6;
    }
    .param-arrow.in { background: #fdf0e3; color: #d97f1d; }
    .param-hint { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
    .param-pills { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
    .param-pill {
      display: inline-flex; align-items: center; gap: 5px;
      background: #e7f6f7; color: #00727d; border: none;
      border-radius: 20px; padding: 4px 11px; font-size: 11.5px; font-weight: 500;
    }
    .tc-user { display: flex; align-items: center; gap: 8px; }
    .tc-user-avatar {
      width: 26px; height: 26px; border-radius: 50%;
      background: linear-gradient(135deg,#7f93ab,#a8b8cc); border: none;
      display: flex; align-items: center; justify-content: center;
      color: #fff; flex-shrink: 0; font-size: 10px; font-weight: 700;
    }

    .proj-data-grid {
      display: grid;
      grid-template-columns: 1fr;
      gap: 0;                      /* колонки идут встык: свои отступы есть у секций */
      align-items: start;
    }
    /* Данные: 2 колонки 60/40 от 1024px. minmax(0,…) — чтобы содержимое
       не распирало треки и не порождало горизонтальную прокрутку */
    .proj-data-grid-3 { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
    .proj-data-grid-3 > :nth-child(3) { grid-column: 2; }
    @media (max-width: 1023px) {
      .proj-data-grid-3 { grid-template-columns: 1fr; }
      .proj-data-grid-3 > :nth-child(3) { grid-column: auto; }
    }
    /* Открытый чат потока сужает область контента, а окно остаётся широким — здесь
       считаем по ширине самой области, иначе колонки не схлопываются. */
    /* Учётная запись отдаёт часть колонки под фото, поэтому «Приглашение» со
       статусом и датой перестаёт помещаться раньше остальных полей — на странице
       участника переходим в одну колонку раньше остальных страниц */
    @container (max-width: 919px) {
      body[data-page="member"] .proj-data-grid-3 { grid-template-columns: 1fr; }
      body[data-page="member"] .proj-data-grid-3 > :nth-child(3) { grid-column: auto; }
      /* В одну колонку скролл общий: своя полоса у каждой колонки здесь ни к чему */
      body[data-page="member"] .body-area > .task-panel.active:has(> .proj-data-grid) {
        height: auto; display: block;
      }
      body[data-page="member"] .task-panel > .proj-data-grid { flex: none; }
      body[data-page="member"] .task-panel > .proj-data-grid > div {
        overflow: visible; min-height: 0; padding: 3px;
      }
    }
    .content > .flow-main-col > .body-area { container-type: inline-size; }
    /* Правая колонка («Планирование» / «Выполняет») держится рядом с данными как
       можно дольше: ниже 1024px не схлопываем сразу в один столбец, а переходим
       на равные половины с узким жёлобом. В один столбец — только когда колонка
       physически перестаёт вмещать поля (меньше 640px) */
    @container (min-width: 640px) and (max-width: 1023px) {
      /* minmax(0,…), а не 1fr: у 1fr минимум равен min-content, и длинные
         пилюли вроде «ЗД-0042 · Разработка модуля авторизации» распирали трек,
         из-за чего внизу появлялся горизонтальный скроллер */
      .proj-data-grid-3 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 20px; }
      .proj-data-grid-3 > :nth-child(3) { grid-column: 2; }
    }
    @container (max-width: 639px) {
      .proj-data-grid-3 { grid-template-columns: 1fr; }
      .proj-data-grid-3 > :nth-child(3) { grid-column: auto; }
    }
    /* Свой вертикальный скролл у каждой колонки данных: длинное описание больше
       не тянет за собой правую колонку. Только пока колонки стоят рядом —
       в один столбец скроллится вся область, как раньше */
    @container (min-width: 640px) {
      /* Панель — колонка: над сеткой может стоять панель фильтров («Выполнение»),
         поэтому сетка занимает остаток высоты (height: 100% выносило её за область
         ровно на высоту фильтров и давало лишний скролл всей области) */
      /* только .active — иначе display: flex показал бы скрытые панели.
         .proj-panel (команда, проект, кейс) прячется инлайновым display: none,
         поэтому его можно брать без .active — инлайн перебивает flex */
      .body-area > .task-panel.active:has(> .proj-data-grid),
      .body-area > .proj-panel:has(> .proj-data-grid) {
        height: 100%; min-height: 0; display: flex; flex-direction: column;
      }
      /* Над панелью стоит балон подсказки — тогда высоту панели должен давать flex.
         height: 100% выносило её за область ровно на высоту балона, и колонка
         не доскролливалась до последней карточки */
      .body-area:has(> .screen-hint):has(> .task-panel > .proj-data-grid),
      .body-area:has(> .screen-hint):has(> .proj-panel > .proj-data-grid) {
        display: flex; flex-direction: column;
      }
      .body-area:has(> .screen-hint) > .task-panel.active:has(> .proj-data-grid),
      .body-area:has(> .screen-hint) > .proj-panel:has(> .proj-data-grid) {
        height: auto; flex: 1;
      }
      .task-panel > .proj-data-grid,
      .proj-panel > .proj-data-grid { flex: 1; min-height: 0; align-items: stretch; }
      .task-panel > .proj-data-grid > div,
      .proj-panel > .proj-data-grid > div {
        min-height: 0; overflow-y: auto; overscroll-behavior: contain;
        /* Боковые отступы — место под тень карточек: скролл-контейнер режет её
           и по горизонтали (overflow-y: auto делает overflow-x тоже auto).
           Справа шире — там ещё и полоса прокрутки */
        padding: 3px 10px 3px 3px;
        scrollbar-width: thin;
      }
    }
    /* Структура / Выполнение: 2 колонки только от 1920px */
    @media (min-width: 1920px) {
      .proj-data-grid:not(.proj-data-grid-3) { grid-template-columns: 1fr 1fr; }
    }

    .toolbar-filter {
      display: inline-flex; align-items: center; gap: 5px;
      padding: 4px 10px; border-radius: 6px; cursor: pointer;
      font-size: 12px; font-weight: 500; color: var(--text-secondary);
      border: 1px solid var(--border); background: #fff;
      transition: all 0.15s; user-select: none; white-space: nowrap;
    }
    .toolbar-filter:hover { border-color: var(--purple-mid); color: var(--text-primary); }
    .toolbar-filter.active { border-color: #9fe1cb; color: #0f6e56; background: #e1f5ee; font-weight: 600; }
    .toolbar-filter svg { opacity: 0.5; flex-shrink: 0; }
    /* Фильтры-дропдауны всегда влево (без margin-left:auto и без спейсера) —
       не прижимаются вправо ни на одной ширине. */
    /* display: contents — выпадайки становятся элементами самой строки фильтров
       и переносятся по одной. Своим блоком группа уезжала на новую строку
       целиком, даже когда там помещалась одна-две */
    .toolbar-filters { display: contents; }
    /* Фильтр со сбросом: пока значение не выбрано — шеврон, после выбора — крестик */
    .toolbar-filter .tf-clear { display: none; }
    .toolbar-filter.has-value .tf-clear { display: block; opacity: .75; }
    .toolbar-filter.has-value .tf-chev { display: none; }
    .toolbar-filter .tf-clear:hover { opacity: 1; }

    /* Дропдаун фильтра «Рабочий поток»: поиск + список потоков, сгруппированных по проектам */
    .toolbar-filter-wrap { position: relative; }
    .filter-dropdown {
      display: none; position: absolute; top: calc(100% + 6px); right: 0;
      width: 300px; max-height: 570px;
      background: #fff; border: 1px solid var(--border); border-radius: 10px;
      box-shadow: var(--shadow-md); z-index: 40; overflow: hidden;
      flex-direction: column;
    }
    .toolbar-filter-wrap.open .filter-dropdown { display: flex; }
    /* Плюс композера: меню вложений раскрывается вверх, а контролы выбора
       результата работы/инструкции/хранилища висят точкой у плюса — выпадайка всплывает
       от него, самих кнопок в тулбаре нет */
    .dpx-plus-wrap { position: relative; display: flex; align-items: center; }
    .dpx-plus-menu { top: auto; bottom: calc(100% + 8px); left: 0; right: auto; min-width: 190px; }
    .dpx-pick-anchor { position: absolute; left: 0; bottom: 0; width: 0; height: 0; }
    .fd-search { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
    .fd-search svg { color: var(--text-muted); flex-shrink: 0; opacity: 1; }
    /* font-family: inherit обязателен — иначе поле берёт системный Arial и подсказка
       выглядит плотнее и темнее остального интерфейса */
    .fd-search input { border: none; outline: none; width: 100%; background: transparent; font-family: inherit; font-size: 13px; font-weight: 400; color: var(--text-primary); }
    .fd-search input::placeholder { color: #b6bfcc; font-weight: 400; }
    .fd-list { overflow-y: auto; padding: 6px; }
    .fd-proj {
      display: flex; align-items: center; gap: 8px; padding: 7px 8px; margin-top: 2px;
      font-size: 13px; font-weight: 600; color: var(--text-primary);
      cursor: pointer; border-radius: 6px;
    }
    .fd-proj:hover { background: #eef0fa; }
    .fd-flow {
      display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 22px;
      font-size: 12.5px; color: var(--text-secondary); cursor: pointer; border-radius: 6px;
    }
    .fd-flow:hover { background: #f1f4f9; color: var(--text-primary); }
    .fd-code {
      font-size: 10.5px; font-weight: 600; color: #9ca3af; background: #eaedf4;
      padding: 1px 6px; border-radius: 4px; flex-shrink: 0;
    }
    .fd-empty { padding: 16px; text-align: center; color: var(--text-muted); font-size: 12.5px; }
    /* Некликабельный заголовок раздела (напр. «Навыки») и приглушённая роль справа в пункте */
    .fd-section { padding: 8px 8px 3px; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
    .fd-muted { margin-left: auto; font-size: 11px; color: var(--text-muted); }
    /* Плоские списки меток и статусов — без отступа под группу */
    #wtTagList .fd-flow, #wtStatusList .fd-flow { padding-left: 8px; }
    /* Серый крестик в кнопке-фильтре — убирает все чипы этого фильтра */
    .filter-x {
      display: inline-flex; align-items: center; justify-content: center;
      width: 15px; height: 15px; padding: 0; flex-shrink: 0;
      border: none; background: none; color: #0f6e56; cursor: pointer; border-radius: 50%;
    }
    .filter-x:hover { color: #0a4d3c; background: #d7f0e6; }
    .filter-x svg { opacity: 1; }

    /* Контейнер панели фильтров: страница ставит один <div class="fbar">, содержимое
       собирает JS. display:contents — чтобы пилюли, чипы и фильтры вели себя как
       прямые дети тулбара и раскладка страниц не менялась. */
    .fbar { display: contents; }
    /* Кнопка «Свернуть все» упирается во внутренний паддинг строки фильтров (12px)
       и не дотягивается до края, где стоят «⋮» и плюсы секций — компенсируем */
    .plan-filter-bar .collapse-btn { margin-right: -12px; }
    /* Блоки панели переносятся целиком: не сминаются (flex-shrink:0), а уезжают на
       следующую строку. Иначе флексбокс сжимает их все сразу и каждый начинает
       переноситься внутри себя — пилюли рвутся на две строки, фильтры тоже.
       max-width:100% — чтобы блок шире строки всё-таки перенёсся внутри, а не вылез. */
    .filter-presets, .flow-chips, .toolbar-filters { flex-shrink: 0; max-width: 100%; }
    /* Пустые блоки (нет пресетов, нет рабочих чипов) убираем совсем: нулевая ширина
       всё равно оставляет за собой gap тулбара, и содержимое отъезжает от края */
    .plan-filter-bar .filter-presets:empty,
    .plan-filter-bar .flow-chips:empty { display: none; }

    /* Сохранённые фильтры (пресеты) — круглые пилюли, как бывшие быстрые фильтры; одиночный выбор */
    /* display: contents — как и у выпадаек: пилюли становятся элементами самой
       строки фильтров и переносятся по одной, а не всей группой разом */
    .filter-presets { display: contents; }
    .preset-chip {
      display: inline-flex; align-items: center; gap: 2px;
      padding: 4px 10px; border-radius: 20px; cursor: pointer;
      font-size: 12px; font-weight: 500; white-space: nowrap;
      color: #93a4ba; border: 1px solid var(--border); background: transparent; transition: all .15s;
    }
    .preset-chip:hover { color: #143258; border-color: var(--border-mid); }
    .preset-chip.active { color: #0f6e56; background: #e1f5ee; border-color: #9fe1cb; font-weight: 600; }
    /* Цвет сохранённого фильтра: бледно, пока набор не выбран, и в полную силу при выборе.
       Специфичность .tinted.active выше .active — иначе побеждала бы зелёная заливка выше. */
    .preset-chip.tinted {
      color: color-mix(in srgb, var(--preset-color) 55%, #a9b4c4);
      border-color: color-mix(in srgb, var(--preset-color) 28%, #fff);
    }
    .preset-chip.tinted:hover {
      color: var(--preset-color);
      border-color: color-mix(in srgb, var(--preset-color) 45%, #fff);
    }
    .preset-chip.tinted.active {
      color: var(--preset-color); font-weight: 600;
      border-color: color-mix(in srgb, var(--preset-color) 50%, #fff);
      background: color-mix(in srgb, var(--preset-color) 10%, #fff);
    }
    /* Выбор цвета в диалоге создания фильтра */
    .preset-colors { display: flex; gap: 8px; flex-wrap: wrap; }
    .preset-color {
      width: 22px; height: 22px; padding: 0; border-radius: 50%; cursor: pointer;
      border: 2px solid transparent; box-shadow: inset 0 0 0 1px rgba(5,28,59,.12);
      transition: transform .12s;
    }
    .preset-color:hover { transform: scale(1.12); }
    .preset-color.sel { border-color: var(--text-secondary); }
    /* «Без цвета» — вариант по умолчанию: пилюля останется обычной серо-зелёной */
    .preset-color-none {
      background: #fff;
      background-image: linear-gradient(45deg, transparent 45%, #c9ced8 45%, #c9ced8 55%, transparent 55%);
    }
    .preset-label { user-select: none; }
    .preset-x {
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; color: inherit; cursor: pointer;
      padding: 1px; margin-left: 2px; border-radius: 50%; opacity: .6;
    }
    .preset-x:hover { opacity: 1; background: rgba(0,0,0,.12); }
    .preset-add {
      display: inline-flex; align-items: center; justify-content: center;
      width: 26px; height: 26px; padding: 0; flex-shrink: 0;
      border: 1px dashed var(--border-mid); border-radius: 50%; background: transparent;
      color: var(--text-secondary); cursor: pointer; transition: all .15s;
    }
    .preset-add:hover { border-color: var(--purple-mid); color: var(--text-primary); border-style: solid; }
    /* Сброс — круглая кнопка с крестиком, рядом с «+»; показывается вместе с ним */
    .preset-reset {
      display: inline-flex; align-items: center; justify-content: center;
      width: 26px; height: 26px; padding: 0; flex-shrink: 0;
      border: 1px solid var(--border-mid); border-radius: 50%; background: transparent;
      color: var(--text-secondary); cursor: pointer; transition: all .15s;
    }
    .preset-reset:hover { border-color: var(--red); color: var(--red); background: #fde5e5; }

    /* Превью чипов в диалоге создания фильтра */
    .preset-chips-preview { display: flex; flex-wrap: wrap; gap: 6px; min-height: 32px; align-items: center; }
    .preset-prev-chip { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 6px; background: #eef1f6; color: #46536e; font-size: 12px; font-weight: 500; }
    .preset-prev-empty { font-size: 12.5px; color: var(--text-muted); }
    /* Статус-чип круглый (одиночный «вид»), в отличие от прямоугольных атрибутных чипов */
    .flow-chip.status { border-radius: 20px; }
    /* Кнопка сброса фильтров — второстепенное действие справа в строке фильтров */
    .filter-reset {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 4px 10px; border-radius: 6px; cursor: pointer;
      font-size: 12px; font-weight: 500; color: var(--text-secondary);
      border: none; background: transparent; transition: all .15s; white-space: nowrap;
    }
    .filter-reset:hover { color: var(--text-primary); background: var(--bg); }
    .filter-reset svg { opacity: .6; }
    .toolbar-filter-wrap.open .toolbar-filter { border-color: var(--purple-mid); color: var(--text-primary); }
    /* Пикер базового плана в диалоге — на всю ширину, дропдаун тоже */
    #basePlanPicker { width: 100%; }
    #basePlanPicker > .toolbar-filter { width: 100%; }
    #basePlanPicker > .toolbar-filter .tf-chev { margin-left: auto; }
    #basePlanPicker .filter-dropdown { left: 0; right: 0; width: auto; min-width: 0; max-height: 280px; }

    /* Чипы выбранных потоков/проектов — справа от быстрых фильтров.
       Форма кодирует режим выбора: прямоугольные — мультивыбор (потоки можно
       набирать вместе); скруглённые (pill) — одиночный выбор, как у статус-фильтров. */
    .flow-chips { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
    .flow-chip {
      display: inline-flex; align-items: center; gap: 2px;
      padding: 3px 4px 3px 10px; border-radius: 6px;
      background: #e1f5ee; border: 1px solid #9fe1cb;
      font-size: 12px; font-weight: 600; color: #0f6e56; white-space: nowrap;
    }
    .flow-chip-label { cursor: pointer; user-select: none; }
    /* Выключенный чип — обычным начертанием, без зачёркивания */
    .flow-chip.off { background: #f1f4f9; border-color: var(--border); color: var(--text-muted); font-weight: 400; }
    .flow-chip-x {
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; color: inherit; cursor: pointer;
      padding: 2px; border-radius: 50%; opacity: .7;
    }
    .flow-chip-x:hover { opacity: 1; background: rgba(0,0,0,.08); }

    /* Карточки-метрики (Планирование) */
    .pm-grid {
      display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
      gap:10px; padding:0 4px;
    }
    .pm-card {
      position:relative; background:var(--card); border-radius:12px;
      padding:14px 16px; box-shadow:var(--shadow-sm); overflow:hidden;
    }
    .pm-card::before {
      content:''; position:absolute; left:0; top:0; bottom:0; width:3px;
      background:var(--border-mid);
    }
    .pm-card.info::before { background:var(--purple); }
    .pm-card.warn::before { background:var(--red); }
    .pm-card.ok::before   { background:var(--teal); }
    .pm-card.blue::before { background:#3b82f6; }

    .pm-top   { display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
    .pm-head  { display:flex; flex-direction:column; gap:1px; min-width:0; }
    .pm-label { font-size:11px; font-weight:500; color:var(--text-muted);
                text-transform:uppercase; letter-spacing:.4px; }
    .pm-value { font-size:18px; font-weight:600; color:var(--text-primary);
                letter-spacing:-.3px; }
    .pm-value.warn { color:var(--red); }

    .pm-ico { width:28px; height:28px; border-radius:8px; flex-shrink:0;
              display:flex; align-items:center; justify-content:center; }
    .pm-ico.info { background:#f2eff8; color:#6e56cf; }
    .pm-ico.warn { background:#fdecec; color:var(--red); }
    .pm-ico.ok   { background:#e6f6f2; color:var(--teal); }
    .pm-ico.blue { background:#eaf1ff; color:#3b82f6; }

    .pm-vd    { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; }
    .pm-delta { font-size:12px;
                display:inline-flex; align-items:center; gap:4px; }
    .pm-delta .arrow { display:inline-flex; }
    .pm-delta .val   { font-weight:600; }
    .pm-delta .unit  { color:var(--text-secondary); }
    .pm-delta.good   { color:var(--teal); }
    .pm-delta.bad    { color:var(--red); }

    /* Модальное окно */
    .modal-overlay {
      display: none;
      position: fixed; inset: 0;
      background: rgba(20, 30, 50, 0.35);
      z-index: 200;
      align-items: center; justify-content: center;
      animation: fadeIn 0.15s ease both;
    }
    .modal-overlay.open { display: flex; }
    .modal {
      background: #fff; border-radius: 14px;
      box-shadow: 0 12px 40px rgba(0,0,0,0.18);
      width: 380px; max-width: calc(100vw - 32px);
      display: flex; flex-direction: column;
      animation: fadeIn 0.18s ease both;
    }
    .modal-head {
      padding: 14px 16px; border-bottom: 1px solid var(--border);
      display: flex; align-items: center;
    }
    .modal-title { font-size: 15px; font-weight: 600; color: var(--text-primary); }
    .modal-close {
      margin-left: auto; background: transparent; border: none;
      cursor: pointer; color: var(--text-muted);
      display: flex; align-items: center; justify-content: center;
      width: 26px; height: 26px; border-radius: 6px;
      transition: background .12s, color .12s;
    }
    .modal-close:hover { background: rgba(0,0,0,0.05); color: #1a1d35; }
    .modal-body {
      padding: 16px; display: flex; flex-direction: column; gap: 12px;
    }
    .modal-field { display: flex; flex-direction: column; gap: 6px; }
    .modal-label { font-size: 12px; color: var(--text-secondary); font-weight: 500; }
    .modal-optional { color: var(--text-muted); font-weight: 400; }
    .modal-input {
      padding: 8px 10px; font-size: 13px;
      border: 1px solid var(--border-mid); border-radius: 7px;
      outline: none; transition: border-color .12s;
      font-family: inherit;
    }
    .modal-input:focus { border-color: #3b82f6; }
    .modal-check {
      display: flex; align-items: center; gap: 8px;
      font-size: 13px; color: var(--text-primary); cursor: pointer;
      padding: 2px 0;
    }
    .modal-check input { margin: 0; cursor: pointer; }
    .modal-radio {
      display: flex; align-items: center; gap: 8px;
      font-size: 13px; color: var(--text-primary); cursor: pointer;
      padding: 2px 0;
    }
    .modal-radio input { margin: 0; cursor: pointer; }
    .modal-radio > span:not(:first-of-type) { margin-left: 4px; }
    .modal-select {
      margin-left: auto; padding: 4px 8px; font-size: 12.5px;
      border: 1px solid var(--border-mid); border-radius: 6px;
      background: #fff; color: var(--text-primary);
      font-family: inherit; cursor: pointer; outline: none;
    }
    .modal-select:disabled { opacity: 0.4; cursor: not-allowed; background: #f7f8fa; }
    .modal-select:focus { border-color: #3b82f6; }
    .modal-foot {
      padding: 12px 16px; border-top: 1px solid var(--border);
      display: flex; justify-content: flex-end; gap: 8px;
    }

    /* Workplan — Планы (список планов) */
    .plan-list { display: flex; flex-direction: column; gap: 10px; padding: 4px 12px 8px; }
    .plan-card {
      background: var(--card); border: 1px solid var(--border); border-radius: 10px;
      padding: 14px 16px; cursor: pointer; transition: border-color .15s, box-shadow .15s;
    }
    .plan-card:hover { border-color: var(--border-mid); box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
    .plan-card.active { border-color: #3b82f6; background: #f7faff; }
    .plan-card-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
    .plan-card-name { font-size: 13.5px; font-weight: 600; color: var(--text-primary); }
    .plan-card-count { margin-left: auto; font-size: 11.5px; color: var(--text-muted);
                       background: #f3f3f9; padding: 2px 8px; border-radius: 6px; }
    .plan-card-tag {
      font-size: 10px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase;
      padding: 3px 7px; border-radius: 5px;
    }
    .plan-card-tag.current { background: #eaf1ff; color: #3b82f6; }
    .plan-card-tag.draft   { background: #fff4e0; color: #d17b16; }
    .plan-card-tag.base    { background: #eef1f6; color: #4b5766; }
    .plan-card-tag.archive { background: #ececf0; color: #8b95a5; }
    .plan-card-desc { margin-top: 8px; font-size: 12.5px; color: var(--text-secondary); line-height: 1.5; }
    .plan-card-foot { margin-top: 10px; display: flex; align-items: center; gap: 10px; font-size: 11.5px; }
    .plan-card-progress {
      display: inline-block; width: 120px; height: 5px; border-radius: 3px;
      background: #eef0f4; overflow: hidden;
    }
    .plan-card-progress > i { display: block; height: 100%; background: var(--teal); border-radius: 3px; }

    /* Режим «Задачи» на «Плане работ» (переключатель — табы в заголовке): диаграмма
       и всё её обрамление скрыты, на странице остаётся только список задач */
    #wt-gantt.tasks-view { display: none; }

    /* ─── Диаграмма Ганта (План работ) ─── */
    /* .fbar — display: contents, поэтому его блоки становятся flex-элементами
       тулбара. Пустые пресеты и чипы съедали по gap каждый и сдвигали фильтры
       вправо от контента (на «Чатах» это было 20px из ниоткуда) */
    .gantt-toolbar > .fbar > .filter-presets:empty,
    .gantt-toolbar > .fbar > .flow-chips:empty { display: none; }
    .gantt-toolbar {
      display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
      padding: 8px 12px; margin-bottom: 10px; border-radius: 9px;
      position: sticky; top: 0; z-index: 16;
      background: var(--area-bg); box-shadow: 0 0 0 6px var(--area-bg);
      transition: background-color .26s ease, box-shadow .26s ease;
    }
    /* В ленте прокручивается вся область, а тулбар липкий и встаёт на 24 px
       ниже её верха — на поле ленты. В этот просвет было видно уезжающие
       карточки, поэтому закрываем его фоном тулбара: прокрутка начинается
       сразу под тулбаром, выше него содержимого не видно */
    body .vibe-feed .gantt-toolbar:first-child::before,
    body .vibe-feed .plan-filter-bar::before {
      content: ''; position: absolute; left: -6px; right: -6px;
      bottom: 100%; height: 26px; background: var(--area-bg);
    }
    .gantt-legend {
      display: flex; align-items: center; gap: 10px;
      padding: 4px 12px 12px;
      font-size: 11.5px; color: var(--text-secondary);
    }
    .gl-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; flex-shrink: 0; }
    /* Мало места для пилюль — прячем легенду цветов (её всегда можно вспомнить) */
    .gantt-legend.legend-compact .gl-item { display: none; }
    /* Подсказка-чип слева от легенды загрузки. Фон полупрозрачный, а не фикс
       #eef1f6: теперь легенда красится в подложку, и с тем же хардкодом чип
       сливался бы с ней в ноль. Так он на тон глубже любой поверхности */
    .legend-hint {
      display: inline-flex; align-items: center; margin-right: 4px;
      background: rgba(15,30,60,.055); color: #5c6b80; border-radius: 20px;
      padding: 3px 11px; font-size: 11.5px; font-weight: 500;
    }
    /* Чип сценария, по которому запущен поток (у этапов сценария нет) */
    .scenario-chip {
      display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0;
      background: #eef1f6; color: #5c6b80; border-radius: 20px;
      padding: 2px 9px 2px 7px; font-size: 11px; font-weight: 500; white-space: nowrap;
    }
    .scenario-chip svg { color: #8b95a5; flex-shrink: 0; }
    .gl-swatch { width: 18px; height: 8px; border-radius: 3px; flex-shrink: 0; }
    /* Переключатели вида и масштаба — сегмент-пилюли справа в легенде */
    .gantt-view-tools { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
    /* Порядок строки легенды: слева пилюли — группировка, затем масштаб, а сама
       легенда цветов уходит вправо (order, чтобы не править разметку страниц) */
    /* Чекбокс «выбрать всех» и счётчик строк слева в тулбаре списка */
    /* Боковых полей у тулбара нет: фильтры и кнопка встают по тем же краям,
       что колонки таблицы под ними. Сверху — такой же воздух, как снизу */
    #wt-people .gantt-toolbar {
      display: flex; align-items: center; gap: 8px;
      /* Сверху воздух даёт внешний отступ — своего поля тулбару не нужно */
      padding: 0 0 8px; margin-top: 10px;
    }
    #wt-people .gantt-toolbar > .fbar-lead { flex-shrink: 0; }
    /* «Участники» — в нижней панели у левого края, меню открывается под кнопкой.
       Вертикальные поля обёртки «Добавить» (9/19px) здесь лишние: из-за них
       кнопка стояла выше соседей */
    #wt-people .gantt-legend > .people-add {
      order: 0; margin: 0 auto 0 0; flex-shrink: 0; position: relative;
    }
    .people-add-btn { white-space: nowrap; }
    /* Кнопка стоит у левого края — меню раскрывается от него же: базовое
       right:0 уводило список левее кнопки, за край области */
    #wt-people .gantt-legend > .people-add > .new-menu { left: 0; right: auto; }
    #wt-people .gantt-toolbar > .fbar { flex: 1; min-width: 0; }
    #wt-people .gantt-row .gantt-label > .item-check,
    #wt-people .gantt-group-head .gantt-label > .item-check { margin-right: 2px; }

    /* Группировка по командам сама показывает команды — фильтр «Команда» скрыт */
    #wt-people.hide-team-filter .toolbar-filter-wrap[data-kind="team"] { display: none; }

    /* «Специальности» — секции как на табе «Данные»: слева навыки, справа
       специальности, у каждой колонки свой вертикальный скролл */
    #wt-spec { display: flex; flex-direction: column; min-height: 0; }
    #wt-spec > .gantt, #wt-spec.scroll-host > .gantt { flex: 1; min-height: 0; display: flex; overflow: hidden; }
    #wt-spec > .gantt > .proj-data-grid {
      flex: 1; min-height: 0; align-items: stretch;
      display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 24px;
    }
    /* Прокрутка колеса передаётся дальше: в ленте колонка по высоте вмещает всё
       и сама не прокручивается, а overscroll-behavior: contain глушил колесо —
       над карточками страница стояла на месте */
    #wt-spec > .gantt > .proj-data-grid > div {
      min-height: 0; overflow-y: auto; overscroll-behavior: auto;
      padding: 3px 10px 3px 3px; scrollbar-width: thin;
    }
    /* Тулбар с «выбрать всё» и счётчиком — как на «Загрузке» */
    #wt-spec > .gantt-toolbar { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-bottom: 8px; }
    #wt-spec .spec-head > .item-check { flex-shrink: 0; }

    /* Строка — два блока друг под другом: шапка (чекбокс, имя, крестик удаления)
       и тело (описание, чипы) по левому краю строки, без отступа под чекбокс */
    #wt-spec .spec-row {
      cursor: pointer; flex-direction: column; align-items: stretch;
      gap: 6px; padding-top: 11px; padding-bottom: 11px;
    }
    #wt-spec .spec-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
    #wt-spec .spec-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
    #wt-spec .spec-head .spec-del { margin-left: auto; }
    #wt-spec .spec-row .proj-data-val {
      display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-start;
      max-width: 100%; margin: 0;
    }
    #wt-spec > .gantt > .proj-data-grid > div { container-type: inline-size; }
    #wt-spec .spec-row .ichip { flex-shrink: 0; }
    /* Крестик на чипе (разорвать связь) и справа в строке (удалить целиком) —
       появляются по наведению на строку */
    #wt-spec .spec-chip { display: inline-flex; align-items: center; gap: 4px; padding-right: 4px; cursor: default; }
    /* Кликабельны только чипы квалификации — у них меняется уровень */
    #wt-spec .spec-chip.spec-qual { cursor: pointer; }
    /* Квалификация в чипе: «навык · уровень» — точка-разделитель и цифра,
       цвет цифры подсказывает уровень */
    .qual-dot { opacity: .45; margin: 0 -1px; }
    /* Цифра уровня — тем же цветом, что имя навыка в чипе, только плотнее */
    .qual-lvl { flex-shrink: 0; font-weight: 600; line-height: 1; color: inherit; }
    /* В списке выбора уровня цифра остаётся кружком — так пункты различимы */
    .qual-dd .qual-lvl {
      width: 18px; height: 18px; border-radius: 50%;
      display: inline-flex; align-items: center; justify-content: center;
      font-size: 10px; background: rgba(15,30,60,.10);
    }
    /* Попап выбора уровня — как список в фильтрах */
    .qual-dd .cs-opt { display: flex; align-items: center; gap: 8px; }
    .qual-dd .cs-opt.sel { background: #e1f5ee; color: #0f6e56; font-weight: 600; }
    /* Крестики на чипах видны всегда: при показе только по наведению чипы
       переверстывались и казалось, что часть навыков появляется лишь на hover */
    #wt-spec .spec-x {
      width: 14px; height: 14px; padding: 0; border: none; border-radius: 4px;
      display: inline-flex; align-items: center; justify-content: center;
      background: transparent; color: inherit; opacity: .45; cursor: pointer;
    }
    #wt-spec .spec-row:hover .spec-x { opacity: .7; }
    #wt-spec .spec-x:hover { opacity: 1; background: rgba(0,0,0,.08); }
    #wt-spec .spec-del { opacity: 0; flex-shrink: 0; margin-left: 8px; transition: opacity .12s; }
    #wt-spec .spec-row:hover .spec-del { opacity: 1; }
    /* Перетаскивание навыка в специальность. Курсор-рука только на ручке:
       клик по самой строке открывает навык, значит на строке — палец */
    #wt-spec .spec-skill { cursor: pointer; }
    /* Ручка переноса слева от чекбокса. Место под неё держим всегда, показываем
       по наведению — иначе строка при наведении дёргалась бы вправо */
    #wt-spec .spec-grip {
      position: static; height: auto; width: 12px; flex-shrink: 0;
      display: inline-flex; opacity: 0; margin: 0 -2px 0 0; padding: 0;
      transition: opacity .12s;
    }
    #wt-spec .spec-row:hover .spec-grip { opacity: .55; }
    #wt-spec .spec-grip:hover { opacity: 1; }
    /* Источник не гасим в ноль — только помечаем, чтобы было видно, что тащим */
    #wt-spec .spec-dragging { opacity: .75; border-style: dashed; border-color: var(--teal); }
    /* Плашка под курсором во время переноса */
    .spec-ghost {
      position: fixed; top: -1000px; left: -1000px; z-index: 5000; pointer-events: none;
      padding: 8px 14px; border-radius: 8px; white-space: nowrap;
      background: #fff; border: 1px solid var(--teal); color: #0f6e56;
      font-size: 13px; font-weight: 600;
      box-shadow: 0 6px 18px rgba(15,30,60,.18);
    }
    #wt-spec .spec-prof.spec-drop {
      border-color: var(--teal); background: #e9f7f2;
      box-shadow: 0 0 0 1px var(--teal);
    }
    /* Специальность: имя жирным, под ним описание */
    #wt-spec .spec-name { font-size: 14px; font-weight: 600; color: var(--text-primary); }
    /* Описание специальности — тонким начертанием: подпись не спорит с именем */
    #wt-spec .spec-desc {
      font-size: 12px; color: var(--text-muted); line-height: 1.35;
      font-weight: 300; -webkit-font-smoothing: antialiased;
    }

    .gantt-group-pills { flex-shrink: 0; order: 0; }
    .gantt-group-pills .seg { white-space: nowrap; }
    /* Порядок в легенде: пилюли группировки слева, затем сама легенда цветов,
       справа от неё — масштаб (День/Неделя/Месяц) и «свернуть все» */
    .gantt-legend > .gl-item { order: 1; }
    .gantt-legend > .gl-item:first-of-type { margin-left: auto; }
    .gantt-legend > .gantt-view-tools { order: 2; margin-left: 8px; }
    /* «Свернуть все» — последней в строке, за легендой цветов */
    .gantt-legend > .gantt-toggle-all { order: 3; margin-left: 4px; }
    .seg-pills { display: inline-flex; background: #eef1f6; border-radius: 8px; padding: 2px; }
    .seg-pills .seg {
      border: none; background: transparent; cursor: pointer;
      font-size: 11.5px; font-weight: 500; color: var(--text-secondary);
      padding: 4px 11px; border-radius: 6px; transition: color .12s, background .12s;
    }
    .seg-pills .seg:hover { color: var(--text-primary); }
    .seg-pills .seg.active { background: #fff; color: #0f6e56; box-shadow: 0 1px 2px rgba(15,30,60,0.08); }
    .gl-swatch.plan { background: #d3dae5; }
    .gl-swatch.fact { background: #a9e5d7; }
    .gl-swatch.fact.bad { background: #f7c2bd; }
    /* «Выполнено» бывает двух цветов: бирюзовое — в плане, красное — у отставших
       от базы, поэтому в легенде показываем оба одним образцом — поровну и пошире. */
    .gl-swatch.fill {
      width: 24px;
      background: linear-gradient(90deg, var(--teal) 0 50%, var(--red) 50% 100%);
    }

    /* Если месяцы не помещаются по ширине — горизонтальный скролл.
       Скроллер один на всю диаграмму, иначе дорожки разъехались бы независимо друг от друга. */
    /* Боковых паддингов быть не должно: sticky-колонки липнут к краю паддинга,
       а полосы едут под ним — в щели видны обрывки. Отступ живёт внутри колонок. */
    .gantt {
      padding: 0 0 8px;
      overflow-x: auto;
      scrollbar-width: none;               /* полосу показывает липкий дублёр .gantt-scrollbar */
    }
    .gantt::-webkit-scrollbar { display: none; }

    /* Дублёр полосы прокрутки: липнет к низу окна, поэтому виден и тогда,
       когда собственная нижняя кромка диаграммы ушла за пределы экрана. */
    .gantt-scrollbar {
      position: sticky; bottom: 0; z-index: 14;
      overflow-x: auto; overflow-y: hidden;
      background: var(--area-bg);
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
    }
    .gantt-scrollbar > div { height: 1px; }
    .gantt-scrollbar::-webkit-scrollbar { height: 5px; }
    .gantt-scrollbar::-webkit-scrollbar-track { background: transparent; }
    .gantt-scrollbar::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .gantt-scrollbar.idle { display: none; }   /* прокручивать нечего */

    .gantt-toggle-all {
      display: inline-flex; align-items: center; justify-content: center;
      width: 24px; height: 24px; padding: 0; flex-shrink: 0;
      border: none; border-radius: 6px; background: #eceff4;
      color: var(--text-secondary); cursor: pointer; transition: background .15s, color .15s;
    }
    .gantt-toggle-all:hover { background: #e2e7ef; color: var(--text-primary); }
    .gantt-toggle-all svg { opacity: .5; transition: transform .2s; }
    .gantt-toggle-all:hover svg { opacity: .8; }
    /* Свёрнуто — стрелка вниз (клик развернёт), развёрнуто — вверх (клик свернёт) */
    .gantt-toggle-all:not(.collapsed) svg { transform: rotate(180deg); }
    /* Та же кнопка в правой группе таб-бара — как остальные значки там:
       без серой плашки, круглая подсветка по наведению */
    .tab-bar .gantt-toggle-all.tab-more {
      width: 32px; height: 32px; padding: 0; border-radius: 50%;
      background: transparent; color: #8b95a5;
    }
    /* В правой группе кнопка идёт последней — за «Добавить» и служебными */
    .tab-bar-actions > .gantt-toggle-all { order: 1; }
    /* «Добавить» — первым в группе: это главное действие шапки, служебные
       кнопки (обновить, сохранить план) идут за ним */
    .tab-bar-actions > #newBtnWrap { order: -1; }
    .tab-bar .gantt-toggle-all.tab-more:hover { background: rgba(0, 0, 0, .06); color: #333; }
    .tab-bar .gantt-toggle-all.tab-more svg { opacity: 1; }
    /* 210 (метки) + 268 (цифры) + 24 (gap) + 478 на 5 месяцев ≈ 980 */
    .gantt-head, .gantt-group, .gantt-group-head, .gantt-row, .gantt-weekgrid { min-width: 1006px; }
    /* Подпись «базовый план не сохранён» в пустой базовой дорожке (над планом) */
    .gantt-nobase {
      position: absolute; top: 50%; transform: translateY(-50%);
      font-size: 10px; color: var(--text-muted); white-space: nowrap; pointer-events: none;
    }
    /* Недельные ячейки внутри трека строки: подсветка недели + клик = фильтр */
    .wk-cells { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
    .wk-cells .wk { position: absolute; top: 1.5px; bottom: 1.5px; pointer-events: auto; cursor: pointer; border-radius: 6px; }
    .wk-cells .wk:hover { background: rgba(90, 120, 170, 0.14); }
    .gantt-head, .gantt-row, .gantt-group-head { display: flex; align-items: stretch; gap: 12px; }
    /* Крайние колонки приколоты — при скролле ездит только область полосок.
       background: inherit — чтобы подхватывать фон строки, в т.ч. при :hover */
    .gantt-head, .gantt-row { background: var(--area-bg); transition: background-color .26s ease; }
    .gantt-label { position: sticky; left: 0; z-index: 3; background: inherit; }
    .gantt-meta  { position: sticky; right: 0; z-index: 3; background: inherit; }
    /* Скруглять надо прилипшие колонки, а не строку: её углы уезжают за край при скролле,
       и у видимой кромки остаётся прямоугольная коробка колонки. */
    .gantt-row .gantt-label, .gantt-group-head .gantt-label { border-radius: var(--r) 0 0 var(--r); }
    .gantt-row .gantt-meta,  .gantt-group-head .gantt-meta  { border-radius: 0 var(--r) var(--r) 0; }
    /* Первая линия сетки — часть закреплённой колонки: приколочена к её правому краю,
       поэтому не скроллится (колонка sticky). Остальные линии месяцев едут со шкалой. */
    .gantt-head .gantt-label,
    .gantt-group-head .gantt-label,
    .gantt-row .gantt-label { border-right: 1px solid var(--border); }
    /* Последняя линия — симметрично приколочена к левому краю колонки сумм (тоже sticky) */
    .gantt-head .gantt-meta,
    .gantt-group-head .gantt-meta,
    .gantt-row .gantt-meta { border-left: 1px solid var(--border); }
    /* Обёртка шкалы: липнет по вертикали, по горизонтали её листает JS вслед за .gantt.
       Держать шкалу внутри .gantt нельзя — его overflow-x перехватывает контекст sticky. */
    .gantt-headwrap {
      position: sticky; top: 52px; z-index: 13;
      overflow: hidden;
      background: var(--area-bg);
      transition: background-color .26s ease;
    }
    .gantt-head {
      padding: 8px 0; margin-bottom: 6px;
      background: var(--area-bg); box-shadow: 0 1px 0 var(--border);
    }
    /* Колонка имени тянется вместе с шириной экрана. База 222 + трек-база 454 + сумма 280
       + два gap по 12 = 980 (min-width строки): на узкой раскладке избытка нет, колонка = 222.
       Всё, что шире, делится между именем и треком 1:3, имя — до потолка 420. */
    /* По умолчанию колонка названий — 30% ширины Ганта, но не шире 480px:
       на широких мониторах фиксированные 248px выглядели узкой полосой,
       а процент без ограничения растягивал её до половины экрана */
    #wt-gantt, #projGanttScroll { --gantt-label-w: min(30%, 480px); }
    .gantt-label { flex: 0 0 var(--gantt-label-w); width: var(--gantt-label-w); min-width: 180px; max-width: 40%; padding-left: 12px; padding-right: 12px; display: flex; align-items: center; gap: 8px; }
    /* Ручка изменения ширины колонки названий (в шапке Ганта) */
    .gantt-col-resizer { position: absolute; top: 0; right: -4px; width: 8px; height: 100%; cursor: col-resize; z-index: 6; }
    .gantt-col-resizer::after { content: ''; position: absolute; top: 0; left: 3px; width: 2px; height: 100%; background: transparent; transition: background .12s; }
    .gantt-col-resizer:hover::after, .gantt-col-resizer.dragging::after { background: #7c9cf0; }
    .gantt-name {
      font-size: 13px; font-weight: 500; color: var(--text-primary);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* Подчёркиваем имя только при наведении на само имя: клик по нему — переход,
       клик по остальной строке к переходу не ведёт */
    .gantt-name.flow-open-link:hover { text-decoration: underline; text-underline-offset: 2px; }
    .gantt-row:hover .gantt-name:not(.flow-open-link) { text-decoration: underline; text-underline-offset: 2px; }
    .gantt-meta { width: 280px; min-width: 280px; padding-left: 12px; padding-right: 12px; display: flex; flex-direction: column; justify-content: center; gap: 3px; }
    .gantt-head .gantt-meta {
      font-size: 11px; font-weight: 600; color: var(--text-muted);
      letter-spacing: .4px;
      flex-direction: row; align-items: center; gap: 6px; justify-content: flex-start;
    }
    /* Ряд заголовков занимает всю ширину колонки: иначе он центрируется и
       «Часы» со «Стоимостью» не встают над своими цифрами */
    .gantt-head .gantt-meta > .gm-row { flex: 1 1 auto; }
    /* Переключатель колонки сумм: свёрнуто — только «План/Факт, ₽»; развёрнуто — сроки, часы, стоимость */
    /* Мелкие служебные кнопки шкалы («свернуть все», «колонка сумм») — одного
       размера, без рамки, фон чуть темнее фона страницы */
    .meta-toggle {
      display: inline-flex; align-items: center; justify-content: center;
      width: 24px; height: 24px; padding: 0; margin-left: auto; flex-shrink: 0;
      border: none; border-radius: 6px; background: #eceff4;
      color: var(--text-secondary); cursor: pointer; transition: background .15s, color .15s;
    }
    .meta-toggle:hover { background: #e2e7ef; color: var(--text-primary); }
    .meta-toggle svg { display: block; transition: transform .2s; }
    #wt-gantt:not(.meta-collapsed) .meta-toggle svg,
    #proj-exec:not(.meta-collapsed) .meta-toggle svg { transform: rotate(180deg); }

    #wt-gantt.meta-collapsed .gm-detail,
    #proj-exec.meta-collapsed .gm-detail { display: none; }
    #wt-gantt.meta-collapsed .meta-h-full,
    #proj-exec.meta-collapsed .meta-h-full { display: none; }
    #wt-gantt:not(.meta-collapsed) .meta-h-short,
    #proj-exec:not(.meta-collapsed) .meta-h-short { display: none; }
    /* Свёрнутая колонка уже — треку остаётся больше места, бары перерисуются по % */
    #wt-gantt.meta-collapsed .gantt-meta { width: 150px; min-width: 150px; }
    /* Проектный Гант: в колонке остались только сроки — сужаем, убираем пустоту справа */
    #proj-exec .gantt-meta { width: 264px; min-width: 264px; }
    #proj-exec.meta-collapsed .gantt-meta { width: 150px; min-width: 150px; }
    /* Липкая шапка Ганта в проекте прилипает к самому верху области (над ней нет
       липкого тулбара на 52px, как на «Панели»), иначе первая строка лезет над ней */
    #proj-exec .gantt-headwrap { top: 0; }
    #wt-gantt.meta-collapsed .gantt-head,
    #wt-gantt.meta-collapsed .gantt-group,
    #wt-gantt.meta-collapsed .gantt-group-head,
    #wt-gantt.meta-collapsed .gantt-row, #wt-gantt.meta-collapsed .gantt-weekgrid { min-width: 850px; }

    .gantt-track { flex: 3 1 454px; min-width: 0; position: relative; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
    .gantt-head .gantt-track { flex-direction: row; gap: 0; }
    .gantt-month {
      flex: 1; text-align: center;
      font-size: 11px; font-weight: 600; color: var(--text-muted);
      padding: 2px 0;
    }
    /* Линия слева только между месяцами — у первого её роль играет разделитель колонки */
    .gantt-month + .gantt-month { border-left: 1px solid var(--border); }

    .gantt-group { margin-bottom: 4px; }
    /* Проекты — тот же сине-фиолетовый акцент, что у родительских строк задач */
    .gantt-group-head {
      padding: 6px 0; border-radius: var(--r);   /* сверху столько же, сколько снизу */
      cursor: pointer; user-select: none; transition: background .12s;
      /* Тот же светлый тон, что и у фона страницы: шапка группы отделяется от
         белой области, но не спорит с ней синевой */
      background: #f6f7fa;
    }
    .gantt-group-head:hover { background: #eef1f6; }
    /* Правило «шапки групп на тон глубже при открытом чате» убрано: подложку
       области больше не затемняем, поэтому группы и так контрастны фону */
    /* Имя группы (процесс, тип потока, команда) — капителью: шапка читается как
       уровень группировки, а не как ещё одна строка списка */
    .gantt-group-head .sec-label { color: #111; text-transform: uppercase; letter-spacing: .4px; font-size: 12.5px; }
    .gantt-group-head .gantt-chevron { color: #8b93cf; }
    .gantt-group-head .gantt-label { gap: 8px; }
    /* Имя проекта ужимается с многоточием при нехватке места — иначе оно выдавливает
       счётчик вплотную к разделителю и правый отступ не помещается. */
    .gantt-group-head .sec-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Счётчик справа от имени группы — сколько строк внутри (потоки, участники,
       навыки). Раньше был скрыт; вернули на всех экранах со списком-диаграммой */
    .gantt-group-head .count-chip {
      display: inline-block;
      /* заливка — затемнение самой шапки: на серой, розовой и жёлтой она всегда
         на тон темнее фона, как у чипов в строках */
      background-color: rgba(15,30,60,.07);
    }
    /* Кнопка «Запуск» в шапке группы Ганта — открывает попап со сценариями */
    .gantt-launch-btn {
      display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
      margin-left: 8px; height: 30px; padding: 0 12px; border-radius: 7px;
      border: none; background: #dde3ef; color: #2a4d7f;
      font-size: 12.5px; font-weight: 600; cursor: pointer; white-space: nowrap;
      transition: background .12s;
    }
    .gantt-launch-btn:hover { background: #d2dbea; }
    .gantt-launch-btn svg { color: #2a4d7f; }
    .launch-dd { z-index: 100; }
    /* «В работу»: создание задачи — первым пунктом, ниже поиск и триггеры */
    .work-dd { z-index: 3000; padding-top: 5px; }
    .work-dd .work-new { padding: 8px 12px; border-radius: 8px; margin: 0 5px; }
    .work-dd .new-menu-sep { margin: 5px 0 0; }
    /* Список действий длинный — отдаём ему больше высоты, чтобы меньше скроллить */
    .work-dd .fd-list { max-height: 460px; overflow-y: auto; }
    /* Вид «Потоки»: плоский список потоков — прячем шапки проектов, показываем все
       строки, имя процесса выводим справа в подписи. */
    /* Имя потока + имя сценария (зелёным) под ним */
    #wt-gantt .gantt-row .gantt-label .gn-col { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
    #wt-gantt .gn-col .gantt-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #wt-gantt .flow-scenario { font-size: 11px; line-height: 1.2; color: #8b95a5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #wt-gantt .flow-proj { display: none; }
    /* Чип кода в строке диаграммы — как везде, только высота от своей строки
       текста: фиксированная высота с line-height оставляла текст выше середины */
    #wt-gantt .gantt-row .gantt-label .item-id {
      /* Высота от собственной строки текста, как у чипа кода в списке задач:
         фиксированная высота с line-height оставляла текст выше середины */
      display: inline-block; padding: 2px 8px; border-radius: 5px; line-height: normal;
    }
    #wt-gantt.flows-view .gantt-group-head { display: none; }
    /* Шапки групп по типам потоков (Этапы / Потоки / Вайбы / Импорт) видны:
       ими и заменяется группировка по процессам */
    #wt-gantt.flows-view .gantt-group.ftype-group > .gantt-group-head { display: flex; }
    #wt-gantt.flows-view .gantt-group.ftype-group { margin-bottom: 8px; }
    #wt-gantt.flows-view .gantt-group.ftype-group.collapsed .gantt-row { display: none; }
    /* У потоков нет иерархии — кнопка «развернуть все проекты» не нужна */
    #wt-gantt.flows-view .gantt-toggle-all { display: none; }
    #wt-gantt.flows-view .gantt-group { margin-bottom: 0; }
    #wt-gantt.flows-view .gantt-group.collapsed .gantt-row { display: flex; }
    #wt-gantt.flows-view .gantt-row .gantt-label { padding-left: 12px; }
    /* Чип направления в строке диаграммы убран: направление и так видно
       по группе, а в плоском списке чип забивал название потока.
       Скрывает его правило #wt-gantt .flow-proj выше */
    /* В шапке группы кнопка живёт в мета-области по центру и видна только когда
       группа развёрнута (тогда gm-строки скрыты и место свободно) */
    .gantt-group-head .gantt-launch-btn {
      position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
      margin: 0; display: none;
    }
    .gantt-group:not(.collapsed) .gantt-group-head .gantt-launch-btn { display: inline-flex; }
    /* Кнопка «Запуск» перенесена в подпись проекта — компактная «+» справа от имени.
       Появляется при наведении на строку бледным плюсом, а под курсором — в обычном виде. */
    #wt-gantt .gantt-group-head .gantt-launch-btn.launch-in-label,
    #wt-spec .gantt-group-head .gantt-launch-btn.launch-in-label,
    #wt-people .gantt-group-head .gantt-launch-btn.launch-in-label {
      position: static; transform: none; display: inline-flex;
      align-items: center; justify-content: center; gap: 0;
      margin: 0 0 0 auto; width: 26px; height: 26px; padding: 0; flex-shrink: 0;
      opacity: 0; background: transparent;
      transition: opacity .12s, background .12s;
    }
    #wt-gantt .gantt-group-head .gantt-launch-btn.launch-in-label svg,
    #wt-spec .gantt-group-head .gantt-launch-btn.launch-in-label svg,
    #wt-people .gantt-group-head .gantt-launch-btn.launch-in-label svg { color: #9aa6b6; }
    /* наведение на строку — бледный плюс */
    #wt-gantt .gantt-group-head:hover .gantt-launch-btn.launch-in-label,
    #wt-spec .gantt-group-head:hover .gantt-launch-btn.launch-in-label,
    #wt-people .gantt-group-head:hover .gantt-launch-btn.launch-in-label { opacity: 1; }
    /* наведение на саму кнопку — обычный вид кнопки */
    /* Подложка плюса — полупрозрачное затемнение: на любой шапке (серой, розовой,
       жёлтой) она на тон темнее её собственного фона, как у .wf-chip */
    #wt-gantt .gantt-group-head .gantt-launch-btn.launch-in-label:hover,
    #wt-spec .gantt-group-head .gantt-launch-btn.launch-in-label:hover,
    #wt-people .gantt-group-head .gantt-launch-btn.launch-in-label:hover { opacity: 1; background: rgba(0,0,0,.09); }
    #wt-gantt .gantt-group-head .gantt-launch-btn.launch-in-label:hover svg,
    #wt-spec .gantt-group-head .gantt-launch-btn.launch-in-label:hover svg,
    #wt-people .gantt-group-head .gantt-launch-btn.launch-in-label:hover svg { color: #2a4d7f; }
    .gantt-chevron {
      flex-shrink: 0; color: var(--text-muted);
      transition: transform .2s;
    }
    .gantt-group.collapsed .gantt-chevron { transform: rotate(-90deg); }
    .gantt-group.collapsed .gantt-row { display: none; }

    /* «Исполнители»: загрузка сплайном по рабочим дням.
       Тонкие границы: низ (0) и уровень 100% максимальной загрузки */
    .load-chart { height: 30px; width: 100%; }
    .load-chart svg { display: block; width: 100%; height: 100%; }
    /* Границы 0 и 100% загрузки. Было #e3e7ee — против подложки шапок групп
       (#eef1f6) разница всего 11 единиц на канал, линии пропадали. Теперь тон
       глубже: читаются и на белых строках, и на группах */
    .lc-bound { stroke: #d3d9e4; stroke-width: 1; vector-effect: non-scaling-stroke; }
    .lc-seg { fill: none; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
    .lc-seg.fact { stroke: #1D9E75; }
    .lc-seg.plan { stroke: #b4bac4; }
    .lc-seg.bad { stroke: #e05252; stroke-width: 1.8; }
    .lc-team .lc-seg { stroke-width: 2.4; }        /* линии команд — жирнее */
    .lc-team .lc-seg.bad { stroke-width: 2.7; }
    /* Зона недели: подсветка по наведению + тултип с загрузкой */
    .lc-week { fill: transparent; cursor: pointer; }
    .lc-week:hover { fill: rgba(90, 120, 170, 0.10); }
    .lc-tip {
      display: none; position: fixed; z-index: 300; pointer-events: none;
      background: #1e2a3a; color: #fff; font-size: 11px; font-weight: 500;
      padding: 4px 9px; border-radius: 6px; white-space: nowrap;
      box-shadow: 0 4px 12px rgba(15, 30, 60, 0.25);
    }
    /* Фильтр диапазона дат (flatpickr) — в стиле остальных фильтров тулбара */
    .dr-input {
      flex-shrink: 0; width: 86px; box-sizing: border-box;
      border: 1px solid var(--border); border-radius: 6px; background-color: #fff;
      padding: 4px 22px 4px 27px; font: inherit; font-size: 12px; font-weight: 500;
      color: var(--text-secondary); cursor: pointer;
      background-image:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='13' height='13' fill='none' stroke='%236b7a8f' stroke-width='2' viewBox='0 0 24 24'><rect x='3' y='4' width='18' height='18' rx='2'/><line x1='16' y1='2' x2='16' y2='6'/><line x1='8' y1='2' x2='8' y2='6'/><line x1='3' y1='10' x2='21' y2='10'/></svg>"),
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='11' height='11' fill='none' stroke='%236b7a8f' stroke-width='2.5' viewBox='0 0 24 24'><polyline points='6 9 12 15 18 9'/></svg>");
      background-repeat: no-repeat, no-repeat;
      background-position: 9px center, right 7px center;
      transition: all 0.15s;
    }
    .dr-input:hover, .dr-input:focus { border-color: var(--purple-mid); color: var(--text-primary); outline: none; }
    .dr-input::placeholder { color: var(--text-secondary); }
    /* Календарь flatpickr — компактнее: мельче шрифт и ячейки, уже диалог */
    .flatpickr-calendar { width: 232px; font-size: 12px; }
    .flatpickr-days { width: 232px; }
    .dayContainer { width: 232px; min-width: 232px; max-width: 232px; padding: 0 4px 4px; }
    .flatpickr-day { flex-basis: 14.2857%; max-width: 14.2857%; height: 28px; line-height: 28px; font-size: 11.5px; }
    .flatpickr-months .flatpickr-month { height: 32px; }
    .flatpickr-current-month {
      height: 32px; padding: 0; font-size: 105%;
      display: flex; align-items: center; justify-content: center;
    }
    .flatpickr-current-month .flatpickr-monthDropdown-months { height: auto; padding: 2px 0 2px 2px; }
    .flatpickr-current-month input.cur-year { padding: 0 0 0 4px; }
    .flatpickr-months .flatpickr-prev-month, .flatpickr-months .flatpickr-next-month {
      height: 32px; padding: 0 8px; display: flex; align-items: center;
    }
    span.flatpickr-weekday { font-size: 10.5px; }
    .gantt-group-head .load-chart { height: 34px; }
    #wt-people .gantt-row { cursor: default; }
    /* Аватар и чип профиля в строке участника */
    /* Первая колонка одинаковой ширины в обоих режимах; ширину тянут за её правый
       край. По умолчанию — треть таблицы, а не фикс в px: доля держится при любой
       ширине окна и при открытом чате. Перетаскивание кладёт в --people-col px
       и с этого момента задаёт ширину само */
    #wt-people .gantt-label {
      flex: 0 0 var(--people-col, 33.333%);
      width: var(--people-col, 33.333%);
      min-width: 0; max-width: none;
    }
    #wt-people .gantt-head .gantt-label { position: sticky; }
    /* График загрузки не может вылезти за свою колонку: липкая «Скорость» справа
       перекрывает трек z-index'ом, но при быстрой горизонтальной прокрутке
       браузер успевает показать кусок графика до перерисовки липкого слоя.
       Обрезка по треку убирает саму возможность — на «Исполнителях» в треке
       только график, ничего наружу торчать не должно */
    #wt-people .gantt-track { overflow: hidden; }
    .people-col-resizer {
      position: absolute; top: 0; bottom: 0; right: -3px; width: 6px; z-index: 6;
      cursor: col-resize;
    }
    .people-col-resizer::after {
      content: ''; position: absolute; top: 0; bottom: 0; left: 2px; width: 2px;
      background: transparent; border-radius: 1px; transition: background .12s;
    }
    .people-col-resizer:hover::after, body.people-col-resizing .people-col-resizer::after { background: #c9d2e4; }
    body.people-col-resizing { cursor: col-resize; user-select: none; }
    #wt-people .gantt-label .mini-ava { width: 20px; height: 20px; font-size: 8.5px; flex-shrink: 0; }
    #wt-people .gantt-row .gantt-label .ichip { margin-left: auto; flex-shrink: 0; }
    /* «Исполнители»: правая колонка «Индекс» + чип себестоимости условного часа */
    /* Чип прижат к правой линии колонки с отступом 13px — как чип
       специальности в первой колонке */
    .perf-col { width: 77px; flex-shrink: 0; box-sizing: border-box; display: flex; align-items: center; justify-content: flex-end; padding-right: 13px; font-size: 12.5px; font-weight: 600; }
    /* «Индекс» приколот к правому краю — при горизонтальной прокрутке едут только полоски
       (та же механика, что у колонки сумм .gantt-meta) */
    #wt-people .perf-col { position: sticky; right: 0; z-index: 3; background: inherit; border-left: 1px solid var(--border); }
    #wt-people .gantt-row .perf-col { border-radius: 0 var(--r) var(--r) 0; }
    /* «Цена» — своя колонка слева от «Скорости», приколота вместе с ней.
       Ширина — по чипу цены, без боковых полей */
    .cost-col {
      width: 58px; flex-shrink: 0; box-sizing: border-box;
      display: flex; align-items: center; justify-content: center; padding: 0;
      font-size: 12.5px; font-weight: 600;
    }
    #wt-people .cost-col { position: sticky; right: 66px; z-index: 3; background: inherit; border-left: 1px solid var(--border); }
    /* Команды на «Исполнителях» — как потоки на «Потоках задач»: шеврон
       первым в строке, шапка — белой карточкой с рамкой, раскрытая команда
       помечается тоном подложки. Капитель снята — читается как имя, не рубрика */
    #wt-people .gantt-group-head .gantt-label > .gantt-chevron { order: -1; }
    #wt-people .gantt-group-head { background: #fff; border: 1px solid var(--border); }
    #wt-people .gantt-group-head:hover { background: #fff; border-color: var(--border-mid); }
    #wt-people .gantt-group:not(.collapsed) > .gantt-group-head,
    #wt-people .gantt-group:not(.collapsed) > .gantt-group-head:hover { background: var(--backdrop); }
    #wt-people .gantt-group-head .sec-label {
      text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 600;
    }

    /* «Цена» и «Скорость» — сразу за первой колонкой (порядок флексом),
       липнуть к правому краю им больше не нужно. Прячутся кнопкой в шапке */
    /* Левой линии у «Цены» нет: разделитель уже рисует первая колонка,
       вторая давала двойную черту */
    /* Липнут к левому краю сразу за колонкой имени — как колонка итогов на
       «Задачах»: при горизонтальной прокрутке шкалы цифры остаются на месте.
       Зазор строки между ними убран, воздух дают собственные поля колонок:
       через прозрачный зазор проглядывала уезжающая шкала */
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) { column-gap: 0; }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > :is(.cost-col, .perf-col) {
      /* Поля одинаковые с обеих сторон — чип стоит по центру колонки */
      padding-left: 13px; padding-right: 13px;
    }
    /* Ширина — с учётом этих полей: при прежних 58px чип со ставкой упирался
       в края колонки и вылезал за них */
    /* Ширину меряет JS по самому широкому чипу колонки (peopleColsFit),
       26px — поля колонки по 13px с каждой стороны; запасные значения, если
       мерить ещё нечего */
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .cost-col {
      width: calc(var(--people-cost-w, 71px) + 26px);
    }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .perf-col {
      width: calc(var(--people-perf-w, 65px) + 26px);
    }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-track { margin-left: 12px; }
    /* У шапки группы своя рамка в 1px: без поправки прилипшие колонки вставали
       на пиксель левее, чем стояли в покое, и содержимое дёргалось */
    #wt-people .gantt-group-head > .gantt-label { left: 1px; }
    #wt-people .gantt-group-head > .cost-col { left: calc(var(--people-col-px, 335px) + 1px); }
    #wt-people .gantt-group-head > .perf-col { left: calc(var(--people-perf-px, 405px) + 1px); }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .cost-col {
      order: 1; border-left: none;
      position: sticky; left: var(--people-col-px, 335px); z-index: 3; background: inherit;
    }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .perf-col {
      order: 2; border-right: 1px solid var(--border);
      position: sticky; left: var(--people-perf-px, 405px); z-index: 3; background: inherit;
    }
    #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-track { order: 3; }
    #wt-people .gantt-row .perf-col { border-radius: 0; }
    /* Кнопка прячет сами колонки «Цена» и «Скорость» — графики загрузки
       остаются и забирают освободившуюся ширину. Поле слева у шкалы держало
       зазор с колонкой цифр: без них оно ни к чему */
    #wt-people.cols-hidden :is(.gantt-head, .gantt-row, .gantt-group-head) > :is(.cost-col, .perf-col) {
      display: none;
    }
    #wt-people.cols-hidden :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-track { margin-left: 0; }
    /* В узкой области графики прячет медиазапрос — тогда «Цена» и «Скорость»
       липнуть не к чему: держим их у правого края строки, иначе справа
       от них оставалась пустая полоса шириной со шкалу */
    @media (max-width: 559px) {
      /* Графики убрал медиазапрос — имени тоже незачем жаться в треть */
      #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-label {
        flex: 1 1 auto; width: auto;
      }
      #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .cost-col {
        position: static; margin-left: auto;
      }
      #wt-people :is(.gantt-head, .gantt-row, .gantt-group-head) > .perf-col { position: static; }
      #wt-people :is(.gantt-head, .gantt-group, .gantt-group-head, .gantt-row, .gantt-weekgrid) {
        min-width: 100%;
      }
    }
    /* Стрелка показывает, что случится по клику: колонки на месте — она
       смотрит влево (свернуть их к имени), спрятаны — вправо (вернуть) */
    .perf-cols-toggle svg { transform: rotate(180deg); transition: transform .15s; }
    .perf-cols-toggle.cols-off svg { transform: none; }

    /* Скорость — таким же чипом, как цена, только цвет по значению.
       Боковые поля — как у чипа цены на вид: проценту одному в чипе было
       тесно; сама цена — чуть компактнее */
    .perf-chip { background: #eef0f4; padding: 3px 14px; }
    .cost-chip { padding: 3px 6px; }
    .perf-chip.perf-good { color: #1f9d63; }
    .perf-chip.perf-mid  { color: #b07d12; }
    .perf-chip.perf-low  { color: #c23a35; }
    /* Подписи колонок шапки — обычным регистром, с заглавной буквы */
    /* Ячейка в две строки: диапазон времени, под ним часовой пояс */
    .proj-data-val.val-stack { flex-direction: column; align-items: flex-end; gap: 6px; }
    /* Имя периода правится на месте */
    .src-name.editable { cursor: text; border-radius: 6px; }
    .src-name.editable:hover { background: #f1f4f9; box-shadow: 0 0 0 4px #f1f4f9; }
    .src-name.name-edit { outline: none; background: #fff; box-shadow: 0 0 0 1px var(--purple-mid, #9aa7bf), 0 0 0 4px #fff; }
    /* Имя добавленного параметра правится на месте — та же подсветка, что у имени
       источника. Строка инструкции сюда не входит: это ссылка, а не параметр, её
       название принадлежит самой инструкции (JS её тоже не пускает в правку) */
    .proj-data-field[data-removable]:not(.instr-row) > .proj-data-label,
    .proj-data-field:not(.instr-row):has(> [onclick*="removeDataField"]) > .proj-data-label { cursor: text; border-radius: 6px; }
    .proj-data-field[data-removable]:not(.instr-row) > .proj-data-label:hover,
    .proj-data-field:not(.instr-row):has(> [onclick*="removeDataField"]) > .proj-data-label:hover { background: #f1f4f9; box-shadow: 0 0 0 4px #f1f4f9; }
    .proj-data-label.name-edit { outline: none; background: #fff; box-shadow: 0 0 0 1px var(--purple-mid, #9aa7bf), 0 0 0 4px #fff; }
    /* Текст не упирается в рамку поля — боковые отступы внутри неё */
    .src-name.name-edit,
    .proj-data-label.name-edit { padding-left: 8px; padding-right: 8px; }
    /* Поле правки — по ширине содержимого: строка параметра не перестраивается,
       значение остаётся на своём месте */
    .proj-data-label.name-edit { flex: 0 1 auto; max-width: 100%; min-width: 0; }
    /* Пока правят имя, крестик удаления параметра прячется, вместо него — очистка имени */
    .proj-data-field.name-editing > .proj-data-del { display: none; }
    /* Поле во всю ширину выдавливало значки справа на пустую вторую строку под ним.
       Стрелку на время правки прячем, крестик очистки кладём поверх поля */
    .proj-data-field.name-editing { position: relative; }
    .proj-data-field.name-editing > svg { display: none; }
    .proj-data-field.name-editing > .name-clear { margin: 0; }
    .name-clear {
      display: none; background: none; border: none; cursor: pointer;
      color: var(--text-muted); padding: 2px; border-radius: 4px;
      align-items: center; flex-shrink: 0;
    }
    .proj-data-field.name-editing > .name-clear { display: flex; }
    .name-clear:hover { color: var(--text-primary); background: #f1f4f9; }
    .proj-data-field.field-stacked > .name-clear,
    .proj-data-field.auto-stacked > .name-clear { position: absolute; top: 8px; right: 12px; margin: 0; }
    .proj-data-field.field-stacked:not(:has(> .proj-data-val)) > .name-clear,
    .proj-data-field.auto-stacked:not(:has(> .proj-data-val)) > .name-clear { top: 50%; transform: translateY(-50%); }
    /* Пустое поле правки подсказывает, что в него вводят */
    .name-edit.is-empty::before { content: attr(data-ph); color: #b3bdca; }
    .pill-val.name-edit { min-width: 6em; display: inline-block; }
    /* Период, пришедший из графика работы: только для чтения — контролы
       внутри не кликаются, крестика удаления нет */
    .field-stacked.from-sched :is(.sched-dates, .sched-parity, .wd) { pointer-events: none; }
    /* Только чтение — строка обесцвечена: видно, что править нечего */
    .field-stacked.from-sched .sched-row { filter: grayscale(1); opacity: .75; }
    .field-stacked.from-sched .sched-dates .spec-x { display: none; }
    /* Чип специальности у навыка — тоже служебная пометка, не статус */
    #memberSkills .ichip.ichip-role { background-color: #eef0f4; color: #50607a; }
    /* Чип с именем графика — служебная пометка, а не статус: тот же серый,
       что у чипа диапазона дат */
    .field-stacked .ichip.ichip-role.src-type { background: #eef0f4; color: #50607a; }
    .field-stacked.from-sched .src-type { cursor: default; }
    /* Рабочий график исполнителя: расписание шире параметров — 60 на 40 */
    #member-schedule > .proj-data-grid { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
    /* Счётчик участников в шапке графика — нейтральный, без цвета */
    #schedUsers { background: rgba(15,30,60,.05); color: #6b7a8f; font-weight: 500; }
    /* Страница графика работы: как в «Рабочем графике» исполнителя — 60 на 40 */
    body[data-page="schedule"] .proj-data-grid { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
    /* Подпись колонки исполнителей в шапке диаграммы */
    .people-head-cap { font-size: 11px; font-weight: 500; color: var(--text-muted); letter-spacing: .02em; white-space: nowrap; }
    .perf-head { color: var(--text-muted); font-weight: 500; font-size: 10.5px; letter-spacing: .02em; }
    .perf-good { color: #1f9d63; }
    .perf-mid  { color: #b07d12; }
    .perf-low  { color: #c23a35; }
    .cost-chip { background: #eef0f4; color: #50607a; }
    /* Самый дорогой час в специальности — розовый чип с тёмно-красной цифрой */
    .cost-chip.cost-top { background: #fde8e6; color: #993536; }
    #wt-people .gantt-row .gantt-label .cost-chip { margin-left: 6px; }
    /* Вид «Исполнители»: плоский список — шапки команд скрыты, строки видны всегда,
       под именем — команды участника (основная выделена) */
    #wt-people.people-flat .gantt-group-head { display: none; }
    #wt-people.people-flat .gantt-group { margin-bottom: 0; }
    #wt-people.people-flat .gantt-group.collapsed .gantt-row { display: flex; }
    /* Секции «Сотрудники» / «Агенты» — единственные шапки в плоском режиме,
       и сворачиваются они по-настоящему */
    /* Отступы оставляем командные (10/6): в шапке теперь свой график загрузки,
       он и уравновешивает надпись — как у групп на вкладке «Команды» */
    #wt-people.people-flat .people-kind > .gantt-group-head { display: flex; }
    #wt-people.people-flat .people-kind { margin-bottom: 10px; }
    #wt-people.people-flat .people-kind.collapsed .gantt-row { display: none; }
    #wt-people.people-flat .gantt-row .gantt-label { padding-left: 12px; }
    #wt-people .pn-col { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
    /* Чипы команд под именем исполнителя не показываем: в группировке по типам
       строка и без них читается, а команда видна в фильтре и в группировке */
    #wt-people .pn-teams { display: none; gap: 4px; flex-wrap: wrap; }
    /* Ширина по содержимому, но не шире 80px — длинное имя обрезает JS через «..» */
    #wt-people .pn-team {
      font-size: 10.5px; line-height: 1.5; padding: 0 6px; border-radius: 4px;
      background: #eef1f6; color: #8b95a5; white-space: nowrap;
      max-width: 80px; overflow: hidden; font-weight: 400;
    }
    /* Основная команда — как чип команды на карточке сотрудника (.ichip-role).
       Модификатор именно pn-main: глобальный класс .main — контейнер страницы, он бы сломал чип */
    #wt-people .pn-team.pn-main { background: #eef1fb; color: #5560c9; }
    #wt-people .pn-team.none { background: transparent; padding-left: 0; font-style: italic; }
    /* Легенда закреплена при вертикальной прокрутке, шкала месяцев — сразу под ней.
       Фон — всегда подложка области (--area-bg), а не фон страницы: липкая полоса
       непрозрачна, и на затемнённой подложке фикс #f6f7fa выделялся светлой лентой.
       Вне области с чатом --area-bg и так равна фону страницы, так что ничего не меняется */
    /* Легенда стоит под фильтрами, прямо над таблицей: поля сверху и снизу
       одинаковые, липнет она следом за тулбаром */
    #wt-people .gantt-legend {
      position: sticky; top: 52px; z-index: 14; background: var(--area-bg);
      /* Сверху воздух даёт нижнее поле тулбара, снизу — своё: поровну.
         Содержимое прижато вправо и без правого поля — как кнопки тулбара */
      padding: 0; margin-bottom: 10px; justify-content: flex-end; flex-wrap: wrap;
    }
    /* Цвета — своей строкой под пилюлями: в общей строке они отжимали масштаб */
    #wt-people .gl-row {
      order: 2; flex-basis: 100%; display: flex; gap: 10px;
      justify-content: flex-start; margin-top: 6px;
    }
    #wt-people .gantt-legend > :not(.gl-row, .people-add) { order: 1; }
    /* Высота строк фиксирована: что бы ни появилось по наведению (чекбокс,
       кнопки), список не должен дёргаться */
    /* Высота с запасом под чип «···»: он на 22px и в строке 34px растягивал её
       на пару пикселей — список дёргался под курсором */
    #wt-people :is(.gantt-row, .gantt-group-head) { min-height: 36px; box-sizing: border-box; }
    #wt-people .gantt-headwrap { top: 92px; }
    /* На «Потоках» тот же стек, но под липким тулбаром: его высоту меряет JS (--gtb-h) */
    #wt-gantt .gantt-legend {
      position: sticky; top: var(--gtb-h, 52px); z-index: 15; background: var(--area-bg);
    }
    #wt-gantt .gantt-headwrap { top: calc(var(--gtb-h, 52px) + 30px); }
    /* Нижний зазор убран: из-за него полоса-дублёр «отлипала» на последних
       пикселях вертикальной прокрутки и прыгала вверх-вниз */
    #viewWorkTasks .body-area { padding-bottom: 0; }
    #wt-all { padding-bottom: 6px; }

    /* Ганта/Исполнители: шапка (фильтры, легенда, шкала) статична — вертикальный
       скролл живёт внутри области строк, поэтому полоса прокрутки начинается под шапкой */
    #viewWorkTasks .content.gantt-scroll { display: flex; flex-direction: column; overflow: hidden; }
    #viewWorkTasks .content.gantt-scroll > .body-area { flex: 1; min-height: 0; display: flex; flex-direction: column; }
    .wt-panel.scroll-host { flex: 1; min-height: 0; display: flex; flex-direction: column; }
    /* Вкладка «Работы» — та же диаграмма в Конфигурации, направлении и потоке.
       Внутренней прокрутки «Выполнения» там нет: липкие полосы прятались под
       шапкой страницы, поэтому легенда, тулбар и шкала едут вместе со страницей */
    #wt-gantt:is(.ws-panel, .proj-panel, .task-panel)
      > :is(.gantt-toolbar, .gantt-legend, .gantt-headwrap) { position: static; }
    #wt-gantt.scroll-host > .gantt-toolbar,
    #wt-gantt.scroll-host > .gantt-legend,
    #wt-gantt.scroll-host > .gantt-headwrap,
    #wt-people.scroll-host > .gantt-legend,
    #wt-people.scroll-host > .gantt-headwrap { position: static; flex-shrink: 0; }
    .wt-panel.scroll-host > .gantt,
    .wt-panel.scroll-host > #wt-flowlist {
      flex: 1; min-height: 0; overflow: auto;
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
    }
    .wt-panel.scroll-host > .gantt::-webkit-scrollbar,
    .wt-panel.scroll-host > #wt-flowlist::-webkit-scrollbar { width: 5px; height: 5px; }
    .wt-panel.scroll-host > .gantt::-webkit-scrollbar-thumb,
    .wt-panel.scroll-host > #wt-flowlist::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }
    .wt-panel.scroll-host > .gantt-scrollbar { display: none; }

    /* Алгоритм пометки отстающих проектов:
       .behind-flows  — в проекте есть потоки с нарушением базы, но сам проект в плане:
                        счётчик розовый, линия выполнения проекта остаётся зелёной.
       .behind-project — сам проект отстаёт от базы:
                        счётчик розовый, линия выполнения проекта — красная. */
    /* У проблемных групп цифра красная, а подложка — то же затемнение шапки:
       плотный розовый чип сливался с розовой шапкой отстающего процесса */
    .gantt-group.behind-flows .count-chip,
    .gantt-group.behind-project .count-chip { background: rgba(15,30,60,.07); color: #c23a35; }
    .gantt-warn { display: inline-flex; align-items: center; color: var(--red); flex-shrink: 0; }

    /* Статус показываем цветом ТЕКСТА имени процесса/потока (подложку «прошлого» убрали):
       норма / в плане — зелёный, отстаёт по прогнозу — жёлтый, отстаёт от базы или
       поток отстал — красный. Код (ID) остаётся чёрным. */
    #wt-gantt .gantt-group-head .sec-label,
    #wt-gantt .gantt-row .gantt-name { color: #111; }
    /* Отставание по прогнозу — то же решение, что у отставших от базы, только
       жёлтой гаммой: имя чёрное, шапка на светло-жёлтой подложке, код — из гаммы */
    #wt-gantt .gantt-group.behind-forecast > .gantt-group-head .sec-label { color: #111; }
    #wt-gantt .gantt-group.behind-forecast > .gantt-group-head,
    #wt-gantt .gantt-group.behind-forecast > .gantt-group-head .gantt-label { background: #fdf3e2; }
    /* Отставший от базы процесс: имя чёрное, а сама шапка на розоватой подложке —
       так статус читается пятном, а не только цветом текста */
    #wt-gantt .gantt-group.behind-project  > .gantt-group-head .sec-label { color: #111; }
    /* Подложку красим и на липкой левой колонке — иначе фон обрывался при скролле */
    #wt-gantt .gantt-group.behind-project  > .gantt-group-head,
    #wt-gantt .gantt-group.behind-project  > .gantt-group-head .gantt-label { background: #fde8e6; }
    #wt-gantt .gantt-row.flow-late .gantt-name,
    .gantt-row.flow-late .gantt-name { color: #c23a35; }

    /* Полоса факта в шапке отстающего по прогнозу проекта — жёлтая (а не красная) */
    .gantt-group.behind-forecast > .gantt-group-head .gantt-bar.fact.bad { background: #f7e3b3; }
    .gantt-group.behind-forecast > .gantt-group-head .gantt-bar.fact.bad .gantt-bar-fill { background: #d99a2b; }
    .gantt-group.behind-forecast > .gantt-group-head .gm-row.bad > b { color: #a36a18; }
    /* Панель действий отстающего проекта — видна только при раскрытии,
       приколота к левому краю, чтобы кнопки не уезжали при горизонтальном скролле */
    /* Подпись и кнопка «Советник» вместе прижаты к правому краю */
    .gantt-actions {
      display: flex; align-items: center; justify-content: flex-end;
      padding: 9px 0 5px;
    }
    .gantt-group.collapsed .gantt-actions { display: none; }
    .ga-note {
      display: inline-flex; align-items: center; gap: 6px;
      font-size: 12px; font-weight: 600; color: #c23a35; white-space: nowrap;
    }
    .ga-btns {
      position: sticky; right: 0; padding-right: 12px;
      display: flex; align-items: center; gap: 10px;
    }
    .ga-btn {
      display: inline-flex; align-items: center; gap: 6px;
      height: 30px; padding: 0 12px; border-radius: 7px;
      border: 1px solid var(--border-mid); background: #fff; color: #3d4655;
      font-size: 12.5px; font-weight: 600; cursor: pointer; transition: all .15s; white-space: nowrap;
    }
    .ga-btn:hover { background: #f5f7fa; border-color: #9aa6b8; }
    .ga-btn svg { opacity: .7; }
    .ga-btn.primary { background: #e1f5ee; border-color: #9fe1cb; color: #0f6e56; }
    .ga-btn.primary:hover { background: #d3efe4; }
    .ga-btn.primary svg { opacity: .85; }
    /* Развёрнутый проект: итог по срокам/часам/сумме прячем — его показывают сами потоки.
       visibility (а не display) — чтобы колонка держала ширину и раскладка не поехала */
    /* У раскрытого проекта цифры не нужны, но сама колонка обязана остаться:
       она непрозрачной шапкой перекрывает полосы, уезжающие под неё при скролле.
       visibility на .gantt-meta убрал бы вместе с текстом и фон. */
    .gantt-group:not(.collapsed) .gantt-group-head .gm-row { visibility: hidden; }

    .gantt-row {
      padding: 7px 0; border-radius: var(--r);
      cursor: pointer; transition: background .12s;
    }
    /* Подсветка строки под курсором — тем же тоном, что у дерева работ
       (.tr-row:hover): прежний #f1f4f9 читался заливкой, а не подсказкой,
       где сейчас мышь */
    .gantt-row:hover { background: var(--area-bg); }
    /* Отступ вложенных потоков — иерархия под группой */
    .gantt-row .gantt-label { padding-left: 34px; }   /* 12 отступ + 22 вложенность */
    /* Проектный Гант: строки не вложены в группы — убираем лишний левый отступ */
    #proj-exec .gantt-row .gantt-label { padding-left: 12px; }
    /* «Списком»: групп нет, все потоки на одном уровне — вложенный отступ не нужен */
    #wt-gantt .gantt > .gantt-row .gantt-label { padding-left: 12px; }

    /* Вертикальная сетка месяцев за барами. Первой линии (0%) здесь нет — её роль
       играет закреплённый разделитель на колонке имени (не скроллится). Остальные
       линии — на стыках месяцев 20/40/60/80% — едут вместе со шкалой. */
    .gantt-row .gantt-track::before,
    .gantt-group-head .gantt-track::before {
      content: ''; position: absolute; inset: 0; pointer-events: none;
      background-image: linear-gradient(to right,
        transparent 20%, var(--border) 20% calc(20% + 1px),
        transparent calc(20% + 1px) 40%, var(--border) 40% calc(40% + 1px),
        transparent calc(40% + 1px) 60%, var(--border) 60% calc(60% + 1px),
        transparent calc(60% + 1px) 80%, var(--border) 80% calc(80% + 1px),
        transparent calc(80% + 1px));
    }
    /* Подложку «прошедшего периода» убрали — статус теперь передаётся цветом имени
       (см. выше). За барами остаётся только сетка месяцев из базового .gantt-track::before. */
    /* Потоки — тонкие полосы */
    .gantt-lane { position: relative; height: 5px; }
    .gantt-bar {
      position: absolute; top: 0; height: 5px; border-radius: 2px;
      min-width: 4px; cursor: default;
    }
    /* Итог по проекту/пространству — те же полосы, но толще */
    .gantt-lane.thick { height: 10px; }
    .gantt-bar.thick { height: 10px; border-radius: 3px; }
    .gantt-bar.plan { background: #d3dae5; }
    /* Полоса факта — светлая подложка (затраченное время),
       заливка внутри — сколько реально выполнено на данный момент */
    .gantt-bar.fact { background: #a9e5d7; }
    .gantt-bar.fact.bad { background: #f7c2bd; }
    /* Ещё не начатый поток: показываем плановый период полосой цвета «План» из легенды (без заливки) */
    .gantt-bar.fact.not-started { background: #a9e5d7; }
    .gantt-bar-fill {
      display: block; height: 100%; border-radius: inherit;
      background: var(--teal);
    }
    .gantt-bar.fact.bad .gantt-bar-fill { background: var(--red); }

    .gm-row {
      display: flex; align-items: center; gap: 6px;
      font-size: 11.5px; color: var(--text-secondary); white-space: nowrap;
    }
    /* Колонка стоимости — без цветных пилюль и жирных цифр, чтобы не рябило:
       подписи «База/План» — тихим серым, суммы обычным начертанием,
       цвет остаётся только у сумм отстающих (красный/жёлтый) */
    .gm-row b { color: var(--text-primary); font-weight: 400; }
    .gantt-row .gm-row b { font-weight: 400; }
    /* Три колонки итогов: сроки тянутся, часы и стоимость — фиксированной
       ширины и по правому краю, чтобы цифры строк стояли друг под другом */
    .gm-dates { flex: 1 1 auto; }
    .gm-hours { flex: 0 0 46px; width: 46px; text-align: right; }
    .gm-money { flex: 0 0 88px; width: 88px; text-align: right; }
    .gm-row :is(.gm-hours, .gm-money) { color: var(--text-primary); }
    .gm-row.muted :is(.gm-dates, .gm-wide) { color: var(--text-muted); }
    .gm-row.bad :is(.gm-hours, .gm-money) { color: var(--red); }
    /* Строка без цифр («Не начата») занимает все три колонки, а кнопка
       сохранения базы остаётся по своему содержимому */
    .gm-wide { flex: 1 1 auto; }
    .gm-save-btn.gm-wide { flex: 0 0 auto; margin-right: auto; }
    /* Заголовки колонок — той же сеткой, что и строки */
    .gm-row.gm-head { color: var(--text-muted); }
    .gm-row.gm-head :is(.gm-hours, .gm-money) { color: inherit; }
    .gm-row.muted { color: var(--text-muted); }
    .gm-tag {
      flex-shrink: 0; width: 38px;
      font-size: 10px; font-weight: 500; letter-spacing: .2px;
      text-align: left; padding: 2px 0; border-radius: 4px;
      color: var(--text-muted);
    }
    .gm-tag.plan { background: transparent; color: var(--text-muted); }
    /* База не сохранена: вместо цифр — кнопка сохранения базового плана */
    .gm-save-btn {
      border: 1px solid #9fdbe0; cursor: pointer; flex-shrink: 0;
      background: #e1f2f4; color: #0098a6;
      font-size: 10.5px; font-weight: 600; line-height: 1.4;
      padding: 2px 9px; border-radius: 9px;
      transition: background .12s, border-color .12s;
    }
    .gm-save-btn:hover { background: #d2ebee; border-color: #7fccd3; }
    .gm-tag.fact { background: transparent; color: var(--text-muted); }
    .gm-tag.fact.bad { background: transparent; color: var(--text-muted); }
    .gm-tag.fact.none { background: transparent; color: #aeb6c2; }


    /* ── Вкладка «Сравнение»: текущий план против базового ── */
    #wt-compare { padding: 4px 2px 20px; }

    /* Сводка драйверов сверху — отвечает на «почему» */
    .cmp-summary { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
    .cmp-verdict {
      flex: 1 1 240px; display: flex; flex-direction: column; gap: 3px;
      padding: 12px 16px; border-radius: 12px;
      background: #fff; border: 1px solid var(--border);
      box-shadow: 0 1px 2px rgba(5,28,59,.04), 0 4px 16px rgba(5,28,59,.05);
      border-left: 4px solid var(--text-muted);
    }
    .cmp-verdict.bad  { border-left-color: var(--red); }
    .cmp-verdict.good { border-left-color: var(--teal); }
    .cmp-verdict-h { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
    .cmp-verdict-v { font-size: 18px; font-weight: 700; color: var(--text-primary); }
    .cmp-verdict.bad .cmp-verdict-v  { color: #c23a35; }
    .cmp-verdict.good .cmp-verdict-v { color: #0f7a63; }
    .cmp-verdict-s { font-size: 12px; color: var(--text-secondary); }

    .cmp-drivers { flex: 2 1 480px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
    .cmp-driver {
      display: flex; flex-direction: column; gap: 3px;
      padding: 12px 14px; border-radius: 12px;
      background: #fff; border: 1px solid var(--border);
      box-shadow: 0 1px 2px rgba(5,28,59,.04), 0 4px 16px rgba(5,28,59,.05);
    }
    .cmp-driver-h { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
    .cmp-driver-v { font-size: 16px; font-weight: 700; color: var(--text-primary); }
    .cmp-driver-v.bad  { color: #c23a35; }
    .cmp-driver-v.good { color: #0f7a63; }
    .cmp-driver-s { font-size: 11.5px; color: var(--text-secondary); }

    /* Легенда */
    .cmp-legendbar { display: flex; gap: 18px; flex-wrap: wrap; align-items: center; padding: 0 4px 10px; }
    .cmp-lg { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary); }
    .cmp-sw { width: 22px; height: 6px; border-radius: 3px; }
    .cmp-sw.base { background: #d3dae5; }
    .cmp-sw.cur  { background: var(--teal); }

    /* Дельта-таблица */
    .cmp-table { display: flex; flex-direction: column; }
    .cmp-group { border-radius: 10px; margin-bottom: 4px; }
    .cmp-group-head, .cmp-row, .cmp-total {
      display: flex; align-items: center; gap: 10px;
      padding: 9px 14px; border-radius: 8px;
    }
    .cmp-group-head {
      background: #eef0fa; margin-top: 6px;
    }
    .cmp-group-head .cmp-title { color: #414c9e; font-weight: 600; }
    .cmp-row { margin-left: 14px; }
    .cmp-row:hover { background: #f4f6fb; }
    .cmp-row.same { opacity: .62; }
    .cmp-group.ungrouped .cmp-row { margin-left: 0; }

    .cmp-name { flex: 1 1 150px; min-width: 116px; display: flex; align-items: center; gap: 8px; overflow: hidden; }
    .cmp-title { font-size: 13px; font-weight: 500; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .cmp-col { flex: 1 1 128px; min-width: 104px; display: flex; flex-direction: column; gap: 1px; }
    .cmp-col.base { color: var(--text-muted); }
    .cmp-dates { font-size: 12px; white-space: nowrap; }
    .cmp-fig { font-size: 12.5px; font-weight: 600; white-space: nowrap; }
    .cmp-col.base .cmp-fig { font-weight: 500; }
    .cmp-arrow { flex: 0 0 auto; color: var(--text-muted); font-size: 13px; }
    .cmp-delta { flex: 1 1 150px; min-width: 96px; display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }

    /* Бейджи отклонений */
    .cmp-d {
      font-size: 11px; font-weight: 600; white-space: nowrap;
      padding: 2px 8px; border-radius: 20px;
    }
    .cmp-d.bad  { background: #fde5e5; color: #c23a35; }
    .cmp-d.good { background: #e1f5ee; color: #0f7a63; }
    .cmp-d.zero { background: #f2f3f6; color: #98a2b3; }

    .cmp-total {
      margin-top: 8px; padding-top: 12px;
      border-top: 1px solid var(--border);
    }
    .cmp-total .cmp-title { font-weight: 700; font-size: 13.5px; }
    .cmp-total .cmp-fig { font-weight: 700; }


    /* ── Вкладка «Состояние»: причина + сигнал + рекомендация в одной карточке ── */
    #wt-state { padding: 4px 2px 22px; }
    .st-head {
      display: flex; flex-direction: column; gap: 3px;
      padding: 12px 16px; margin-bottom: 14px; border-radius: 12px;
      background: #fff; border: 1px solid var(--border); border-left: 4px solid var(--text-muted);
      box-shadow: 0 1px 2px rgba(5,28,59,.04), 0 4px 16px rgba(5,28,59,.05);
    }
    .st-head.sev-high { border-left-color: var(--red); }
    .st-head-h { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); }
    .st-head-v { font-size: 18px; font-weight: 700; color: var(--text-primary); }
    .st-head.sev-high .st-head-v { color: #c23a35; }
    .st-head-s { font-size: 12.5px; color: var(--text-secondary); }

    .st-list { display: flex; flex-direction: column; gap: 10px; }
    .st-card {
      padding: 12px 16px; border-radius: 12px;
      background: #fff; border: 1px solid var(--border); border-left: 4px solid var(--text-muted);
      box-shadow: 0 1px 2px rgba(5,28,59,.04), 0 4px 16px rgba(5,28,59,.05);
    }
    .st-card.sev-high { border-left-color: var(--red); }
    .st-card.sev-med  { border-left-color: #f0a04b; }
    .st-card.sev-low  { border-left-color: #cbd2dc; }

    .st-top { display: flex; align-items: center; gap: 9px; margin-bottom: 7px; }
    .st-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; background: var(--text-muted); }
    .sev-high .st-dot { background: var(--red); }
    .sev-med  .st-dot { background: #f0a04b; }
    .sev-low  .st-dot { background: #98a2b3; }
    .st-cause { flex: 1; font-size: 14px; font-weight: 600; color: var(--text-primary); }
    .st-impact { flex-shrink: 0; font-size: 12px; font-weight: 600; padding: 2px 10px; border-radius: 20px; background: #f2f3f6; color: #6b7a8f; }
    .sev-high .st-impact { background: #fde5e5; color: #c23a35; }
    .sev-med  .st-impact { background: #fdeede; color: #9a6216; }

    .st-signal { font-size: 12.5px; color: var(--text-secondary); margin-bottom: 7px; }
    .st-lbl { display: inline-block; font-size: 10px; text-transform: uppercase; letter-spacing: .4px; color: var(--text-muted); margin-right: 7px; }
    .st-where { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
    .st-chip { font-size: 11px; color: #46536e; background: #eef1f6; padding: 2px 9px; border-radius: 20px; }

    .st-rec { font-size: 13px; color: var(--text-primary); padding: 9px 12px; border-radius: 8px; background: #e9f7f2; margin-bottom: 6px; }
    .st-rec-lbl { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .4px; color: #0f7a63; margin-bottom: 2px; }
    .st-effect { font-size: 11.5px; color: var(--text-muted); }

    /* Фильтр панели проблем по проекту (открывается из «Советника») */
    .st-filter { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; font-size: 12.5px; color: var(--text-secondary); }
    .st-filter-chip {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 3px 5px 3px 12px; border-radius: 20px;
      background: #e1f5ee; color: #0f6e56; font-weight: 600;
    }
    .st-filter-chip button {
      display: inline-flex; border: none; background: none; color: inherit;
      cursor: pointer; padding: 2px; border-radius: 50%;
    }
    .st-filter-chip button:hover { background: rgba(15,110,86,.15); }


    /* Stub pages */
    .stub {
      flex: 1; display: flex; align-items: center; justify-content: center;
      padding: 40px 20px;
    }
    .stub-inner {
      max-width: 380px; text-align: center;
      display: flex; flex-direction: column; align-items: center; gap: 10px;
    }
    .stub-ico {
      width: 56px; height: 56px; border-radius: 14px;
      background: #eaf1ff; color: #3b82f6;
      display: flex; align-items: center; justify-content: center;
      margin-bottom: 6px;
    }
    .stub-title { font-size: 18px; font-weight: 600; color: var(--text-primary); }
    .stub-desc  { font-size: 13px; color: var(--text-secondary); line-height: 1.55; }

    /* Animations */
    @keyframes fadeIn { from{opacity:0;transform:translateY(3px)} to{opacity:1;transform:translateY(0)} }
    .ani { animation: fadeIn 0.18s ease both; }

    /* ────────────────── WORKFLOWS ────────────────── */
    .flows-list { display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
    /* Карточки потоков внутри секции идут с воздухом между собой — иначе они
       слипаются в сплошную ленту (список одинаково выглядит и в «Потоках работ»,
       и на вкладке «Потоки» проекта) */
    #viewProcesses .section-body,
    #wt-flowlist .section-body,
    #proj-flows .section-body { display: flex; flex-direction: column; gap: 8px; }
    /* Секции репозитория стоят вплотную — в свёрнутом виде их плашки сливались
       в сплошную полосу. Разводим по вертикали */
    #wt-repo, #ws-repo { display: flex; flex-direction: column; gap: 8px; }
    /* То же на «Выполнении» задачи: свёрнутые секции шли встык */
    #task-exec .proj-data-grid > div { display: flex; flex-direction: column; gap: 8px; }
    #wt-flowlist { padding-top: 4px; }
    /* Вкладка «Процессы» подгружает собственный .body-area — его боковой отступ
       складывался бы с отступом worktasks (двойной). Убираем, чтобы совпало с «Потоки». */
    #wt-processes > .body-area { padding-left: 0; padding-right: 0; }
    #proj-exec .section-body,
    /* Потоки проекта: карточки шли вплотную — тот же отступ, что в списках выше */
    #proj-pipelines .section-body { display: flex; flex-direction: column; gap: 10px; }
    /* «Источники задач» — как карточки-потоки: та же высота/отступы, шеврон, чипы справа */
    #proj-exec .items-list { display: flex; flex-direction: column; gap: 5px; }
    #proj-exec .items-list .item-row { padding: 14px 16px; border-radius: 12px; flex-wrap: nowrap; }
    #proj-exec .items-list .item-row .item-chips { margin-left: auto; }
    #proj-exec .items-list .item-row::after {
      content: ''; flex-shrink: 0; width: 15px; height: 15px;
      background: no-repeat center / 15px url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%23b2bac6' stroke-width='2.5' viewBox='0 0 24 24'><polyline points='9 18 15 12 9 6'/></svg>");
    }
    .flow-card {
      display: flex; align-items: center; gap: 14px;
      background: #fff; border: 1px solid var(--border); border-radius: 12px;
      padding: 14px 16px; cursor: pointer;
      box-shadow: 0 1px 3px rgba(0,0,0,0.04);
      transition: border-color .15s, box-shadow .15s, transform .08s;
    }
    .flow-card:hover { border-color: var(--border-mid); box-shadow: 0 4px 12px rgba(15,30,60,0.08); }
    .flow-card:active { transform: scale(0.995); }
    .flow-ico {
      width: 40px; height: 40px; border-radius: 10px; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center; color: #fff;
      box-shadow: 0 2px 6px rgba(15,30,60,0.15);
    }
    .flow-main { flex: 1; min-width: 0; }
    .flow-top { display: flex; align-items: center; gap: 8px; margin-bottom: 0; flex-wrap: wrap; row-gap: 5px; }
    .flow-top .flow-team { margin-left: auto; }
    .flow-name { font-size: 14px; font-weight: 600; color: var(--text-primary); }
    /* Тип потока: «Этап» (под проектом) или «Процесс» (в пространстве) */
    .flow-type {
      font-size: 10.5px; font-weight: 600; letter-spacing: .2px;
      padding: 1px 7px; border-radius: 5px; white-space: nowrap;
      text-transform: uppercase;
    }
    .flow-type.ft-stage   { color: #5a6b86; background: #eef1f6; border: 1px solid #dde3ec; }
    .flow-type.ft-process { color: #2563b8; background: #eaf1fb; border: 1px solid #cfe0f5; }
    .flow-type.ft-project { color: #0f7a63; background: #e6f5f0; border: 1px solid #c3e6dc; }
    /* Бесцветный значок типа (проект/процесс) слева от имени потока */
    .flow-type-ico { display: inline-flex; align-items: center; color: #9aa3b2; flex-shrink: 0; }
    /* Чипы в подвале карточки потока: направление и процесс (справа от статуса) */
    .fc-chip {
      font-size: 11px; font-weight: 500; white-space: nowrap;
      padding: 2px 8px; border-radius: 5px;
    }
    .fc-dir  { color: #7c5cbf; background: #efeafb; }   /* направление */
    .fc-proc { color: #5a6b86; background: #eef1f6; }   /* процесс */
    /* ── Дашборд «Панель управления»: 6 панелей 2×3 ── */
    .dash-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding: 6px 0 20px; align-items: stretch; }
    .dash-card {
      position: relative; background: #fff; border: 1px solid var(--border); border-radius: 14px;
      padding: 20px 22px; cursor: pointer; display: flex; flex-direction: column; gap: 5px; min-height: 138px;
      transition: border-color .15s, box-shadow .15s, transform .1s;
    }
    .dash-card:hover { border-color: var(--border-mid); box-shadow: 0 6px 20px rgba(15,30,60,.08); }
    .dash-card:active { transform: scale(.995); }
    .dash-ico { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 8px; }
    .dash-ico-teal   { background: #e1f5ee; color: #0f6e56; }
    .dash-ico-red    { background: #fceaea; color: #c23a35; }
    .dash-ico-blue   { background: #eaf1fb; color: #2563b8; }
    .dash-ico-purple { background: #efeafb; color: #7c5cbf; }
    .dash-ico-amber  { background: #faeeda; color: #a5710f; }
    .dash-ico-coral  { background: #faece7; color: #b3491f; }
    .dash-ico-slate  { background: #eaeef4; color: #5a6b86; }
    .dash-title { font-size: 16px; font-weight: 600; color: var(--text-primary); }
    .dash-desc { font-size: 12.5px; color: var(--text-secondary); }
    .dash-metrics { display: flex; flex-wrap: wrap; gap: 14px; margin-top: auto; padding-top: 12px; font-size: 12px; color: var(--text-muted); }
    .dash-metric b { color: var(--text-primary); font-weight: 600; }
    .dash-metric.dash-metric-alert b { color: #c23a35; }
    .dash-fav {
      position: absolute; right: 14px; top: 14px; width: 26px; height: 26px; padding: 0;
      display: flex; align-items: center; justify-content: center;
      background: none; border: none; border-radius: 7px; cursor: pointer; color: #cbd1db;
      transition: background .12s, color .12s;
    }
    .dash-fav svg { fill: none; }
    .dash-fav:hover { background: rgba(0,0,0,.05); color: #9aa3b2; }
    .dash-fav.active { color: #72c1a4; }
    .dash-fav.active svg { fill: none; }
    @media (max-width: 720px) { .dash-grid { grid-template-columns: 1fr; } }

    /* ─── Панель управления: компактные карточки по разделам + чат deepleex ─── */
    .dash-groups { padding: 6px 0 0; display: flex; flex-direction: column; gap: 20px; }
    .dash-group-label { font-size: 11px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: #9aa6b6; margin: 0 2px 10px; }
    .dash-mini-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
    .dash-mini {
      position: relative; display: flex; align-items: center; gap: 11px;
      background: #fff; border: 1px solid var(--border); border-radius: 11px;
      padding: 18px 14px; cursor: pointer;
      transition: border-color .15s, box-shadow .15s, transform .1s;
    }
    /* Быстрые действия — кнопки шириной по содержимому, а не колонками сетки */
    .dash-mini-grid:has(.dash-mini-action) { display: flex; flex-wrap: wrap; }
    .dash-mini-action { flex: 0 0 auto; box-shadow: 0 2px 6px rgba(15,30,60,.08); }
    .dash-mini-action:hover { box-shadow: 0 5px 16px rgba(15,30,60,.12); }
    .dash-mini:hover { border-color: var(--border-mid); box-shadow: 0 4px 14px rgba(15,30,60,.07); }
    .dash-mini:active { transform: scale(.99); }
    /* «Быстрые действия» — кнопки (заливка, без белой карточки и тени), чтобы отличались от навигации */
    .dash-mini-action { background: var(--backdrop); border-color: var(--border); }
    .dash-mini-action:hover { background: #e4e9f1; border-color: var(--border-mid); box-shadow: none; }
    /* Иконка кнопки — без подложки: бокс по размеру глифа (специфичность выше
       общего .dash-mini .dash-ico ниже), цвет знака сохраняется */
    .dash-mini.dash-mini-action .dash-ico { background: transparent; width: auto; height: auto; }
    /* Знаки быстрых действий — нейтральные, без цветов: карточки читаются текстом */
    .dash-mini.dash-mini-action .dash-ico { color: var(--text-secondary); }
    /* Без подложки текст прижимаем ближе к знаку (общий отступ карточек — 11px) */
    .dash-mini-action { gap: 8px; }
    .dash-mini .dash-ico { width: 34px; height: 34px; border-radius: 9px; margin: 0; flex-shrink: 0; }
    .dash-mini .dash-ico svg { width: 17px; height: 17px; }
    .dash-mini-body { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
    .dash-mini-title { font-size: 13.5px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .dash-mini-desc { font-size: 11.5px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .dash-mini-badge {
      margin-left: auto; flex-shrink: 0; min-width: 18px; height: 18px; padding: 0 5px;
      background: #eef1f6; color: #7a8698; font-size: 11px; font-weight: 600;
      border-radius: 9px; display: flex; align-items: center; justify-content: center;
    }
    /* Бейдж карточки — как счётчик «Полученное» в сайдбаре (белый, красный, розовая рамка) */
    .dash-mini-badge.alert { background: #fff; color: #c23a35; box-shadow: inset 0 0 0 1px #f2b8b4; }

    /* Композер ИИ-ассистента deepleex — чипы сверху, поле ввода + панель инструментов;
       оформление карточки как у блока учётной записи (.sidebar-user). */
    /* Экран поделён на три равные части по вертикали: приветствие стоит внизу
       первой, композер — внизу второй, третья остаётся пустой (.dash-tail).
       Все три доли — равные flex-строки колонки .dash-groups */
    .dash-greet { flex: 1; display: flex; align-items: flex-end; justify-content: center; padding: 18px 0 0; }
    .dash-greet > .proj-header { width: auto; justify-content: center; }
    .dash-tail { flex: 1; }
    /* Знак deepleex перед приветствием — тот же, что в логотипе сайдбара.
       Отбивку до текста даёт gap самого .proj-header — своего margin не нужно */
    .dpx-greet-mark { display: inline-flex; align-items: center; flex-shrink: 0; color: #051c3c; }
    #viewDash .content { display: flex; flex-direction: column; }
    #viewDash .body-area { flex: 1; display: flex; flex-direction: column; min-height: 0; padding-bottom: 0; }
    /* Композер вместе с блоком действий — по центру области по вертикали
       (вместо прижатия к низу через margin-top: auto у .dpx-chat) */
    /* gap: 0 — распорка .dash-greet должна примыкать к композеру, иначе область
       приветствия обрывается на 20px выше инпута и центр уезжает */
    #viewDash .dash-groups { flex: 1; gap: 0; }
    /* Композер — вторая треть: сам блок занимает её целиком, а поле ввода
       с подсказками прижато к её низу */
    #viewDash .dash-groups > .dpx-chat {
      flex: 1; margin: 0 auto;
      display: flex; flex-direction: column; justify-content: flex-end;
    }
    /* Поля по бокам — у всех композеров: поле ввода не должно упираться
       в края области, где бы композер ни стоял */
    .dpx-chat { margin: auto auto 0; max-width: 900px; width: 100%; padding: 0 20px; }
    /* Приветствие крупнее заголовков страниц (19px) — это главный текст экрана */
    .proj-title.dpx-greeting { font-size: 21px; letter-spacing: -.4px; }
    /* В узкой области приветствие переносится по словам и остаётся по центру
       (у .proj-header > .proj-title стоит flex-shrink: 0 — здесь его снимаем) */
    .dash-greet > .proj-header > .dpx-greeting {
      flex: 0 1 auto; min-width: 0; white-space: normal; text-align: left; line-height: 1.3;
    }
    .dpx-sugs { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 4px 10px; }
    /* На «Начале» подсказки стоят под полем ввода: сперва сам вопрос, потом
       готовые заходы. Порядок задаём флексом — разметка остаётся общей */
    #viewDash .dash-groups > .dpx-chat > .dash-sugs { order: 1; margin: 10px 4px 0; }
    /* Быстрые действия — блок под композером, по центру области.
       Ширину не ограничиваем шириной композера (900px): ряду кнопок нужно больше,
       и он переносился при свободном месте — переносим только когда не влезает в область */
    .dash-actions { width: fit-content; max-width: 100%; margin: 34px auto 8px;
      display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
    .dash-actions .dash-mini-grid { margin: 0; }
    /* Кнопки действий: при переносе неполная строка остаётся по центру блока
       (первая строка при этом занимает всю ширину, поэтому подсказки ниже
       по-прежнему выровнены по её левому краю) */
    .dash-actions .dash-mini-grid { justify-content: center; }
    .dpx-sug {
      font-size: 12px; color: #55647f; background: #fff;
      border: 1px solid var(--border); border-radius: 20px; padding: 6px 13px; cursor: pointer;
      font-family: inherit; box-shadow: 0 1px 2px rgba(15,30,60,.04);
      transition: background .12s, border-color .12s;
    }
    .dpx-sug:hover { background: #f7f9fc; border-color: var(--border-mid); }
    .dpx-box {
      background: #fff; border-radius: 14px;
      /* Второй слой тени — рамка поля. Почти чёрная: поле ввода — главный
         элемент композера, и полупрозрачная рамка его не выделяла */
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(80,120,220,.45);
      padding: 6px 6px 6px 16px; display: flex; flex-direction: row; align-items: center; gap: 8px;
      transition: box-shadow .15s;
    }
    /* Композер дашборда — в две строки: поле сверху, тулбар внутри той же рамки снизу */
    .dpx-box:has(> .dpx-box-row) { flex-direction: column; align-items: stretch; gap: 6px; padding: 10px 10px 8px 16px; }
    .dpx-box-row { display: flex; align-items: center; gap: 8px; }
    .dpx-box > .dpx-toolbar { row-gap: 0; margin-left: -8px; }
    .dpx-box > .dpx-toolbar .dpx-tool { background: none; border-color: transparent; box-shadow: none; }
    .dpx-box > .dpx-toolbar .dpx-tool:hover { background: rgba(0,0,0,.04); border-color: transparent; }
    .dpx-tool-mic { margin-left: auto; }
    /* Пока поле пустое, отправлять нечего — кнопка скрыта */
    .dpx-box:has(.dpx-box-row) .dpx-send { display: none; }
    .dpx-box.has-text .dpx-send { display: flex; }
    /* «+» внутри поля слева: без рамки и фона — он часть поля, а не кнопка над ним */
    .dpx-box > .dpx-box-plus {
      margin-left: -8px; flex-shrink: 0;
      border: none; background: transparent; box-shadow: none;
    }
    .dpx-box > .dpx-box-plus:hover { background: #eef1f6; }
    /* Плюс в обёртке меню — без рамки везде, как «+» внутри поля: круглая
       обводка на дашборде выбивалась из остальных инструментов композера */
    .dpx-plus-wrap > .dpx-box-plus {
      width: 28px; height: 28px; margin-left: -6px; flex-shrink: 0;
      border: none; border-radius: 50%;
      background: transparent; box-shadow: none;
    }
    .dpx-plus-wrap > .dpx-box-plus:hover { background: #eef1f6; }
    /* В фокусе рамка почти чёрная — цвета поменяны местами с покоем */
    .dpx-box:focus-within { box-shadow: 0 4px 14px rgba(15,30,60,.1), 0 0 0 1px rgba(15,30,60,0.78); }
    .dpx-field {
      flex: 1; min-width: 0; border: none; outline: none; background: none;
      font-size: 14px; color: var(--text-primary); font-family: inherit; padding: 2px 0;
    }
    /* Бледнее прежнего #9aa6b6: подсказка не должна конкурировать с введённым
       текстом, а рамка поля теперь почти чёрная и сама держит границы ввода */
    .dpx-field::placeholder { color: #b3bdca; }
    .dpx-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    /* Панель инструментов вынесена из карточки — под полем ввода, кнопки без рамок и фона */
    /* row-gap: 0 — при переносе кнопок вторая строка не отбивается сверху */
    .dpx-chat > .dpx-toolbar { margin-top: 10px; padding: 0 2px; row-gap: 0; }
    /* Выбранное в выпадайках-фильтрах — чипами над полем ввода (пусто → не занимает места) */
    .dpx-picks { display: none; flex-wrap: wrap; gap: 6px; margin: 0 2px 8px; }
    .dpx-picks.show { display: flex; }
    /* Отметка выбранного пункта в выпадайке — как у чипа */
    .fd-flow.sel, .fd-proj.sel { background: #e1f5ee; color: #0f6e56; font-weight: 600; }
    /* В чате потока композер компактнее — тулбар прижат к полю ввода.
       Панель чата вдвое уже страницы, и три кнопки перестают влезать в строку
       буквально на 1–2px: 30 + 136 + 152 плюс два зазора по 8px против 333px
       доступных. Поджимаем зазор и боковой padding — «Все участники» перестают
       переноситься, а на совсем узком чате перенос по-прежнему сработает */
    .ai-foot .dpx-chat > .dpx-toolbar { margin-top: 0; gap: 6px; padding: 3px 0; }
    .dpx-chat > .dpx-toolbar .dpx-tool { background: none; border-color: transparent; box-shadow: none; }
    .dpx-chat > .dpx-toolbar .dpx-tool:hover { background: rgba(0,0,0,.04); border-color: transparent; }
    /* Выпадайки в композере (Все активности / Все команды) — раскрываются вверх, поверх всего */
    .dpx-toolbar .toolbar-filter-wrap { position: relative; }
    .dpx-toolbar .toolbar-filter-wrap .filter-dropdown { top: auto; bottom: calc(100% + 6px); left: 0; right: auto; z-index: 400; min-width: 250px; max-height: 320px; }
    .dpx-tool {
      display: inline-flex; align-items: center; gap: 6px;
      height: 30px; padding: 0 11px; border-radius: 8px; cursor: pointer;
      background: #fff; border: 1px solid var(--border);
      font-size: 12.5px; font-weight: 500; color: #55647f; font-family: inherit;
      transition: background .12s, border-color .12s;
    }
    .dpx-tool:hover { background: #f4f6fa; border-color: var(--border-mid); }
    .dpx-tool svg { color: #8b95a5; flex-shrink: 0; }
    .dpx-tool-plus { width: 30px; padding: 0; justify-content: center; }
    .dpx-tool-plus svg { color: #55647f; }
    .dpx-toolbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
    /* Иконка внутри поля ввода — часть поля, поэтому без рамки и заливки */
    .dpx-tool-ico {
      width: 32px; height: 32px; padding: 0; justify-content: center; border-radius: 50%;
      background: none; border-color: transparent; box-shadow: none;
    }
    .dpx-tool-ico:hover { background: rgba(0,0,0,.04); border-color: transparent; }
    .dpx-send {
      width: 32px; height: 32px; flex-shrink: 0; border: none; border-radius: 50%; cursor: pointer;
      display: flex; align-items: center; justify-content: center; color: #fff;
      background: #1c2333; transition: opacity .12s, transform .1s;
    }
    .dpx-send:hover { opacity: .9; }
    .dpx-send:active { transform: scale(.94); }
    /* Поле пустое — кнопка ещё не действие: остаётся на месте, но без тёмного
       круга, одной серой стрелкой, как соседняя иконка микрофона */
    .dpx-box:not(.has-text) .dpx-send {
      background: none; color: #8b95a5;
      transition: background .12s, color .12s, transform .1s;
    }
    .dpx-box:not(.has-text) .dpx-send:hover {
      background: rgba(0,0,0,.04); color: #55647f; opacity: 1;
    }

    /* Тип сценария кейса — цветом: процесс · поток · задача */
    .sc-chip { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 5px; white-space: nowrap; }
    .sc-chip.sc-process { color: #2563b8; background: #eaf1fb; }
    .sc-chip.sc-flow    { color: #0f7a63; background: #e6f5f0; }
    .sc-chip.sc-task    { color: #7c5cbf; background: #efeafb; }
    /* Сценарий в шапке «Описание» — нейтральный чип: цвет тут ничего не кодирует */
    .sc-chip.sc-plain   { color: #55647f; background: #eef1f6; }
    /* Имя сценария в шапке секции жмётся первым (flex-shrink много больше
       единицы): места не хватило — обрезаем его многоточием, а название
       секции, счётчик и кнопки остаются целыми */
    /* Место чип отдаёт до конца (min-width: 0): название секции важнее имени
       сценария, поэтому оно обрезается только когда от чипа уже ничего не
       осталось. Счётчик и кнопки шапки не жмутся вовсе */
    .section-head > .sc-chip {
      flex-shrink: 100; min-width: 0; overflow: hidden; text-overflow: ellipsis;
    }
    .section-head > .count-chip { flex-shrink: 0; }
    /* Описание карточки: отбито от названия сверху, к чипам снизу липнет */
    .flow-desc { font-size: 12px; color: var(--text-secondary); margin-top: 5px; }
    .flow-foot { display: flex; align-items: center; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
    .flow-foot .flow-count { margin-left: auto; }
    .flow-count { font-size: 11.5px; color: var(--text-muted); flex-shrink: 0; }
    .flow-team {
      display: inline-flex; align-items: center; gap: 5px;
      font-size: 11px; color: var(--text-secondary);
      background: var(--bg); border: 1px solid var(--border);
      padding: 2px 8px; border-radius: 5px; white-space: nowrap;
    }
    .flow-team-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
    /* progress rendered inside the "Выполняется" status chip */
    .ichip-status.progress {
      position: relative; overflow: hidden;
      display: inline-flex; align-items: center;
    }
    .ichip-status.progress .st-fill {
      position: absolute; left: 0; top: 0; bottom: 0;
      background: rgba(31, 157, 99, 0.28); z-index: 0;
    }
    .ichip-status.progress .st-txt { position: relative; z-index: 1; }
    .flow-chev { color: var(--text-muted); flex-shrink: 0; }
    .flow-card:hover .flow-chev { color: var(--text-secondary); }
    .flows-filter .filter-btn {
      width: auto; padding: 4px 14px;
      display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
    }
    .flows-filter .filter-btn .nav-badge { margin-left: 2px; }

    /* ────────────────── EXECUTORS ────────────────── */
    .exec-ava {
      width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      color: #fff; font-size: 12px; font-weight: 700;
      box-shadow: 0 2px 6px rgba(15,30,60,0.15);
    }
    .member-card { cursor: default; }
    /* Карточка-ссылка (график работы) — рука по наведению */
    .member-card[onclick] { cursor: pointer; }
    .member-card:active { transform: none; }
    .member-status {
      margin-left: auto; flex-shrink: 0;
      font-size: 11px; color: var(--text-muted);
      display: inline-flex; align-items: center; gap: 5px;
    }
    .member-status::before {
      content: ""; width: 6px; height: 6px; border-radius: 50%;
      background: #c7ced8;
    }
    .member-status.online { color: #1f9d63; }
    .member-status.online::before { background: #34d399; box-shadow: 0 0 0 3px rgba(52,211,153,0.15); }
    .member-tasks {
      margin-left: auto; font-size: 11.5px; color: var(--text-muted); white-space: nowrap;
    }
    .member-tasks b { color: var(--text-primary); font-weight: 600; }

    /* Участники / Команды / Навыки — многоколоночная сетка.
       Список профилей (.items-list на вкладке «Участники») сюда же: карточка профиля
       должна быть той же ширины, что карточка агента рядом. */
    #exec-members .flows-list,
    #exec-members .items-list,
    #exec-teams .flows-list,
    #exec-profiles .items-list {
      display: grid;
      /* Не больше четырёх карточек в ряд: на широком экране колонка тянется,
         на узком работает прежний минимум в 260px */
      grid-template-columns: repeat(auto-fill, minmax(max(260px, calc((100% - 30px) / 4)), 1fr));
      gap: 6px;
    }
    /* Боковой отступ одинаковый на всех вкладках: без него карточки упираются в края панели */
    #exec-members .flows-list,
    #exec-members .items-list,
    #exec-teams .flows-list,
    #exec-profiles .items-list,
    #exec-schedules .flows-list { padding: 3px 22px 2px; }
    #exec-members .flows-list,
    #exec-teams .flows-list { gap: 10px; }

    .mini-ava {
      width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      color: #fff; font-size: 9px; font-weight: 700;
    }

    /* Аватары — без цвета и тени: в списках цветные кружки спорили с чипами
       и статусами, а тень добавляла им веса, которого у инициалов нет.
       !important — фон приходит инлайновым градиентом из разметки */
    /* Инициалы терялись: заливка стала светлой, а цвет букв остался от прежних
       цветных аватаров — белым. Заливку берём на тон плотнее, буквы тёмными,
       и оба свойства с !important: правила самих аватаров идут ниже по файлу */
    .mini-ava, .exec-ava, .ai-msg-ava, .user-avatar, .um-avatar, .ai-ava {
      background: #dde3ee !important;
      color: #3b4a5e !important; box-shadow: none;
    }

    /* Chat list (notifications tab) */
    .chat-list { display: flex; flex-direction: column; padding-top: 2px; }
    .chat-row {
      display: flex; align-items: center; gap: 12px;
      padding: 11px 10px; cursor: pointer;
      border-bottom: 1px solid var(--border);
      transition: background 0.12s;
    }
    .chat-row:last-child { border-bottom: none; }
    /* Фильтры вровень с заголовком и строками списка: своего бокового
       отступа тулбару здесь не нужно, страница уже отбита .body-area */
    #viewChats .gantt-toolbar { padding-left: 0; padding-right: 0; }
    .chat-row:hover { background: #f6f8fb; }
    .chat-row.active { background: #eaf1ff; box-shadow: inset 3px 0 0 #3b82f6; }
    .chat-row.active:hover { background: #eaf1ff; }
    .chat-row-ava {
      width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      color: #fff; font-size: 12px; font-weight: 700;
    }
    .chat-row-ava.task { border-radius: 11px; }
    .chat-row-main { flex: 1; min-width: 0; }
    .chat-row-top { display: flex; align-items: baseline; gap: 8px; }
    .chat-row-name { font-size: 13px; font-weight: 600; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .chat-row-time { margin-left: auto; font-size: 11px; color: var(--text-muted); flex-shrink: 0; }
    .chat-row-preview { font-size: 12px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
    .chat-row-unread {
      flex-shrink: 0; min-width: 18px; height: 18px; padding: 0 5px;
      border-radius: 9px; background: var(--teal); color: #fff;
      font-size: 10.5px; font-weight: 400;
      display: flex; align-items: center; justify-content: center;
    }

    /* Activity feed (changes tab) */
    .notif-list { display: flex; flex-direction: column; padding-top: 2px; }
    .notif-item { display: flex; align-items: flex-start; gap: 12px; padding: 12px 8px; border-bottom: 1px solid var(--border); }
    .notif-item:last-child { border-bottom: none; }
    .notif-item .mini-ava { width: 32px; height: 32px; border-radius: 9px; font-size: 11px; }
    .notif-body { flex: 1; min-width: 0; padding-top: 3px; }
    .notif-text { font-size: 13px; color: var(--text-secondary); line-height: 1.45; }
    .notif-text b { font-weight: 600; color: var(--text-primary); }
    .notif-time { font-size: 11px; color: var(--text-muted); margin-top: 3px; }

    .ichip-role { background: #eef1fb; color: #5560c9; }

    /* Карточку «по умолчанию» отмечает только бейдж — заливки и цветной рамки нет */
    .flow-card.flow-default:hover { border-color: var(--border-mid); }
    #wt-schedules .flow-card > .item-check { flex-shrink: 0; margin-right: 2px; }
    .flow-default-badge {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 10.5px; font-weight: 600; line-height: 1;
      color: #1f9d63; background: #e3f5ec;
      padding: 3px 8px; border-radius: 5px; white-space: nowrap;
    }


    /* ────────────────── AI ASSISTANT ────────────────── */
    .ai-btn {
      position: relative;
      width: 40px; height: 40px;
      border: 1px solid var(--border);
      border-radius: 7px;
      background: var(--bg);
      color: var(--purple);
      cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
      flex-shrink: 0;
    }
    .ai-btn:hover { border-color: var(--border-mid); color: var(--teal); background: #fff; }
    .ai-btn.active { background: var(--purple); color: #fff; border-color: var(--purple); }
    .space-btn {
      width: 40px; height: 40px;
      border: 1px solid var(--border); border-radius: 7px;
      background: var(--bg); color: var(--purple);
      cursor: pointer; flex-shrink: 0;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
    }
    .space-btn:hover { border-color: var(--border-mid); color: var(--teal); background: #fff; }
    .ai-btn svg { transition: transform 0.2s; }
    .ai-btn:hover svg { transform: scale(1.08) rotate(-4deg); }
    .ai-pulse {
      position: absolute; top: 7px; right: 7px;
      width: 6px; height: 6px; border-radius: 50%;
      background: var(--teal);
      box-shadow: 0 0 0 0 rgba(42, 180, 160, 0.6);
      animation: aiPulse 1.8s ease-out infinite;
    }
    .ai-btn.active .ai-pulse { display: none; }

    /* ── Модалка «Новая задача» ──────────────────────────────── */
    /* Затемнение — на весь экран, а само окно стоит в области контента: сайдбар
       и хлебные крошки читаются на фоне, поэтому понятно, где заводится задача */
    .nt-overlay {
      position: fixed; inset: 0; z-index: 200;
      background: rgba(20,28,40,.45);
      display: none; overflow: auto;
    }
    .nt-overlay.open { display: block; }
    /* Позицию считает ntPosition() по реальным краям сайдбара и топбара:
       сайдбар можно тянуть, и фиксированные отступы разъезжались */
    .nt-modal-pos {
      position: absolute; inset: 20px;
      display: flex; align-items: stretch;
    }
    body.nt-open { overflow: hidden; }
    .nt-modal {
      background: #fff; border-radius: 14px; width: 100%;
      /* Тень поглубже: окно должно заметно отрываться от страницы под ним */
      box-shadow: 0 28px 80px rgba(10,18,32,.55), 0 6px 18px rgba(10,18,32,.30);
      /* Окно занимает всю высоту экрана за вычетом отступов оверлея (44px сверху
         и снизу) — описание тянется до низа, а не обрывается на полпути */
      display: flex; flex-direction: column; height: 100%; max-height: 100%;
    }
    .nt-head {
      display: flex; align-items: center; gap: 12px; flex-shrink: 0;
      padding: 15px 20px; border-bottom: 1px solid #eef1f6;
    }
    .nt-title-input {
      flex: 1; min-width: 0; border: none; outline: none; background: transparent;
      /* Кегль как у заголовка страницы: окно — та же шапка, только модальная */
      font-size: 16px; font-weight: 500; color: #1a2740; padding: 4px 2px;
    }
    /* Подсказка в поле названия — совсем лёгкая: она не должна читаться как уже
       введённый заголовок */
    .nt-title-input::placeholder { color: #c3cbd8; font-weight: 300; -webkit-font-smoothing: antialiased; }
    .nt-actions { display: flex; gap: 8px; flex-shrink: 0; }
    /* Чип потока слева от кнопок: в каком потоке заводим задачу */
    .nt-flow { flex-shrink: 0; margin-right: 4px; display: inline-flex; align-items: center; }
    /* В строке «Описание» выбор потока стоит у правого края и с рамкой —
       иначе чип теряется на светлой подложке шапки */
    .proj-data-section-head > .nt-flow { margin-left: auto; margin-right: 0; }
    .proj-data-section-head > .nt-flow .cs-trigger { border-color: rgba(0,114,125,.28); }
    .nt-flow .cs-trigger { max-width: 240px; }
    .nt-btn {
      /* 32px — как «В работу» и другие кнопки строк */
      height: 32px; padding: 0 16px; border-radius: 8px; cursor: pointer; white-space: nowrap;
      font-size: 12.5px; font-weight: 600; border: 1px solid var(--border, #e2e8f0);
      background: #fff; color: #55607a; transition: background .12s, border-color .12s;
    }
    /* «Отменить» — второстепенное действие, поэтому без полужирного */
    .nt-cancel { font-weight: 500; }
    .nt-primary { font-weight: 500; }
    .nt-btn:hover { background: #f3f5f9; }
    .nt-primary { background: var(--teal, #0098a6); border-color: var(--teal, #0098a6); color: #fff; }
    .nt-primary:hover { background: #00828e; border-color: #00828e; }
    /* Фон как в основном окне: карточки полей внутри белые, и на белом фоне
       модалки их границы пропадали — на #f6f7fa они читаются так же, как на странице */
    .nt-body {
      padding: 8px 20px 24px; overflow: auto; background: var(--bg);
      /* Тело — последний блок модалки, поэтому скругление нижних углов на нём:
         иначе закрашенный фон торчал бы прямыми углами из-под radius модалки */
      border-radius: 0 0 14px 14px;
    }

    /* Rich-text редактор описания */
    .rt-toolbar {
      display: flex; gap: 2px; flex-wrap: wrap; padding: 4px; margin: 2px 4px 8px;
      border: 1px solid #e7ebf2; border-radius: 8px; background: #fafbfd;
    }
    .rt-btn {
      width: 28px; height: 28px; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; border-radius: 6px; cursor: pointer; color: #6b7688;
    }
    .rt-btn:hover { background: #eceff5; color: #1a2740; }
    .rt-editor {
      min-height: 96px; padding: 10px 12px; margin: 0 4px;
      border: 1px solid #e2e8f0; border-radius: 8px;
      font-size: 13px; line-height: 1.7; color: #3b4a5e; outline: none;
    }
    .rt-editor:focus { border-color: var(--teal, #0098a6); background: #fff; }
    /* Вставленная картинка вписывается в область: пропорции сохраняются
       (width/height: auto), высота ограничена — иначе длинный скриншот
       выдавливает остальное содержимое секции */
    .rt-editor img,
    .proj-data-section img {
      display: block; margin: 8px 0;
      max-width: 100%; max-height: 320px; width: auto; height: auto;
      border: 1px solid var(--border); border-radius: 8px;
    }
    /* В статичном виде картинка открывается в просмотрщике; в редакторе клик
       оставляем за курсором, иначе правка текста превращается в борьбу с попапом */
    .proj-data-section:not(:has(.rt-editor)) img { cursor: zoom-in; }
    /* Просмотрщик картинки */
    .img-zoom {
      position: fixed; inset: 0; z-index: 4000;
      display: flex; align-items: center; justify-content: center;
      background: rgba(15,25,45,.72); backdrop-filter: blur(3px);
      opacity: 0; transition: opacity .16s ease;
    }
    .img-zoom.open { opacity: 1; }
    .img-zoom img {
      max-width: 92vw; max-height: 92vh; border-radius: 10px;
      box-shadow: 0 24px 64px rgba(0,0,0,.45); background: #fff;
    }
    .img-zoom-close {
      position: absolute; top: 18px; right: 18px;
      width: 34px; height: 34px; padding: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; border-radius: 50%; background: rgba(255,255,255,.14);
      color: #fff; cursor: pointer; transition: background .12s;
    }
    .img-zoom-close:hover { background: rgba(255,255,255,.26); }

    /* Применить/отменить правку описания — справа в тулбаре редактора */
    .rt-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }
    .rt-act {
      width: 26px; height: 26px; padding: 0; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: 1px solid var(--border); border-radius: 7px; background: #fff;
      color: var(--text-secondary); cursor: pointer; transition: background .12s, color .12s, border-color .12s;
    }
    .rt-act:hover { background: #f1f4f9; color: var(--text-primary); }
    .rt-act.ok { border-color: transparent; background: var(--teal); color: #fff; }
    .rt-act.ok:hover { background: #00868f; color: #fff; }
    .rt-editor:empty::before { content: attr(data-ph); color: #b9c2d0; }
    /* Пустое описание: подсказка нарисована псевдоэлементом, а не текстом — иначе
       она попадала бы в редактор как содержимое */
    .desc-ph:empty::before { content: attr(data-ph); color: #b9c2d0; }
    /* Кликом по тексту начинают правку — курсор об этом и говорит */
    /* Пустое описание держит заметное поле для клика — иначе в него трудно
       попасть, а секция выглядит как случайный зазор */
    .desc-ph { cursor: text; min-height: 60px; }
    .vibe-desc { cursor: text; }
    .rt-editor p { margin: 0 0 8px; }
    .rt-editor p:last-child { margin-bottom: 0; }
    .nt-body .rt-editor + div { margin-top: 12px; }     /* отступ блока тегов от редактора */
    /* Модалка новой задачи: слева одно «Описание» во всю высоту, теги — по низу,
       справа свёрнутые секции (см. ntArrangeSections) */
    .nt-body { flex: 1; display: flex; flex-direction: column; min-height: 0; }
    .nt-body > .proj-data-grid.nt-grid { align-items: stretch; flex: 1; min-height: 420px; }
    .nt-grid > * { min-width: 0; }
    .nt-grid .nt-desc-sec { display: flex; flex-direction: column; height: 100%; }
    .nt-grid .nt-desc-sec > .rt-editor { flex: 1; }
    .nt-grid .nt-desc-sec > .rt-editor + div { margin-top: auto; }
    @keyframes aiPulse {
      0%   { box-shadow: 0 0 0 0 rgba(42, 180, 160, 0.5); }
      70%  { box-shadow: 0 0 0 8px rgba(42, 180, 160, 0); }
      100% { box-shadow: 0 0 0 0 rgba(42, 180, 160, 0); }
    }

    .ai-content-wrap {
      flex: 1;
      display: flex;
      gap: 8px;
      min-height: 0;
    }
    .ai-main-col {
      flex: 1; min-width: 0;
      display: flex; flex-direction: column; gap: 10px;
      min-height: 0;
    }
    .ai-main-col > .main { flex: 1; min-height: 0; }

    .ai-panel, .chat-panel {
      position: fixed;
      top: 10px; right: 10px; bottom: 10px;
      width: 380px;
      background: #fff;
      border: 1px solid var(--border);
      border-radius: 14px;
      box-shadow: -12px 0 44px rgba(15,30,60,0.16);
      display: flex;
      flex-direction: column;
      overflow: hidden;
      transform: translateX(calc(100% + 24px));
      opacity: 0;
      pointer-events: none;
      transition: transform 0.32s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.32s;
      z-index: 100;
    }
    .chat-panel { z-index: 110; }
    body.ai-open .ai-panel,
    body.chat-open .chat-panel { transform: translateX(0); opacity: 1; pointer-events: auto; }
    /* Таб-бар начинается там же, где фильтр и карточки списка под ним */
    .flow-main-col .sticky-header > .tab-bar { margin-left: 24px; }
    /* Чат открывается табом «Чат», а не иконкой: текст, точка новых сообщений
       и шеврон вправо — панель выезжает справа */
    .flow-chat-tab { gap: 6px; }
    .flow-chat-tab .fct-chev { color: #9aa6b6; }
    .flow-chat-tab:hover .fct-chev { color: #55647f; }
    /* Открытый чат забирает таб себе — в основном баре его быть не должно */
    body.flow-chat-open .flow-chat-tab { display: none; }
    /* Счётчик непрочитанных вместо безымянной точки — сколько именно ждёт ответа
       видно, не открывая чат. Размеры как у .nav-badge.count в сайдбаре */
    .flow-chat-count {
      display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
      min-width: 17px; height: 17px; padding: 0 4px;
      border-radius: 9px; background: var(--teal); color: #fff;
      font-size: 10.5px; font-weight: 600;
      /* Без line-height: 1 — он делал строчный бокс (10.5px) ниже глифа, и цифра
         съезжала вверх: сверху оставалось 1.25px, снизу 2.75px. На normal — 2/2 */
    }
    /* Шапка окна чата: тот же таб-бар, что в контенте, но с кнопкой скрытия в конце.
       Отступы по бокам как у .ai-body / .ai-foot, чтобы всё в панели шло по одной линии */
    .flow-chat-panel .chat-head { flex-shrink: 0; padding-bottom: 10px; }
    .flow-chat-panel .chat-head > .tab-bar { margin: 0 22px; }
    /* Сам таб «Чат» тоже сворачивает панель — шеврон влево перед текстом
       показывает, куда она уедет (контент занимает освободившееся место) */
    .chat-head-tab { gap: 5px; cursor: pointer; }
    .chat-head-tab .cht-chev { color: #9aa6b6; }
    .chat-head-tab:hover .cht-chev { color: #55647f; }
    .chat-hide-btn {
      display: inline-flex; align-items: center; justify-content: center; align-self: center;
      margin-left: auto; width: 26px; height: 26px; flex-shrink: 0;
      border: none; border-radius: 7px; background: transparent;
      color: #9aa6b6; cursor: pointer; transition: background .12s, color .12s;
    }
    .chat-hide-btn:hover { background: rgba(15,30,60,.06); color: #2a4d7f; }
    /* Прыжок к последнему непрочитанному. Висит в .ai-foot, а не в ленте:
       .ai-foot не прокручивается, поэтому кнопка держится над композером
       при любой высоте переписки */
    .flow-chat-panel .ai-foot { position: relative; }
    .chat-jump {
      position: absolute; top: -42px; left: 50%; transform: translateX(-50%); z-index: 22;
      display: none; align-items: center; gap: 5px;
      height: 28px; padding: 0 10px 0 8px;
      border: 1px solid var(--border); border-radius: 14px;
      background: var(--card); color: #55647f; cursor: pointer;
      box-shadow: 0 2px 8px rgba(16,32,64,.12);
      transition: background .12s, color .12s;
    }
    .chat-jump.show { display: inline-flex; }
    /* Прыжок к непрочитанным — только в ленте чата: при закрытой колонке
       композер переезжает в основную колонку, где ленты нет, и кнопка
       там ни к чему */
    body.vibe-chat-hidden .vibe-foot .chat-jump { display: none; }
    /* То же на прочих вкладках: композер стоит внизу каждой, а ленты там нет */
    body:not(.vibe-chat-tab):not(.vibe-chat-only) .vibe-foot .chat-jump { display: none; }
    /* Непрочитанных нет — остаётся только шеврон возврата к последнему сообщению */
    .chat-jump.no-unread { padding: 0 8px; }
    .chat-jump.no-unread .cj-count { display: none; }
    /* Линия «Непрочитанные сообщения»: её ставит syncChatSep перед первым таким
       сообщением — бирюзовая, как всё непрочитанное в интерфейсе */
    .ai-unread-sep {
      display: flex; align-items: center; gap: 10px; margin: 4px 0 14px;
      font-size: 10.5px; font-weight: 600; letter-spacing: .3px; color: #0f6e56;
      text-transform: uppercase; white-space: nowrap;
    }
    .ai-unread-sep::before, .ai-unread-sep::after {
      content: ''; flex: 1; height: 1px; background: #bfe3d9;
    }
    .chat-jump:hover { background: #f4f6fa; color: #2a4d7f; }
    .chat-jump .cj-count {
      display: inline-flex; align-items: center; justify-content: center;
      min-width: 17px; height: 17px; padding: 0 4px;
      border-radius: 9px; background: var(--teal); color: #fff;
      font-size: 10.5px; font-weight: 600;
    }
    /* Непрочитанных нет — счётчик прячем, а не показываем ноль */
    .flow-chat-tab.no-unread .flow-chat-count { display: none; }
    /* Панель чата — докнута в области контента слева, половина ширины (не попап, без фона/рамки).
       Раскладка общая для потока, проекта и задачи: цепляемся за .flow-main-col,
       а не за id страницы, иначе правило пришлось бы дублировать под каждый view */
    .content:has(> .flow-main-col) { position: relative; overflow: hidden; display: flex; flex-direction: column; }
    .content > .flow-main-col {
      flex: 1; min-height: 0; display: flex; flex-direction: column;
      transition: margin-left .26s ease, background-color .26s ease;
    }
    /* Отступ от таб-бара до содержимого — как на остальных страницах с табами.
       Он в самой шапке (не в прокручиваемой области), иначе строки списка
       просвечивают в этом зазоре при прокрутке. */
    /* Фон убираем — иначе он закрывает общую подложку области */
    .content > .flow-main-col > .body-area { flex: 1; min-height: 0; overflow-y: auto; background: transparent; }
    /* Слева отступ такой же, как справа (24px): чат уехал вправо, внешнего зазора
       у левого края больше нет, и половинить его теперь не за чем.
       Таб-бар двигаем синхронно с телом, иначе табы уедут от содержимого */
    .content > .flow-main-col > .body-area { padding-left: 24px; }
    .content > .flow-main-col > .sticky-header > .tab-bar { margin-left: 24px; }
    /* Липкие панели (фильтры, шапка Ганта) и строки красятся в --area-bg —
       см. их правила выше, иначе они светлыми прямоугольниками выделялись бы */
    /* Табы и содержимое — одна область на подложке чуть темнее фона страницы.
       Подложка — не серая вуаль поверх фона, а собственный оттенок того же
       цвета, что и фон страницы (#f6f7fa), просто на тон глубже.
       Смысл у неё только рядом с чатом: она отделяет контент от переписки.
       Без чата подложка сливается с фоном — цвет ведём через --area-bg, чтобы
       вместе с ней плавно перекрашивалось всё, что на неё посажено */
    .content > .flow-main-col {
      --area-bg: var(--bg);
      background: var(--area-bg); border-radius: 12px;
      padding: 8px 0 10px;
      margin-left: 12px;
      transition: margin-right .26s ease, margin-left .26s ease, background-color .26s ease;
    }
    /* Подложку под контентом не затемняем нигде: чат — белая карточка с рамкой,
       он отделён от контента сам, а вторая заливка только добавляла шума.
       --area-bg остаётся фоном страницы, и всё, что на нём сидит (фильтр-бар,
       шапка Ганта, легенда), не выделяется светлыми прямоугольниками */
    .content > .flow-main-col > .sticky-header { padding-bottom: 10px; background: transparent; }

    /* Список задач потока — как на «Плане работ»: тень, воздух между строками, ховер */
    /* Больше воздуха между строками; высоты — прежние */
    .items-list, .item-group, .item-subrows { gap: 6px; }
    .item-subrows { padding: 0 8px 8px; }
    /* Рамка одинаковая у всех строк списка — как у вложенного сценария; теней нет */
    .items-list > .item-row,
    .item-subrows > .item-row.item-subrow {
      border-color: #e6eaf2; box-shadow: none;
    }
    /* Ручка перетаскивания прижата к краю у всех строк, включая шапки групп */
    .item-row { padding-left: 2px; }
    /* Вложенные строки и вложенные группы оформлены как внешние: та же заливка и тень */
    .item-subrows > .item-row.item-subrow { background: #f7f9fc; }
    /* Вложенные сценарии — на тон плотнее строк, чтобы уровень читался заливкой */
    .item-subrows > .item-group.work-group {
      background: #eff2f8; border-color: #e6eaf2; box-shadow: none;
    }
    /* Вызов сценария и строка вложенного сценария — одна карточка на вид */
    .items-list > .item-row.item-row-parent {
      background: #eff2f8; border-color: #e6eaf2; box-shadow: none;
    }
    .items-list > .item-row:hover { border-color: #9aa7bf; background: var(--card); }
    /* Чат живёт справа, контент слева. --flow-chat-w — линия раздела, а не ширина
       панели: 12px зазора делим поровну между чатом и контентом, поэтому при 50%
       обе половины ровно равны */
    /* Чат — обычная панель таба: занимает область контента целиком, лента внутри
       прокручивается, композер прижат к низу. Отдельной выезжающей панели больше
       нет — таб «Чат» переключается как остальные */
    .flow-chat-panel {
      display: flex; flex-direction: column; min-height: 0; height: 100%;
    }
    /* Панель таба под чат: контент не прокручивается снаружи — скроллит лента */
    .body-area > #chat-panel { height: 100%; min-height: 0; }
    .body-area:has(> #chat-panel.active),
    .body-area:has(> #chat-panel[style*="display: block"]) { overflow: hidden; display: flex; flex-direction: column; }
    /* Чат — белая карточка с рамкой: переписка отделяется от контента сама,
       без затемнённой подложки под ним. Одинаково на потоке, проекте, задаче
       и команде. Радиус взят у .flow-main-col, горизонтальных отступов нет —
       их держат .ai-body / .ai-foot */
    .flow-chat-panel {
      background: transparent; border-radius: 0;
      border: none;
      /* Снизу отступа нет: тулбар композера сам себе граница, а лишние 9px
         читались как пустая полоса под ним. Сверху 7px, а не 8 — рамка
         съедает свой пиксель, иначе шапка чата не встанет вровень с табами */
      padding: 7px 0 0;
    }
    /* Правила выезжающей панели (ширина, ресайзер, сжатие контента) убраны:
       чат теперь обычный таб и занимает ту же область, что остальные панели */
    /* Поля чата: текст и композер одинаково отбиты от обоих краёв панели.
       База .ai-body / .ai-foot даёт слева 14px и 12px — вровень с правым 22px */
    .flow-chat-panel .ai-body { padding-right: 22px; padding-left: 22px; }
    .flow-chat-panel .ai-foot { padding-right: 22px; padding-left: 22px; }
    /* Зазор над композером переносим внутрь ленты сообщений: 10px убираем
       сверху у .ai-foot и добавляем снизу к .ai-body. Здесь padding работает
       как надо — лента прижата к низу, поэтому отступ виден всегда */
    /* Отбивка между лентой и композером: 12px воздуха над полем ввода, чтобы
       последнее сообщение не липло к нему, и запас снизу в самой ленте */
    .flow-chat-panel .ai-foot { padding-top: 12px; }
    .flow-chat-panel .ai-body { padding-bottom: 36px; }
    /* Уходящий вниз текст растворяется, а не обрезается по краю. Маска привязана
       к рамке блока, а не к содержимому, поэтому работает на любой прокрутке.
       48px — ровно зазор до края (36px padding + 12px margin сообщения):
       домотав ленту вниз, последнее сообщение читается без затухания */
    .flow-chat-panel .ai-body {
      -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 48px), transparent);
      mask-image: linear-gradient(to bottom, #000 calc(100% - 48px), transparent);
    }
    /* Сообщение участника: строка «аватар + имя», текст — с новой строки под ними */
    .ai-msg.ai-msg-agent { display: block; }
    .ai-msg.ai-msg-agent .ai-msg-ava {
      border-radius: 50%; display: inline-flex; vertical-align: middle; margin: 0;
    }
    .ai-msg-name {
      margin-left: 8px; vertical-align: middle;
      font-size: 12.5px; font-weight: 600; color: #2a3547;
    }
    .ai-msg.ai-msg-agent .ai-agent-text {
      background: transparent; border: none; padding: 6px 0 0; box-shadow: none;
      color: #2a3547; font-size: 13px; line-height: 1.62;
    }
    .ai-msg.ai-msg-agent .ai-agent-text p { margin: 0 0 8px; }
    .ai-msg.ai-msg-agent .ai-agent-text p:last-child { margin-bottom: 0; }
    /* Без фона/рамки у самой панели чата */
    .flow-chat-panel .ai-body { background: transparent; }
    .flow-chat-panel .ai-foot { background: transparent; border-top: none; padding-bottom: 0; }

    .ai-head {
      display: flex; align-items: center; justify-content: space-between;
      padding: 12px 14px;
      border-bottom: 1px solid var(--border);
      background: linear-gradient(180deg, #f7f9fc, #ffffff);
      flex-shrink: 0;
    }
    .ai-title { display: flex; align-items: center; gap: 10px; }
    .ai-ava {
      width: 32px; height: 32px; border-radius: 9px;
      background: linear-gradient(135deg, var(--purple), var(--purple-dark));
      color: #fff;
      display: flex; align-items: center; justify-content: center;
      box-shadow: 0 2px 6px rgba(5, 28, 59, 0.2);
    }
    .ai-name { font-size: 13px; font-weight: 600; color: var(--text-primary); }
    .ai-sub {
      font-size: 11px; color: var(--text-muted);
      display: flex; align-items: center; gap: 5px; margin-top: 1px;
    }
    .ai-dot {
      width: 6px; height: 6px; border-radius: 50%;
      background: #34d399;
      box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.15);
    }
    .ai-head-actions { display: flex; gap: 4px; }
    .ai-icon-btn {
      width: 28px; height: 28px; border-radius: 6px;
      border: 1px solid transparent; background: transparent;
      color: var(--text-muted);
      cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
    }
    .ai-icon-btn:hover { background: var(--bg); color: var(--text-primary); }

    .ai-body {
      flex: 1;
      overflow-y: auto;
      padding: 16px 14px 8px;
      background: linear-gradient(180deg, #fff 0%, #fafbfd 100%);
    }
    .ai-body::-webkit-scrollbar { width: 5px; }
    .ai-body::-webkit-scrollbar-thumb { background: #d4d2e8; border-radius: 10px; }

    .ai-day {
      text-align: center; font-size: 10.5px; color: var(--text-muted);
      margin: 0 0 14px; letter-spacing: 0.3px; text-transform: uppercase;
    }

    .ai-msg { display: flex; gap: 8px; margin-bottom: 12px; align-items: flex-end; }
    .ai-msg.user { flex-direction: row-reverse; }
    .ai-msg-ava {
      width: 22px; height: 22px; border-radius: 6px;
      background: linear-gradient(135deg, var(--purple), var(--purple-dark));
      color: #fff;
      display: flex; align-items: center; justify-content: center;
      flex-shrink: 0;
    }
    .ai-bubble {
      max-width: 82%;
      padding: 9px 12px;
      border-radius: 12px;
      font-size: 12.5px;
      line-height: 1.55;
      color: var(--text-primary);
    }
    .ai-msg.assistant .ai-bubble {
      background: #fff;
      border-radius: 12px 12px 12px 3px;
      border: 1px solid var(--border);
    }
    /* Картинка-вложение в сообщении: превью + подпись с именем файла */
    .ai-att-img {
      margin-top: 8px; border: 1px solid var(--border); border-radius: 10px;
      overflow: hidden; background: #fff; cursor: pointer; max-width: 260px;
      transition: border-color .12s, box-shadow .12s;
    }
    .ai-att-img:hover { border-color: var(--border-mid); box-shadow: 0 4px 14px rgba(15,30,60,.08); }
    .ai-att-img svg { display: block; width: 100%; height: 104px; background: #f3f5fa; }
    .ai-att-img svg rect { fill: #d9e2f0; }
    .ai-att-img svg rect.b1 { fill: #bcd8cd; }
    .ai-att-img svg rect.b2 { fill: #f0c3bd; }
    .ai-att-img svg rect.b3 { fill: #bcd8cd; }
    .ai-att-img svg path { stroke: #aab6c8; stroke-width: 1.5; fill: none; }
    .ai-att-cap {
      display: block; padding: 6px 9px; font-size: 10.5px; color: var(--text-muted);
      border-top: 1px solid var(--border); background: #f7f9fc;
    }

    /* Свои сообщения — светло-серым, без заливки цветом */
    .ai-msg.user .ai-bubble {
      background: #e4e9f1;
      color: var(--text-primary);
      border-radius: 12px 12px 3px 12px;
    }
    .ai-msg-time {
      font-size: 10px; color: var(--text-muted);
      margin: 3px 32px 8px;
    }
    .ai-msg.user + .ai-msg-time { text-align: right; }

    .ai-list { margin: 8px 0 2px; display: flex; flex-direction: column; gap: 6px; }
    .ai-list-item {
      display: flex; align-items: center; gap: 6px;
      padding: 7px 9px;
      background: var(--bg);
      border: 1px solid var(--border);
      border-radius: 8px;
      font-size: 12px;
    }
    .ai-list-id {
      font-size: 10.5px; font-weight: 600; color: var(--text-muted);
      background: #fff;
      padding: 2px 6px; border-radius: 4px;
      border: 1px solid var(--border);
      flex-shrink: 0;
    }
    .ai-list-name {
      flex: 1; min-width: 0;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .ai-badge {
      font-size: 10px; padding: 2px 6px; border-radius: 5px;
      font-weight: 500; white-space: nowrap; flex-shrink: 0;
    }
    .ai-badge.red { background: #fee2e2; color: #b91c1c; }
    .ai-badge.orange { background: #ffedd5; color: #b45309; }

    .ai-chips { margin-top: 10px; display: flex; gap: 6px; flex-wrap: wrap; }
    .ai-chip {
      font-size: 11.5px; padding: 4px 10px; border-radius: 6px;
      background: #fff; border: 1px solid var(--border-mid); color: var(--purple);
      cursor: pointer;
      transition: all 0.15s;
      display: inline-flex; align-items: center; gap: 4px;
    }
    .ai-chip:hover { background: var(--purple-light); border-color: var(--purple-mid); }

    .ai-bubble-typing {
      display: flex; gap: 4px; align-items: center;
      padding: 12px 14px !important;
    }
    .ai-bubble-typing span {
      width: 6px; height: 6px; border-radius: 50%;
      background: var(--text-muted);
      animation: aiTyping 1.2s infinite ease-in-out;
    }
    .ai-bubble-typing span:nth-child(2) { animation-delay: 0.15s; }
    .ai-bubble-typing span:nth-child(3) { animation-delay: 0.3s; }
    @keyframes aiTyping {
      0%, 60%, 100% { transform: translateY(0); opacity: 0.5; }
      30% { transform: translateY(-3px); opacity: 1; }
    }

    .ai-foot {
      padding: 10px 12px 12px;
      border-top: 1px solid var(--border);
      background: #fff;
      flex-shrink: 0;
    }
    .ai-input-wrap {
      display: flex; align-items: flex-end; gap: 6px;
      background: var(--bg);
      border: 1px solid var(--border);
      border-radius: 10px;
      padding: 6px 6px 6px 10px;
      transition: border-color 0.15s, background 0.15s;
    }
    .ai-input-wrap:focus-within { border-color: var(--purple-mid); background: #fff; }
    .ai-input {
      flex: 1;
      border: none; background: transparent;
      resize: none;
      font-family: inherit;
      font-size: 12.5px;
      color: var(--text-primary);
      outline: none;
      max-height: 90px;
      padding: 5px 0;
      line-height: 1.5;
    }
    .ai-input::placeholder { color: var(--text-muted); }
    .ai-send {
      width: 30px; height: 30px; border-radius: 8px;
      border: none;
      background: var(--purple);
      color: #fff;
      cursor: pointer;
      display: flex; align-items: center; justify-content: center;
      transition: all 0.15s;
      flex-shrink: 0;
    }
    .ai-send:hover { background: var(--teal); }
    .ai-hint {
      font-size: 10.5px; color: var(--text-muted);
      margin-top: 6px; text-align: center;
    }

    /* ── Страница исполнителя: расписание и профиль ── */
    /* Диапазон: первой строкой имя и признак (крестик справа), второй — даты
       слева и дни недели справа */
    .proj-data-field.field-stacked:has(.sched-row) > .src-head { display: flex; align-items: center; gap: 8px; padding-right: 0; }
    /* Признак диапазона — у правого края, перед крестиком удаления */
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .ichip { flex-shrink: 0; }
    /* Чип графика — сразу за именем; вправо распирает только признак
       «работает / не работает», за ним крестик удаления */
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .ichip-status { margin-left: auto; }
    /* Даты переехали в первую строку и стоят вплотную слева от статуса:
       распорку держит чип дат, статусу она уже не нужна */
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .sched-dates { margin-left: auto; }
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .sched-dates ~ .ichip-status { margin-left: 0; }
    /* Общее правило .src-head > .src-type тоже распирало влево — тогда
       свободное место делилось между двумя чипами и график отъезжал от имени */
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .src-type { margin-left: 0; }
    .proj-data-field.field-stacked:has(.sched-row) > .src-head > .proj-data-del { position: static; margin: 0 0 0 6px; align-self: center; }
    /* Строка периода: между именем и датами — воздух, сама карточка выше */
    .proj-data-field.field-stacked:has(.sched-row) { padding-top: 12px; padding-bottom: 12px; }
    /* Чипы периода (признак, даты, дни недели) — выше: при line-height 1 текст
       обрезался сверху и снизу */
    .proj-data-field.field-stacked:has(.sched-row) .ichip {
      height: 18px; padding: 0 8px; line-height: 18px;
      display: inline-flex; align-items: center;
    }
    /* Чётность недели — чип-переключатель: выключенный нейтральный,
       включённый подсвечен, как активная пилюля */
    .sched-parity { margin-left: auto; cursor: pointer; font-weight: 400; }
    /* Крестик в чипе дат: сбрасывает период в «Всегда» */
    .sched-dates { cursor: pointer; }
    /* Крестик в чипе дат: только иконка, без рамки и фона */
    .sched-dates .spec-x {
      margin-left: 3px; width: 12px; height: 12px; padding: 0; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
      border: none; background: none; box-shadow: none; border-radius: 0;
      color: currentColor; opacity: .45; cursor: pointer; transition: opacity .12s;
    }
    .sched-dates .spec-x:hover { opacity: 1; background: none; }
    /* Дни недели: показаны все семь, выключенные — бледные и без заливки */
    .week-days .wd { cursor: pointer; font-weight: 400; transition: background .12s, color .12s, box-shadow .12s; }
    .week-days .wd.off { background: transparent; color: #b3bdca; box-shadow: inset 0 0 0 1px var(--border); }
    .week-days .wd:hover { color: var(--text-primary); }
    /* Признак периода: работает — зелёный, не работает — красный, без жирного */
    .proj-data-field.field-stacked:has(.sched-row) .ichip-status { font-weight: 400; }
    .proj-data-field.field-stacked:has(.sched-row) .ichip.ichip-status.open.open { background: #d4f0eb; color: #0f6e56; border: none; box-shadow: none; }
    .proj-data-field.field-stacked:has(.sched-row) .ichip.ichip-status.st-deferred.st-deferred { background: #fde5e5; color: #c23a35; border: none; box-shadow: none; }
    .sched-row {
      display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
      justify-content: flex-start; margin-left: 0; margin-top: 8px;
    }
    .field-stacked:not(.from-sched) .src-head .ichip-status { cursor: pointer; }
    /* Дни и чётность — служебные переключатели, а не статусы: серые, как чип
       диапазона дат. Цветным в строке остаётся только статус периода */
    .proj-data-field.field-stacked:has(.sched-row) :is(.sched-parity, .week-days .wd) {
      background-color: #eef0f4; color: #50607a; box-shadow: none;
    }
    .proj-data-field.field-stacked:has(.sched-row) .week-days .wd.off {
      background-color: transparent; color: #b3bdca; box-shadow: inset 0 0 0 1px var(--border);
    }
    /* Диапазон дат — чипом, как даты на карточке канбана (.ichip-dates) */
    .sched-dates { white-space: nowrap; }
    /* Отступ от чипа чётности даёт gap самой строки: лишние 10px переносили дни
       на вторую строку, когда подпись длиннее («Нечётная неделя») */
    .week-days { display: flex; flex-wrap: wrap; gap: 6px; }

    /* Фотография исполнителя: превью и две кнопки рядом */
    /* Без #task-data: селектор с id перебивал правило свёрнутой секции, и фото
       оставалось видно, когда «Учётная запись» свёрнута */
    .member-photo { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 0 4px 16px; }
    /* Секция с фото слева: сам блок фото лежит в разметке последним (правка
       описания меняет блок сразу за шапкой), место слева ему даёт грид */
    .proj-data-section.photo-left { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 4px; }
    .photo-left > .proj-data-section-head { grid-column: 1 / -1; }
    .photo-left > .member-photo { grid-column: 1; grid-row: 2 / span 99; align-self: start; }
    .photo-left > :not(.proj-data-section-head):not(.member-photo) { grid-column: 2; }
    .photo-left .mp-actions { align-items: stretch; }
    .photo-left .mp-actions .mp-btn { justify-content: center; }

    /* «Учётная запись»: поля без тени и рамки, подложка на тон темнее страницы —
       блок читается как единая карточка учётки, а не как список отдельных полей */
    .acc-section .proj-data-field { background: var(--backdrop); box-shadow: none; }
    /* Значения на серой подложке — белые пилюли, иначе сливаются с полем */
    /* background-color, а не background: шорткат стирал стрелку селекта (она
       нарисована background-image) */
    .acc-section :is(.cs-trigger, .proj-data-pill, .ichip) { background-color: #fff; }
    /* Статус приглашения тоже белый: у базового .ichip-status длинная цепочка
       :not(...), поэтому селектор здесь намеренно «тяжелее» */
    .acc-section.acc-section .ichip.ichip-status.acc-invite.acc-invite.acc-invite {
      background-color: #fff; color: var(--text-secondary);
    }
    .acc-section.acc-section .ichip.ichip-status.acc-invite.acc-invite.acc-invite.open { color: #1aa966; }
    /* Дата приглашения стоит слева от статуса и не спорит с ним по яркости */
    /* Дата набрана так же, как текст статуса, только серым */
    .acc-invite-date { color: var(--text-secondary); font-size: 10.5px; font-weight: 400; line-height: 1; margin-left: 4px; }
    .acc-section:not(.invited) .acc-invite-date { display: none; }
    /* Фото участника здесь крупнее вдвое */
    .acc-section .mp-frame { width: 144px; height: 144px; font-size: 40px; }

    /* У агента личных данных нет, контакты появляются только
       после принятого приглашения, а код приглашения — наоборот, до него */
    .acc-section.kind-agent .acc-staff { display: none; }
    .acc-section:not(.invited) .acc-contact { display: none; }
    .acc-section.invited .acc-invite-copy { display: none; }
    .acc-section .acc-invite { cursor: pointer; }
    /* Фото выбирают кликом по самому кружку — отдельной кнопки «Выбрать» нет */
    .mp-frame { cursor: pointer; transition: filter .12s; }
    .mp-frame:hover { filter: brightness(.94); }
    .mp-frame {
      width: 72px; height: 72px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
      display: flex; align-items: center; justify-content: center;
      background: #eef1f6; color: #6b7a8f; font-size: 22px; font-weight: 600;
    }
    /* Общее правило .proj-data-section img (рамка, поля, max-height) не должно
       дотягиваться до аватара — фото всегда заполняет кружок */
    .mp-frame img, .proj-data-section .mp-frame img {
      width: 100%; height: 100%; max-width: none; max-height: none;
      margin: 0; border: none; border-radius: 0; object-fit: cover; display: block;
    }
    .mp-actions { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
    /* Кнопки как теги, только без рамки: тот же размер, шрифт и радиус */
    .mp-actions .mp-btn {
      display: inline-flex; align-items: center;
      background: #eef1f6; border: none;
      border-radius: 20px; padding: 4px 13px;
      font: inherit; font-size: 12px; font-weight: 500; color: #3b4a5e;
      cursor: pointer; transition: background .15s, border-color .15s, color .15s;
    }
    .mp-actions .mp-btn:hover { background: #e0e6ef; color: var(--text-primary); }
    /* Кнопка ровно одна: пока фото нет — «Выбрать», как только выбрано — «Сбросить» */
    .member-photo .mp-btn[onclick*="memberPhotoReset"] { display: none; }
    .member-photo.has-photo .mp-btn[onclick*="memberPhotoReset"] { display: inline-flex; }
    .member-photo.has-photo .mp-btn[onclick*="memberPhotoPick"] { display: none; }
    /* Числовые и временные поля — как пилюли значений, а не системные инпуты */
    .hours-input {
      width: 58px; text-align: center; font: inherit; font-size: 12.5px; color: var(--text-primary);
      background: #f1f4f9; border: 1px solid transparent; border-radius: 6px; padding: 4px 8px;
      transition: border-color .12s, background .12s;
    }
    .hours-input:hover { border-color: var(--border-mid); }
    .hours-input:focus { outline: none; background: #fff; border-color: var(--purple-mid, #9aa7bf); }
    .time-input { width: 66px; }
    /* Отбивка от следующего контрола: «8» и «часов в день» слипались */
    .field-row > .hours-input + .data-select { margin-left: 8px; }
    /* Ставка: поле ввода суммы, знак валюты рядом, отбивка до селектора периода */
    .money-input { width: 74px; text-align: right; }
    .field-unit { color: var(--text-secondary); margin: 0 10px 0 4px; }
    .field-dash { color: var(--text-muted); }
    /* Подпись «из графика» / предупреждение о нехватке рабочего времени */
    #member-schedule .src-type { cursor: default; }
    #member-schedule .src-type.warn { background: #fde8e6; color: #993536; }

    /* «Задания»: список плоский — без тени, только лёгкая рамка. Непрочитанные
       по-прежнему держат зелёную полосу слева (её рисует та же box-shadow) */
    body[data-page="assignments"] .item-row { box-shadow: none; border-color: var(--border); }
    body[data-page="assignments"] .item-row.unread { box-shadow: inset 3px 0 0 0 var(--teal); }
    body[data-page="assignments"] .item-row:hover { box-shadow: none; border-color: var(--border-mid); }
    body[data-page="assignments"] .item-row.unread:hover { box-shadow: inset 3px 0 0 0 var(--teal); }

    /* Навык, пришедший из рабочего пространства: серый чип с его именем,
       связи и сам навык из списка команды не убрать */
    /* Чип пространства стоит в строке имени и прижат вправо */
    .spec-chip.ws-chip { background-color: #eef0f4; color: #50607a; }
    .spec-head > .ws-chip { margin-left: auto; }
    /* Навык из пространства и в карточке специальности серый — он не свой */
    .spec-chip.ws-skill { background-color: #eef0f4; color: #50607a; }
    .spec-row.from-ws .spec-x { display: none; }
    .spec-scope { cursor: pointer; background-color: #eef0f4; color: #50607a; }
    .proj-data-section.only-private > .spec-row.from-ws { display: none; }

    /* Тип сущности в шапке — рядом с кодом, но приглушённее самого кода */
    .proj-header .ent-type { color: #6b7a8f; }

    /* «Задания»: секции не липнут друг к другу — воздух между ними */
    body[data-page="assignments"] .asg-panel .section + .section { margin-top: 10px; }

    /* В окне новой задачи поля плоские: без тени, с лёгкой рамкой — как на «Заданиях» */
    /* Поля в окне создания оформлены как на самой задаче: та же светлая рамка
       и синеватая тень (раньше окно нарочно шло без теней) */
    .nt-modal .proj-data-field {
      border-color: #e6eaf2;
      box-shadow: 0 1px 2px rgba(60,90,160,.10), 0 2px 6px rgba(60,90,160,.12);
    }
    /* Подсветка рамкой — только у кликабельных строк (инструкции, источники):
       у остальных при наведении тень остаётся прежней */
    .nt-modal .proj-data-field:hover {
      box-shadow: 0 1px 2px rgba(60,90,160,.10), 0 2px 6px rgba(60,90,160,.12);
    }
    /* Наведение на кликабельную строку: только рамка цвета акцента, фон не трогаем.
       box-shadow повторяет её контур — так рамка читается, а размеры не скачут */
    .nt-modal .proj-data-field[onclick]:hover {
      border-color: #0098a6; box-shadow: 0 0 0 1px #0098a6;
    }

    /* Перетаскивание шагов сценария: тянем строку, линия показывает место */
    /* Ручка и чекбокс — одна группа управления строкой, поэтому стоят вплотную:
       отрицательный margin съедает общий gap строки */
    .row-grip { display: inline-flex; margin-right: -6px; }
    .item-row.row-dragging { opacity: .45; }
    /* Зелёная линия ровно в том месте, куда встанет строка */
    .row-drop-before, .row-drop-after { position: relative; }
    .row-drop-before::after, .row-drop-after::after {
      content: ''; position: absolute; left: 0; right: 0; height: 2px; z-index: 3;
      background: #1aa966; border-radius: 2px; pointer-events: none;
    }
    .row-drop-before::after { top: -3px; }
    .row-drop-after::after { bottom: -3px; }

    /* Сценарии: фильтр-бар статичен, обе секции живут в одном прокручиваемом блоке */
    #wt-cases.scroll-host > .plan-filter-bar,
    #wt-triggers.scroll-host > .plan-filter-bar { flex-shrink: 0; }
    #wt-cases .cases-list, #wt-triggers .cases-list {
      flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden;   /* по горизонтали не ездим */
      overscroll-behavior: contain; padding-right: 4px;
    }

    /* display: inline-flex у кнопки перебивал [hidden] — карандаш оставался виден */
    .param-icon-btn[hidden] { display: none; }
    /* Применить/отменить стоят в шапке секции на месте карандаша */
    .proj-data-section-head .rt-actions.head-actions { display: inline-flex; align-items: center; gap: 6px; }

    /* Сценарии и действия — вкладки Конфигурации, направления и потока, но строка
       у них своя: общие правила списка задач (выравнивание вправо, порядок колонок) не нужны */
    :is(#wt-cases, #wt-triggers) .item-row { justify-content: flex-start; }
    :is(#wt-cases, #wt-triggers) .item-row > * { order: 0; }

    /* Таб-бар без вкладок (осталась только кнопка справа) — линия не нужна */
    .tab-bar:not(:has(.tab)) { border-bottom: none; }

    /* «Свернуть все» — у правого края фильтр-бара, а не сразу за фильтрами */
    .plan-filter-bar { position: relative; }
    .plan-filter-bar .collapse-btn { margin-left: auto; }
    .plan-filter-bar .fbar:has(.collapse-btn) { flex: 1; min-width: 0; }
    /* Группа фильтров не сжимается: с flex:1 и min-width:0 ей доставался огрызок
       строки, и дропдауны рвались по одному («Тэги» уезжал вниз в одиночку).
       Не помещается — переносится целиком, строка тулбара это умеет */
    .plan-filter-bar .fbar:has(.collapse-btn) > .toolbar-filters { flex: 0 0 auto; max-width: 100%; }

    /* «Потоки» на этой же странице: у области фиксированная высота (её задаёт
       список задач), поэтому панель прокручивается сама */
    .content:has(> .body-area > #wt-all) > .body-area > :is(#wt-flows, #wt-processes) {
      flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
      /* полоса прокрутки уходит в поля области — карточки встают вровень с подсказкой */
      margin-right: -10px;   /* ровно ширина полосы прокрутки */
      scrollbar-width: thin; scrollbar-color: #d4d2e8 transparent;
    }
    :is(#wt-flows, #wt-processes) > .plan-filter-bar { position: sticky; top: 0; z-index: 5; background: var(--area-bg); }

    /* Карточки потоков не липнут друг к другу */
    :is(#wt-flows, #wt-processes, #wt-teams) .section-body > .flow-card + .flow-card { margin-top: 8px; }

    /* ─── Карта страниц прототипа (по клику на домик в крошках) ─── */
    .bc-home { cursor: pointer; }
    .bc-home:hover { color: #55647f; }
    .site-map {
      position: fixed; z-index: 3000; width: 300px; max-height: 70vh;
      display: flex; flex-direction: column;
      background: #fff; border-radius: 12px;
      box-shadow: 0 12px 34px rgba(20,28,40,.22), 0 0 0 1px rgba(20,28,40,.06);
      overflow: hidden;
    }
    .site-map-head {
      padding: 10px 14px 8px; font-size: 11px; font-weight: 600;
      color: var(--text-muted); text-transform: uppercase; letter-spacing: .4px;
    }
    .site-map-list { overflow-y: auto; padding: 0 6px 8px; }
    .site-map-sub {
      padding: 10px 8px 4px; font-size: 11px; color: var(--text-muted);
      border-top: 1px solid var(--border); margin-top: 6px;
    }
    .site-map-item {
      display: flex; align-items: baseline; gap: 8px;
      padding: 6px 8px; border-radius: 6px; text-decoration: none;
      font-size: 13px; color: var(--text-primary);
    }
    .site-map-item:hover { background: #f1f4f9; }
    /* До страницы нет пути от index.html — приглушаем, но оставляем открываемой */
    .site-map-item.orphan .sm-name { color: #a3adbb; }
    .site-map-item.here { background: #eef1f6; font-weight: 600; }
    .sm-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .sm-file { flex-shrink: 0; font-size: 11px; color: #b3bdca; }

    /* ══════════ ОБЩЕЕ ОФОРМЛЕНИЕ СТРАНИЦ (перенесено со страницы потока) ══════════
       Блок стоит последним: правила задают внешний вид карточки окна, шапки,
       таб-бара, секций, строк и значений на всех страницах разом */
    /* Окно контента потока — такая же карточка, как подложка сайдбара */
    body .main {
      background: #fff;
      box-shadow: 0 2px 8px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
    }
    /* Шапка потока повторяет шапку сайдбара: 60px и линия снизу, вплотную к табам */
    .head-card { margin-bottom: 0; }
    /* Панель потока — белая, как и вся карточка: --area-bg ведёт за собой
       липкие полосы (фильтры, шапки), чтобы они не темнели прямоугольниками */
    body .content,
    .content > .flow-main-col { --area-bg: #fff; background: #fff; }
    .content > .flow-main-col { padding-top: 0; }
    /* Карточки параметров и результатов работы — та же заливка и тень, что у строк списков */
    body .proj-data-field {
      /* Как строки в «Сценарии»: та же заливка, светлая рамка и синеватая тень */
      background: #f7f9fc; border: 1px solid #e6eaf2;
      box-shadow: 0 1px 2px rgba(60,90,160,.10), 0 2px 6px rgba(60,90,160,.12);
    }
    /* На тонированной карточке бирюзовая пилюля почти пропадала — берём
       нейтральную серо-синюю, она читается на любой заливке */
    .proj-data-pill { background: #d3ecef; color: #056470; }
    body .proj-data-val .data-select,
    body .proj-data-val .cs-trigger {
      background-color: #d3ecef; color: #056470;
      /* только цвет: background целиком стирал бы стрелку выпадайки */
      background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23056470' stroke-width='2.5' viewBox='0 0 24 24'><polyline points='6 9 12 15 18 9'/></svg>");
    }
    .proj-data-val .cs-val { color: #056470; }
    /* Все значения параметров — формы «даты»: прямоугольник со скруглением 6px */
    body .proj-data-val .data-select,
    .proj-data-val .cs-trigger { border-radius: 6px; }
    /* Наведение на значение меняет фон, а не рамку — одинаково у дат,
       выпадающих значений и остальных пилюль */
    body .proj-data-val .proj-data-pill:hover,
    body .proj-data-val .data-select:hover,
    body .proj-data-val .cs-trigger:hover {
      background-color: #c2e4e8; border-color: transparent;
    }
    /* Чип ограничений («Авто») выглядит так же, как значение параметра */
    body .proj-data-field > .lim-chip {
      background: #d3ecef; color: #056470;
      font-size: 11.5px; padding: 3px 11px; border-radius: 6px;
    }
    /* Карточка результата работы — как строки списков: рамка вместо тени */
    body .art-card {
      background: #f7f9fc; border-color: #e6eaf2; box-shadow: none;
    }
    /* В ленте vibe-страниц карточка результата работы — белая */
    :is(.vibe-panel-cols, .vibe-mini, .vibe-colx) .art-card { background: #fff; }
    /* Панель белая, поэтому строки берут цвет фона страницы — иначе бы слились */
    body .items-list > .item-row:not(.item-row-parent):not(.unread) {
      background: #f7f9fc;
    }
    /* На серой строке светлый чип навыка почти пропадал — затемняем его на тон.
       Часы там же нейтральные: цвет объёма работ в списке шагов лишний */
    body .items-list > .item-row .ichip-skill,
    body .item-row .ichip-vol {
      background-color: rgba(15,30,60,.07); color: #50607a;
    }
    /* Строки списков идут без тени: уровень держит рамка, как и у полей-параметров.
       Групповая строка тоже плоская — её выделяет заливка */
    body .items-list > .item-row,
    body .items-list > .item-row:hover,
    .items-list > .item-group.work-group { box-shadow: none; }
    body .items-list > .item-group.work-group {
      background: #eff2f8; border-color: #e6eaf2;
    }
    /* Таб-бар без нижнего отступа, кнопки справа — по центру его высоты */
    /* Линия под табами идёт от края до края карточки: держим её на .sticky-header
       и выпускаем его влево на отступ колонки (сами табы остаются на месте) */
    body .content > .flow-main-col > .sticky-header {
      padding-bottom: 0; margin-left: -12px; padding-left: 12px;
      /* Белая подложка: строки списка не просвечивают сквозь липкие табы */
      background: #fff;
    }
    /* Линия идёт по таб-бару, а не по всей шапке: под закладкой чата её нет */
    body .content > .flow-main-col > .sticky-header > .tab-bar {
      border-bottom: 1px solid var(--border);
    }
    /* Содержимое карточки идёт во всю её ширину: у шапки, табов и области
       одинаковый отступ от краёв, лишний вложенный отступ снят.
       Слева 20px — заголовок отбит от края карточки, справа 10px */
    .head-card .inner { padding-left: 20px; padding-right: 10px; }
    .content > .flow-main-col > .sticky-header { padding-left: 20px; }
    .content > .flow-main-col > .sticky-header > .tab-bar { margin-left: 0; margin-right: 0; padding-right: 20px; }
    body .content > .flow-main-col > .body-area {
      margin-left: -12px; padding: 10px 20px 0;
    }
    /* Отступ области задаёт саму рамку — верхний margin первого блока лишний */
    .content > .flow-main-col > .body-area > .screen-hint { margin-top: 0; }
    .tab-bar > .tab-bar-actions { align-self: center; margin-bottom: 0; }
    body .head-card .inner {
      display: flex; align-items: center;
      height: 60px; padding-top: 0; padding-bottom: 0;
    }
    /* Каталоги («Знания», «Бизнес процессы»): полоса разделов живёт в шапке и
       при нехватке ширины переносится на вторую строку — жёсткие 60px её
       обрезали. Высота по содержимому плюс воздух сверху и снизу */
    body .head-card .inner:has(.knw-tabs) {
      height: auto; min-height: 60px; padding-top: 9px; padding-bottom: 8px;
    }
    body .head-card .inner:has(.knw-tabs) > .proj-header { flex-wrap: wrap; row-gap: 6px; }

    /* Поля учётной записи участника — бледнее и без рамки: блок и так обведён
       карточкой секции, вторая рамка внутри лишняя */
    body #memberAccount > .proj-data-field { background: #fbfcfe; border-color: transparent; }

    /* Данные учётной записи только читаются: значение показываем текстом,
       без чипа и без крестика — правится оно в самой учётной записи */
    body #memberAccount .acc-contact .proj-data-pill {
      background: none; color: #3c8892; padding: 0; cursor: default;
    }
    body #memberAccount .acc-contact .proj-data-pill:hover { background: none; }
    body #memberAccount .acc-contact .pill-x { display: none; }

    /* Навык и его специальность — одной строкой: чип уходит к правому краю */
    body #memberSkills > .proj-data-field.field-stacked {
      flex-direction: row; align-items: center; flex-wrap: nowrap;
    }
    body #memberSkills > .proj-data-field > .proj-data-val { margin-left: auto; width: auto; }

    /* Подложка области содержимого — белая, как и вся карточка страницы:
       серый фон оставался только там, где области ещё красились фоном страницы */
    body .body-area { background: #fff; }
    /* Подсказка на белой области — заливкой цвета фона страницы и с тенью:
       так она отделяется от белого листа, а не сливается с ним */
    body .screen-hint {
      background: var(--bg);
      box-shadow: 0 1px 2px rgba(16,32,64,.06), 0 2px 6px rgba(16,32,64,.07);
      /* Воздух сверху и снизу, но вдвое меньше прежнего: подсказка не липнет
         к линии табов и не отъедает половину первого экрана */
      margin: 8px 0;
    }

    /* Без ручки перетаскивания чекбокс упирался в край строки (padding-left 2px
       оставлен под грипер) — возвращаем строке обычный левый отступ */
    body .item-row:not(:has(> .row-grip)) { padding-left: 10px; }

    /* «Добавить» — одним зелёным тоном, без плюса: подпись и шеврон сами
       достаточно читаются, иконка только утяжеляла кнопку */
    /* Подпись и шеврон — один блок и одного серого цвета с иконками рядом:
       кнопка служебная, ярким цветом её выделять незачем */
    body .new-btn-split .new-btn-main,
    body .new-btn-split .nba-chev,
    body .new-btn-split .new-btn-chev { color: #8b95a5; }
    body .new-btn-split .new-btn-ico { display: none; }
    /* Между подписью и шевроном нет шва: половинки стоят вплотную.
       Шрифт — как у вкладок рядом: 13px обычного начертания */
    body .new-btn-split .new-btn-main {
      padding-right: 0; font-size: 13px; font-weight: 500;
    }
    body .new-btn-split .nba-chev { padding: 0 10px 0 4px; }
    body .new-btn-split:hover .new-btn-main,
    body .new-btn-split:hover .nba-chev,
    body .new-btn-split:hover .new-btn-chev { color: #56637a; }

    /* Панель управления — без карточки: композер и плитки лежат прямо на фоне
       страницы, белый лист с рамкой вокруг них ничего не добавлял.
       «Мои работы» сюда не входят: у списка карточка нужна — она отделяет его
       от фона так же, как на «Выполнении» */
    body .main:has(> #viewDash),
    body #viewDash > .content,
    body #viewDash > .content > .body-area {
      background: transparent; box-shadow: none; border: none;
      /* Подложка области здесь — фон страницы: липкий фильтр-бар и всё, что
         красится в --area-bg, идут тем же цветом, а не белым по серому */
      --area-bg: var(--bg);
    }
    /* Подсказка здесь лежит прямо на фоне страницы — заливку берём белую,
       иначе она сливалась бы с ним в одно пятно */
    body #viewDash .screen-hint { background: #fff; }

    /* Строки списка заданий лежат на сером фоне страницы, а не на белой карточке,
       поэтому серая заливка строк здесь не работает — берём белую */
    body #viewAssignments .items-list > .item-row:not(.item-row-parent),
    body #viewAssignments .items-list > .item-row:not(.item-row-parent):hover {
      background: #fff;
    }

    /* «Кем выполняется» — когда исполнителей несколько, у каждой строки свой
       крестик и общий справа только дублирует их. При одном значении строчного
       крестика нет, поэтому общий остаётся — иначе значение нечем убрать */
    body .proj-data-field:is([data-multi="doer"], [data-multi="manager"]):has(.field-row ~ .field-row) > .proj-data-del { display: none; }

    /* Открытый чат — показываем шеврон влево: он говорит, куда уедет колонка,
       если закладку нажать. Пока чат скрыт, закладка обходится одной иконкой */
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on .chat-chev {
      display: block;
    }
    /* С шевроном закладка шире, поэтому левый отступ убавляем — иначе она
       выпирает за пределы привычной ширины */
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].chat-on {
      padding-left: 8px;
    }

    /* Списочные секции оформлены как секции параметров («Планирование»): свёрнутая
       без серой плашки, отбита линией снизу, наведение — светлой заливкой */
    /* Свёрнута — та, у которой тело скрыто: класс .expanded остаётся висеть
       после collapseAroundRazdel(), поэтому ориентируемся на само тело */
    body .section:not(.expanded),
    body .section:has(> .section-body[style*="display: none"]) {
      border-bottom: 1px solid var(--border);
    }
    /* Воздух до разделительной линии держит сама секция, а не поле заголовка:
       разное поле у раскрытой и свёрнутой шапки двигало название вверх-вниз
       при каждом сворачивании */
    body .section:not(.expanded) > .section-head,
    body .section:has(> .section-body[style*="display: none"]) > .section-head {
      background: transparent;
    }
    /* Воздух между секциями держит поле свёрнутой секции снизу — своего
       верхнего отступа заголовку не нужно */
    body .vibe-feed .section > .section-head { margin-top: 0; }
    /* Верхнее поле держит секция в любом состоянии: пока 8px появлялись
       только у свёрнутой, заголовок прыгал на них при каждом сворачивании.
       Нижнее — только у свёрнутой: это воздух до разделительной линии */
    body .section { padding-top: 8px; }
    body .section:not(.expanded),
    body .section:has(> .section-body[style*="display: none"]) { padding-bottom: 8px; }
    body .section:not(.expanded) > .section-head:hover,
    body .section:has(> .section-body[style*="display: none"]) > .section-head:hover {
      background: #f1f4f9;
    }
    /* «Планирование» на вкладке выполнения — во всю ширину колонки, как соседние
       секции: собственный боковой отступ секции параметров тут лишний */
    body #task-exec > .proj-data-grid .proj-data-section { padding: 0; }

    /* Поле ввода значения — тот же чип, что и остальные значения параметров:
       цианового тона, со скруглением 6px, а не пилюлей */
    body .data-input {
      background-color: #d3ecef; color: #056470; border-radius: 6px;
    }
    body .data-input:hover { background-color: #c2e4e8; border-color: transparent; }
    body .data-input:focus { background-color: #fff; border-color: #0098a6; }

    /* Обычные строки списков — белые: групповые идут светло-серой плашкой,
       и уровень читается контрастом заливок, а не оттенками серого.
       Класс продублирован — иначе правило легче ранних и они его перебивают */
    body .items-list > .item-row.item-row:not(.item-row-parent),
    body .items-list > .item-row.item-row:not(.item-row-parent):hover,
    body .item-subrows > .item-row.item-subrow.item-subrow {
      background: #fff;
    }
    /* Кроме проблемной задачи: розовая подложка — признак нарушения (нет оценки
       или сорван срок), о ней говорит подсказка вкладки. Правило выше красит все
       строки белым и перебивало исходную заливку, поэтому повторяем её здесь */
    body #wt-all .items-list > .item-row.item-row:has(.item-name.danger) {
      background: #fde8e6; border-color: #f3d4d1;
    }
    body #wt-all .items-list > .item-row.item-row:has(.item-name.danger):hover {
      background: #fde8e6; border-color: #9aa7bf;
    }
    /* И кроме непрочитанных: их зелёную заливку те же правила гасили добела,
       и признак держался на одной полосе слева. Селектор с id — чтобы
       перебить такое же правило «Заданий» */
    body .items-list > .item-row.item-row.unread,
    body .items-list > .item-row.item-row.unread:hover,
    body #viewAssignments .items-list > .item-row.unread,
    body #viewAssignments .items-list > .item-row.unread:hover { background: #d5efe1; }

    /* Групповые строки (разделы, вложенные сценарии, составные задачи) — общей
       светлой заливкой: уровень читается отступом и бэйджем, а не цветом */
    body .item-row.item-row-parent.item-row-parent,
    body .item-row.item-row-parent.item-row-parent:hover,
    body .item-group.work-group.work-group,
    :is(#viewWorkTasks, #wt-all) .item-row.item-row-parent.item-row-parent,
    #viewWorkTasks #wt-all .item-row-parent:hover,
    #flow-scenario .items-list > .item-row.item-row-parent,
    #flow-scenario .items-list > .item-row.item-row-parent:hover {
      background: #f7f9fc;
    }

    /* ─────────────── Страница «Дизайн-система» ───────────────
       Витрина элементов: сами элементы берутся системными классами, здесь только
       раскладка образцов — плитки цветов, ряды примеров и подписи */
    .ds-grid {
      display: grid; grid-template-columns: repeat(auto-fill, minmax(176px, 1fr));
      gap: 10px; padding: 0 4px 16px;
    }
    .ds-sw {
      background: #fff; border: 1px solid #e6eaf2; border-radius: 10px; overflow: hidden;
      box-shadow: 0 1px 2px rgba(60,90,160,.10), 0 2px 6px rgba(60,90,160,.12);
    }
    .ds-sw > i { display: block; height: 44px; border-bottom: 1px solid #e6eaf2; }
    .ds-sw > .ds-meta { padding: 7px 10px 8px; }
    .ds-name { font-size: 12.5px; font-weight: 600; color: var(--text-primary); }
    .ds-val {
      font-size: 11px; color: var(--text-secondary);
      font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    }
    /* Ряд живых примеров — чипы, кнопки, поля идут в строку с переносом */
    .ds-row {
      display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
      padding: 0 4px 16px;
    }
    .ds-cap { padding: 0 4px 8px; font-size: 12px; color: var(--text-secondary); line-height: 1.5; }
    /* Образец текста: подпись слева, сам стиль справа — видно и как выглядит,
       и чем задано */
    .ds-type { display: flex; align-items: baseline; gap: 14px; padding: 0 4px 12px; }
    .ds-type > .ds-val { flex-shrink: 0; width: 190px; }
    /* Образец полосы разделов. Класс .lb-rail здесь не годится: leftbar.js
       принимает первую найденную полосу за настоящую и свою уже не строит —
       поэтому оформление полосы повторено, а кнопки взяты системные (.lb-btn) */
    .ds-rail {
      flex-shrink: 0; width: 52px;
      display: flex; flex-direction: column; align-items: center; gap: 4px;
      padding: 8px 0; background: #fff; border-radius: 10px;
      box-shadow: 0 2px 8px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04);
    }
    /* Активная кнопка образца: класс .on снимает setRail() при каждом переходе */
    .ds-rail .lb-btn.ds-on { background: var(--purple); color: #fff; }
    /* Полоса диаграммы: подпись слева, дорожка на всю оставшуюся ширину */
    .ds-bar { display: flex; align-items: center; gap: 12px; padding: 0 0 14px; }
    .ds-bar > .ds-name { flex: 0 0 132px; font-weight: 500; }
    .ds-bar > .gantt-lane { flex: 1; min-width: 0; }

    /* Табы прямо в заголовке страницы: линия под ними идёт через всю карточку,
       а не обрывается по ширине таб-бара. Для этого линию держит .head-card,
       а сам бар растягиваем на высоту шапки — тогда подчёркивание активной
       вкладки ложится ровно на неё */
    body .head-card:has(.proj-header > .tab-bar) { border-bottom: 1px solid var(--border); }
    body .head-card:has(.proj-header > .tab-bar) > .inner { align-items: stretch; }
    body .head-card .proj-header > .tab-bar { align-self: stretch; border-bottom: none; }
    /* Подпись вкладки ближе к линии: снизу вдвое меньше воздуха, чем сверху */
    body .head-card .proj-header > .tab-bar > .tab {
      align-items: flex-end; padding-bottom: 13px;
    }
    /* Мало места — таб-бар целиком уходит под заголовок, а не ужимает его до
       многоточия. Перенос даёт flex-basis по содержимому: с flex:1 (базис 0)
       бар не переносился, а сжимался. Высота шапки при этом считается по
       содержимому — иначе вторая строка обрезалась бы по фиксированным 48px */
    body .head-card .proj-header:has(> .tab-bar) { flex-wrap: wrap; row-gap: 4px; }
    body .head-card .proj-header > .tab-bar { flex: 1 1 auto; }
    /* Поле только сверху: снизу таб-бар должен лечь подчёркиванием ровно на
       линию карточки, а сверху заголовку нужен воздух — без него он слипался
       с табами, когда бар переносится на свою строку */
    body .head-card:has(.proj-header > .tab-bar) > .inner {
      height: auto; min-height: 48px; padding-top: 6px;
    }
    /* В кадре название страницы скрыто — воздуху над вкладками не для чего
       стоять, шапка области и так отделяет их сверху */
    html.in-frame .head-card:has(.proj-header > .tab-bar) > .inner { padding-top: 0; }
    /* Каталоги — исключение: их полоса разделов переносится на вторую строку,
       и без воздуха сверху вкладки упираются в шапку области */
    html.in-frame .head-card:has(.proj-header > .knw-tabs) > .inner { padding-top: 9px; }

    /* Шапки — одной высоты 52px: блок пространства в сайдбаре и заголовок
       страницы стоят на одной линии, как две половины одной строки */
    /* Имя пространства отбито от края панели так же, как заголовок страницы
       от края своей карточки — 20px */
    /* Шапка пуста (имя уехало к пилюлям) — осталась прокладкой-высотой,
       курсор и подсветка наведения ей больше не нужны */
    body .logo { height: 48px; padding-left: 20px; pointer-events: none; }
    body .head-card .inner { height: 48px; }
    /* Подпись «Рабочее пространство» убрана — имя и знак говорят сами за себя */
    body .logo .logo-sub { display: none; }
    body .logo-name { margin-bottom: 0; }

    /* Пилюли пространств — спокойные серые плашки с буквой: без градиента,
       без теней и без подпрыгивания под курсором */
    body .ws-pill,
    body .logo-mark {
      background: #e7eaf0; color: #55637a; box-shadow: none;
    }
    body .ws-pill:hover { background: #dbe0e9; transform: none; box-shadow: none; }
    body .ws-pill.active {
      background: #cfd6e2; color: #33415a; box-shadow: none;
    }
    body .ws-pill.active:hover { background: #c6cedd; transform: none; }

    /* Аватары в списке чатов и в ленте истории — тоже без цвета: цветные кружки
       перетягивали внимание с самих сообщений. !important — заливка приходит
       инлайном из разметки строки */
    body #viewChats :is(.chat-row-ava, .mini-ava) {
      background: #e7eaf0 !important; color: #55637a; box-shadow: none;
    }

    /* «В работу» переехала за поиск — отбиваем её от него, а правый отступ
       строки снимаем: кнопка встаёт по краю окна, как пилюли слева */
    /* Своего отступа у кнопки нет — зазор до поиска задаёт gap самой строки */
    body #mainTopbar > .task-btn { margin-left: 0; }
    body #mainTopbar { padding-right: 0; }
    /* Свёрнутый поиск — одного размера и скругления с «В работу» рядом */
    body .topbar.search-collapsed .topbar-search {
      width: 34px; height: 34px; flex: 0 0 34px; border-radius: 10px;
    }

    /* Имя пространства крупнее, заголовок страницы мельче: слева — контекст,
       справа — экран внутри него */
    /* Имя пространства и заголовок страницы — одним начертанием: две части
       одной строки, спорить друг с другом им незачем */
    body .logo-name { font-size: 16px; font-weight: 500; }
    /* Знак пространства в шапке сайдбара не нужен: он же стоит пилюлей в первой
       строке, а имя и без него читается */
    body .logo .logo-icon { display: none; }
    /* Заголовок страницы обычным начертанием: рядом стоят вкладки, и жирный
       текст спорил с активной из них */
    body .head-card .proj-title { font-size: 16px; font-weight: 500; }

    /* Первая секция навигации ближе к шапке пространства — вдвое меньше воздуха */
    body .sidebar-body > .nav-section:first-child { padding-top: 5px; }

    /* Строки списка задач оформлены как задачи в сценарии потока: белая заливка,
       тонкая рамка и та же тень. Прозрачную рамку тут держали намеренно —
       теперь она общая для всех списков. Строки-нарушения сохраняют свою
       розовую гамму, наведение по-прежнему подсвечивает только рамку */
    body #viewWorkTasks #wt-all .item-row:not(:has(.item-name.danger)) {
      border-color: #e6eaf2;
    }
    /* Строка-нарушение — рамка своей, розовой гаммы (без неё плашка «плавала») */
    body #viewWorkTasks #wt-all .item-row:has(.item-name.danger) {
      border-color: #f3d4d1;
    }

    /* Подпись «название» встаёт над именами задач: в шапке код — простой текст,
       и он у́же плашки кода в строке. Ширина = плашке с кодом вида «ЗД-0047» */
    body :is(#viewWorkTasks, #wt-all) .item-head .item-id { width: 67px; }

    /* У счётчика проблем своя межстрочная (10px), и общая компенсация сажала
       цифру ниже середины — здесь она не нужна */
    body .tab .tab-alert-count { padding-top: 0; }

    /* Счётчики «требуют внимания» — тем же кружком, что счётчик проблем на
       вкладке «Все» (.tab-alert-count): в сайдбаре у «Работ» и на вкладке «Мои»
       он значит то же самое, поэтому и выглядеть должен одинаково */
    body .nav-item.attn > .nav-badge.count,
    body .tab > .nav-badge.count {
      padding: 0 4px; border-radius: 9px;
      background: #efa39d; color: #fff;
      font-size: 10px; font-weight: 600; line-height: 1; padding-top: 0;
      box-shadow: none;
    }
    body .tab.active > .nav-badge.count { background: #e74c3c; }

    /* Разделительной линии под «Рабочими данными» нет: разделы навигации и так
       разведены отступами */
    body .sidebar-body .config-node {
      border-bottom: none;
      /* и без отбивки снизу: пункты навигации идут единым списком */
      padding-bottom: 0; margin-bottom: 0;
    }

    /* Разделитель между пространствами и хлебными крошками: слева — где я
       работаю, справа — где нахожусь */
    /* Ряд пространств занимает ровно колонку сайдбара, поэтому крошки начинаются
       от его правой границы — как и содержимое страницы под ними.
       Ширина считается от --sidebar-w, так что при перетаскивании панели
       крошки едут вместе с ней. Со скрытым сайдбаром ряд снова по содержимому */
    /* Ширина ряда — не меньше сайдбара (крошки начинаются от его границы),
       но имя пространства у пилюли может вытолкнуть крошки правее */
    body #mainTopbar > .ws-pills-flat {
      margin-right: 0; padding-right: 0; border-right: none;
      min-width: calc(var(--sidebar-w, 265px) - 4px); width: auto;
    }
    body.sb-hidden #mainTopbar > .ws-pills-flat { min-width: 0; }
    body #mainTopbar > .breadcrumb { margin-left: 14px; }

    /* Содержимое шапок опущено к линии: заголовок, имя пространства и кнопки
       справа встают на один уровень с подписями вкладок, а не выше них */
    body .head-card .proj-title,
    body .logo-name { position: relative; top: 1px; }
    body .head-card .tab-bar > .tab-bar-actions { position: relative; top: 3px; }

    /* Шеврон раскрытия ловит клик квадратом во всю высоту строки: сама стрелка
       9px, попасть в неё мышью было тяжело. Ширина в раскладке прежняя —
       область расширяет псевдоэлемент, поэтому строка не разъезжается */
    body .sidebar .tree-arrow:not(.empty) { position: relative; }
    body .sidebar .tree-arrow:not(.empty)::after {
      content: ''; position: absolute; top: 50%; left: 50%;
      width: 30px; height: 30px; transform: translate(-50%, -50%);
    }
    /* У вложенных строк строка ниже (26px) — квадрат по её высоте */
    body .sidebar .tree-children .tree-arrow:not(.empty)::after,
    body .sidebar .chat-list .tree-arrow:not(.empty)::after { width: 26px; height: 26px; }

    /* Шапка окна создания задачи — той же высоты, что шапки страниц */
    body .nt-head { height: 48px; padding-top: 0; padding-bottom: 0; }
    /* Тело окна белое, как области страниц */
    body .nt-body { background: #fff; }

    /* «+» и «×» в строке значения — одна группа кнопок, поэтому стоят вплотную */
    body .field-row > .proj-data-add + .proj-data-del { margin-left: 2px; }
    /* ...но когда строчный «+» спрятан (плюс ушёл в шапку мульти-поля),
       группы нет: крестик отбивается от значения так же, как в строках ниже */
    body .multi-field:is(.mf-stacked, :has(.multi-extra)) .field-row > .proj-data-add + .proj-data-del { margin-left: 8px; }
    /* То же для крестика всего параметра: он идёт сразу за «плюсом» строки,
       а не отдельно у правого края */
    body .proj-data-field.multi-field > .proj-data-del { margin-left: -8px; }

    /* Чип ограничений и крестик — по центру строки с названием параметра:
       чип на 20px выше подписи, а крестик вынут из потока, поэтому их центры
       расходились на пару пикселей */
    body .proj-data-field.field-stacked > .lim-chip { margin-top: -2px; }
    body .proj-data-field.field-stacked > .proj-data-del { top: 9.5px; }

    /* Подсказка экрана скрыта — содержимое встаёт сразу под линией заголовка:
       прежние 20px убраны, верхний отступ первого блока тоже гасим, чтобы
       они не складывались (иначе на разных страницах выходит по-разному) */
    body :is(.content, .flow-main-col) > .body-area:has(> .screen-hint[style*="display: none"]),
    body :is(.content, .flow-main-col) > .body-area:not(:has(> .screen-hint)) { padding-top: 0; }
    /* Верхние отступы первого блока (и его первых потомков — margin складывается
       наружу) гасим, иначе на разных страницах выходит 20, 30 и больше */
    body .body-area > .screen-hint[style*="display: none"] + *,
    body .body-area > .screen-hint[style*="display: none"] + * > :first-child,
    body .body-area > .screen-hint[style*="display: none"] + * > :first-child > :first-child,
    body :is(.content, .flow-main-col) > .body-area:not(:has(> .screen-hint)) > :first-child,
    body :is(.content, .flow-main-col) > .body-area:not(:has(> .screen-hint)) > :first-child > :first-child {
      margin-top: 0;
    }
    /* Фильтр-бар — исключение из правила выше: к линии заголовка он не привязан,
       и прижатый вплотную выглядел съехавшим. Держим сверху то же поле, что и
       снизу. !important — гаситель выше собран из :is/:not/:has и специфичнее
       любого разумного селектора для одного бара */
    body .body-area .plan-filter-bar { margin-top: 10px !important; }

    /* Линия под вкладками идёт от края до края карточки: держит её сама шапка,
       а не таб-бар (он начинается с отступа). Закладка чата переехала в заголовок,
       так что прятать линию под ней больше не нужно */
    body .content > .flow-main-col > .sticky-header {
      border-bottom: 1px solid var(--border);
    }
    body .content > .flow-main-col > .sticky-header > .tab-bar { border-bottom: none; }

    /* Непрочитанных нет — закладка нейтрально-серая, а ноль в иконке не рисуем */
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].no-unread:not(.chat-on) {
      background: #eef0f4;
    }
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].no-unread:not(.chat-on):hover {
      background: #e4e8ef;
    }
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"].no-unread .count-chip {
      display: none;
    }

    /* При создании задачи исполнителя не выбирают — его подставит поток,
       поэтому «Кем выполняется» в окне не показываем */
    body .nt-modal .proj-data-field[data-multi="doer"] { display: none; }

    /* Ручка перетаскивания параметра: висит слева за пределами поля и появляется
       при наведении — в самой строке места не занимает, раскладка не прыгает */
    body .proj-data-field.param-has-grip { position: relative; }
    body .param-grip {
      /* Внутри поля, в его левом отступе: при наведении ручка появляется слева
         от названия и ничего не сдвигает. Высота = строке поля, выключка по
         центру — так ручка встаёт на одну линию с названием, а не над ним */
      position: absolute; left: 2px; top: 0; height: 40px;
      display: none; align-items: center; margin: 0; padding: 0;
    }
    body .proj-data-field:hover > .param-grip { display: inline-flex; }
    /* Линия места вставки — как у строк списка */
    body .proj-data-field.row-drop-before::after,
    body .proj-data-field.row-drop-after::after { left: 0; right: 0; }

    /* Поля-параметры без рамки и тени: подряд их бывает под десяток, и тени
       давали рябь. Подложка остаётся — она отделяет поле от белой колонки
       и показывает, что строка интерактивна. Наведение отзывается той же
       подложкой на тон темнее, а не всплывающей тенью */
    body .proj-data-field { border: none; box-shadow: none; transition: background .12s; }
    body .proj-data-field:hover { box-shadow: none; background: #eef2f8; }

    /* ── Секция параметров — панель как колонка канбана ──
       Плашек было столько же, сколько полей, и колонка рябила. Теперь плашка
       одна на секцию: заливка, скругление, тень и внутренние поля взяты
       у .kanban-col, шапка — у .kanban-col-head. Сами поля лежат плоско */
    body .proj-data-section {
      /* По бокам поля нет: заголовок и строки идут от самой рамки, а линии
         между ними дотягиваются до неё, а не обрываются в отступе */
      padding: 10px 0;
      /* Панель держит рамка: заливки нет, поля лежат прямо на фоне страницы */
      background: transparent; border-radius: 12px;
      border: 1px solid rgba(16,32,64,.10);
      box-shadow: none;
    }
    /* Окно новой задачи повторяет вкладку «Данные» задачи: там секции
       без карточной рамки — заголовок, разделительная линия и поля */
    body .nt-modal .proj-data-section {
      border: none; border-radius: 0; padding: 8px 0 0;
    }
    body .nt-modal .proj-data-section:not(:last-child) { border-bottom: 1px solid var(--border); padding-bottom: 8px; }
    body .proj-data-section > .proj-data-section-head {
      min-height: 0; margin-top: 0; margin-bottom: 6px;
      /* Слева — те же 16px, что у содержимого строк: заголовок и названия
         полей встают на одну вертикаль, линия под ним по-прежнему от рамки */
      padding: 3px 5px 7px 16px; gap: 7px;
      font-size: 12.5px; color: #3d4655;
      /* Та же линия, что делит поля между собой: заголовок отделён от списка */
      border-bottom: 1px solid rgba(16,32,64,.10);
      /* Секции не сворачиваются — заголовок не кнопка */
      cursor: default;
    }
    /* Ведущий шеврон сворачивал секцию — сворачивания больше нет */
    body .proj-data-section > .proj-data-section-head > svg:first-child { display: none; }
    body .proj-data-section > .proj-data-section-head:hover { background: transparent; }

    /* Поля внутри панели — без собственной подложки, соседние делит линия.
       Линию вешаем через «+»: тогда её нет ни перед первым полем, ни после
       последнего, что бы ни стояло в секции до и после списка */
    body .proj-data-section > .proj-data-field {
      background: transparent; border-radius: 0; box-shadow: none;
      margin-bottom: 0;
    }
    body .proj-data-section > .proj-data-field + .proj-data-field {
      border-top: 1px solid rgba(16,32,64,.10);
    }
    body .proj-data-section > .proj-data-field:hover { background: rgba(255,255,255,.5); }

    /* Остальное содержимое секции — описание и теги — отбито от рамки на те же
       16px, что заголовок и строки. У описания отступ прописан инлайном в
       разметке десятка страниц, перебить его можно только !important */
    body .proj-data-section > div:not([class]) {
      padding-left: 16px !important; padding-right: 16px !important;
    }
    body .proj-data-section > .tag-row { padding-left: 16px; padding-right: 16px; }

    /* В окне создания задачи колонки скроллятся каждая сама: длинный список
       параметров справа не тянет за собой описание слева */
    body .nt-body { overflow: hidden; }
    body .nt-grid { min-height: 0; }
    body .nt-grid > * { overflow-y: auto; min-height: 0; padding-right: 6px; }
    /* Последняя секция колонки идёт без нижнего отступа: колонка растянута ровно
       по высоте сетки, и эти 10px давали полосу прокрутки на пустом месте.
       Низ окна держит padding у .nt-body */
    body .nt-grid > * > .proj-data-section:last-child { margin-bottom: 0; }

    /* Кнопки-иконки рядом с «Добавить» (три точки, подсказка, плюс) подсвечиваются
       тем же бирюзовым, что и она сама — одна группа действий, один отклик */
    body :is(.tab-more, .more-btn):hover {
      background: #d3ecef; border-color: transparent; color: #056470;
    }

    /* Чипы на карточке канбана — одной бледной подложкой: код, даты, часы и
       статус перестают спорить друг с другом, статус читается цветом текста.
       Плотные статусы («Закрыта» с белым текстом) остаются как были */
    body .kanban-card :is(.item-id, .ichip-dates, .ichip-hours, .kc-objs,
      .ichip-status:not(.st-closed-ok):not(.st-closed-no)) {
      background: #f2f4f8;
    }

    /* Цифра в счётчике — строго по центру: у цифр нет нижних выносных, поэтому
       обычное центрирование сажает их выше середины. Компенсируем верхним
       отступом; высота фиксирована (border-box), так что размер не растёт */
    body :is(.count-chip, .k-count, .tab-alert-count, .nav-badge) {
      display: inline-flex; align-items: center; justify-content: center;
      box-sizing: border-box; height: 18px; line-height: 1; padding-top: .22em;
      /* min-width = высоте: у однозначных чисел получается ровный круг,
         у двузначных — аккуратная пилюля того же радиуса */
      min-width: 18px; border-radius: 999px;
    }
    /* Счётчик в закладке чата вписан в саму иконку — её размер и задаёт рамки.
       Отступ сверху опускает цифру от верхней линии пузыря к его середине
       (низ иконки занят «хвостиком», поэтому геометрический центр выше нужного) */
    body :is(.sticky-header, .head-card > .inner) > .tab[onclick*="chat-panel"] .count-chip { height: auto; padding-top: 3px; }

    /* Счётчик строк в шапке группы — кружком: это число, а не чип-значение */
    body .gantt-group-head .count-chip {
      display: inline-flex; align-items: center; justify-content: center;
      box-sizing: border-box; min-width: 20px; height: 20px;
      padding: 0 6px; border-radius: 999px; font-size: 11.5px; line-height: 1;
    }

    /* Включённые дни недели — как значения параметров */
    body .week-days .wd { background: #d3ecef; color: #056470; }
    body .week-days .wd.off { background: transparent; color: #b3bdca; box-shadow: inset 0 0 0 1px var(--border); }
    body .week-days .wd:hover { background: #c2e4e8; color: #044f5a; }
    body .week-days .wd.off:hover { background: transparent; color: #8b95a5; }

    /* ── Чип кода: иконка типа вместо кода ──────────────────────────────────
       В чипе видна иконка типа сущности, сам код скрыт (его читают из разметки
       десятки мест app.js) и показывается в карточке по наведению вместе с
       названием типа и командами работы над сущностью */
    /* Квадрат под иконку: горизонтальные отступы кода тут лишние, вертикальные
       наоборот добираем до квадрата. Правило Ганта бьёт по id — повторяем его */
    .eid-chip,
    #wt-gantt .gantt-row .gantt-label .item-id.eid-chip {
      display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
      width: 22px; height: 22px; padding: 0;
    }
    .eid-inline { cursor: pointer; }
    .eid-code { display: none; }
    /* Значок перед названием в ссылках «код · название» */
    .eid-inline { display: inline-flex; align-items: center; vertical-align: -2px; margin-right: 5px; }
    .eid-chip .eid-ico { display: inline-flex; align-items: center; color: #7d8aa0; }
    /* Значок типа стоит перед названием, а не в чипе: тип читается вместе с
       именем, а чип рядом остаётся кнопкой меню с многоточием */
    .eid-name-ico {
      display: inline-flex; align-items: center; vertical-align: -2px;
      margin-right: 5px; color: #7d8aa0;
    }
    .eid-chip:hover .eid-ico { color: #16345c; }
    /* В строках списка чип появляется только под курсором, и своими 22px он
       перерастал строку — она подпрыгивала на 2px при наведении. Ужимаем его
       до высоты остального содержимого строки */
    .item-row > .item-id.eid-chip { height: 20px; }
    /* Иконка подтипа ресурса уехала внутрь чипа — её собственный отступ там лишний */
    .eid-chip .res-ico { margin-right: 0; }

    .eid-pop {
      position: fixed; display: none; z-index: 4000; min-width: 210px;
      background: #fff; border-radius: 10px; padding: 5px 0;
      box-shadow: 0 10px 28px rgba(15,30,60,0.16), 0 0 0 1px rgba(0,0,0,0.05);
      animation: fadeIn 0.12s ease both;
    }

    /* «Затрачено часов» — сумма по дням: пилюля открывает попап, где часы
       проставляются на каждый день срока работы. Итог возвращается в пилюлю */
    .proj-data-pill.hours-pill { cursor: pointer; transition: background .12s; }
    .proj-data-pill.hours-pill:hover { background: #d5eff1; }
    /* «Затрачено» и «осталось» стоят друг под другом — одна ширина и «ч»
       у правого края: числа читаются столбиком. У поля ввода единица лежит
       поверх — внутрь number-инпута букву не положить */
    .hours-pill, .hours-box > :is(.hours-left, .hours-plan) {
      box-sizing: border-box; width: 78px;
      display: inline-flex; align-items: center; justify-content: flex-end;
    }
    .hours-box { position: relative; display: inline-flex; align-items: center; }
    .hours-box > :is(.hours-left, .hours-plan) { padding-right: 24px; text-align: right; }
    /* План правится на месте: кнопка согласования появляется только когда
       значение отличается от согласованного, исходное — у названия */
    .plan-agree { display: none; }
    .proj-data-field.plan-changed .plan-agree { display: inline-flex; }
    .plan-was { margin-left: 8px; }
    .hours-unit { position: absolute; right: 11px; font-size: 11.5px; color: inherit; pointer-events: none; }
    .hours-box:has(.hours-left:focus) .hours-unit { color: #00727d; }
    /* Перерасход: затрачено больше плана — или столько выйдет вместе с остатком */
    /* Прогноз не правят — он считается из затрат и остатка: показываем его тем
       же серым чипом, что и readonly-значения «Назначения» (исполнитель, сроки) */
    .proj-data-pill.hours-forecast,
    /* Подсветки под курсором у него нет: нажимать не на что — общее правило
       наведения на значения перебиваем тем же селектором с :hover */
    body .proj-data-val .proj-data-pill.hours-forecast:hover {
      background: #e3e6ee; color: #5a6b86; cursor: default;
    }
    .proj-data-pill.hours-pill.over { background: #fde8ee; color: #b4275a; }
    .proj-data-pill.hours-pill.over:hover { background: #fbdae4; }
    .data-input.hours-left.over { background-color: #fde8ee; color: #b4275a; }
    .data-input.hours-left.over:hover { border-color: #f0b9cc; }
    .data-input.hours-left.over:focus { border-color: #d94b7d; background: #fff; }
    .hours-box:has(.hours-left.over) .hours-unit { color: #b4275a; }
    .hours-pop {
      position: fixed; display: none; z-index: 4000; width: 232px;
      background: #fff; border-radius: 10px; padding: 6px;
      box-shadow: 0 10px 28px rgba(15,30,60,0.16), 0 0 0 1px rgba(0,0,0,0.05);
      animation: fadeIn 0.12s ease both;
    }
    .hours-pop-head { padding: 3px 6px 6px; font-size: 11px; font-weight: 600; color: var(--text-secondary); }
    .hours-pop-body { max-height: 258px; overflow-y: auto; }
    .hours-pop-row {
      display: flex; align-items: center; gap: 6px;
      padding: 2px 6px; border-radius: 7px; font-size: 12px; color: var(--text-primary);
    }
    .hours-pop-row:hover { background: #f1f4f9; }
    /* Выходной день бледнее: часы там ставят как исключение */
    .hours-pop-row.off .hours-pop-day { color: #a9b6c8; }
    .hours-pop-day { flex: 1; min-width: 0; }
    .hours-pop-inp { width: 54px; text-align: right; }
    .hours-pop-unit { width: 9px; color: var(--text-secondary); }
    .hours-pop-foot {
      display: flex; align-items: center; justify-content: space-between;
      margin-top: 4px; padding: 6px 6px 2px; border-top: 1px solid #eef1f6;
      font-size: 12px; color: var(--text-secondary);
    }
    .hours-pop-foot b { color: var(--text-primary); }

    /* Таб-тумблер чата на vibe-страницах — в первой строке заголовка справа
       (туда его переносит app.js): иконка мини/макс, как у кнопки панели;
       счётчик непрочитанных — кружком в правом верхнем углу иконки */
    :is(.vibe-sticky, .proj-header-right) .tab[data-chat-toggle] {
      margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
      position: relative; width: 30px; min-height: 30px; padding: 0;
      background: transparent; color: var(--text-secondary); border-radius: 8px;
    }
    :is(.vibe-sticky, .proj-header-right) .tab[data-chat-toggle]:hover {
      background: rgba(15, 30, 60, .06); color: var(--text-primary);
    }
    /* Колонка видна — «развернуть страницу», скрыта — «вернуть колонку» */
    .tab[data-chat-toggle] .vet-ico { display: none; align-items: center; }
    .tab[data-chat-toggle].active .vet-max { display: inline-flex; }
    .tab[data-chat-toggle]:not(.active) .vet-min { display: inline-flex; }
    /* Счётчик непрочитанных нужен только у свёрнутой колонки: открытая
       лента и так на экране. Селектор не слабее правила позиционирования
       кружка ниже — иначе его display: flex побеждал бы */
    :is(.vibe-sticky, .proj-header-right) .tab[data-chat-toggle].active > .count-chip { display: none; }
    :is(.vibe-sticky, .proj-header-right) .tab[data-chat-toggle] > .count-chip {
      position: absolute; top: -4px; right: -6px; margin: 0;
      box-sizing: border-box; min-width: 16px; height: 16px; padding: 0 3px;
      display: flex; align-items: center; justify-content: center;
      border-radius: 9px; border: 2px solid #fff;
      font-size: 9px; font-weight: 700; line-height: 1;
    }
    .vibe-sticky .tab[data-chat-toggle] ~ .tab-bar-actions { margin-left: 8px; }
    /* Пока в «Выполнении» есть проблемы, его таб красный — видно, не открывая
       раздел. Селекторы с .tab-bar: компактные табы задаёт leftbar.css ниже */
    .tab-bar .tab.tab-issues { color: #c0392f; }
    .tab-bar .tab.tab-issues:hover { background: #fdeceb; color: #a52f26; }
    .tab-bar .tab.tab-issues.active { background: #f7d2cf; color: #a52f26; }
    .tab-bar .tab.tab-issues > .count-chip { background: #f7d2cf; color: #a52f26; }
    .tab-bar .tab.tab-issues.active > .count-chip { background: #f2bfbb; }
    /* Счётчик — как у кнопки прыжка к непрочитанным (.cj-count): бирюзовый
       круг с белой цифрой; бледная заливка на сером табе была не видна */
    :is(.vibe-sticky, .proj-header-right) :is(.tab[data-chat-toggle], .tab[data-sec="sec-chat"]) .count-chip.tab-cnt-green {
      background: var(--teal); color: #fff;
    }

    /* ── Чат сущности: кнопка статуса, строка-сводка и карточки в ленте ── */
    .vibe-status-wrap { position: relative; flex-shrink: 0; }
    .vibe-status {
      display: inline-flex; align-items: center; gap: 5px; height: 24px;
      padding: 0 10px; border: none; border-radius: 999px; cursor: pointer;
      font-size: 11.5px; font-weight: 600; transition: filter .12s;
    }
    .vibe-status:hover { filter: brightness(.96); }
    .vibe-status.st-todo  { background: #eef1f6; color: #55647f; }
    .vibe-status.st-doing { background: #d9f2e7; color: #0f6e56; }
    .vibe-status.st-pause { background: #faeeda; color: #854f0b; }
    .vibe-status.st-done  { background: #e6f1fb; color: #185fa5; }
    .vibe-status-menu {
      display: none; position: absolute; top: calc(100% + 6px); left: 0; z-index: 60;
      min-width: 150px; background: #fff; border-radius: 10px; padding: 5px 0;
      box-shadow: 0 10px 28px rgba(15,30,60,.16), 0 0 0 1px rgba(0,0,0,.05);
    }
    .vibe-status-wrap.open .vibe-status-menu { display: block; }
    .vibe-status-item { padding: 7px 14px; font-size: 12.5px; cursor: pointer; white-space: nowrap; }
    .vibe-status-item:hover { background: #f1f4f9; }
    /* Значок в шапке чата — кнопка «Данные» (клик открывает vibe-страницу),
       меню «···» тут нет: чип скрыт, иконка типа остаётся и под курсором */
    .vibe-chat-head .head-mark .eid-chip { display: none !important; }
    .vibe-chat-head .head-mark:hover > .eid-name-ico { opacity: 1; }
    /* В шапке чата статус — чёрной кнопкой, как статус в шапке страницы,
       и у правого края колонки; меню открывается от правого края кнопки */
    .vibe-chat-head .vibe-status-wrap { margin-left: auto; }
    .vibe-chat-head .vibe-status {
      background: #1e2a3a; color: #fff; height: 28px; padding: 0 12px;
      border-radius: 8px; font-size: 12px; font-weight: 600;
    }
    .vibe-chat-head .vibe-status:hover { background: #33415a; filter: none; }
    .vibe-chat-head .vibe-status-menu { left: auto; right: 0; }
    /* Крестик — у правого края и без статуса в шапке (статус живёт в таб-баре,
       в шапке чата он остаётся только в доке) */
    .vibe-chat-head .vibe-chat-close { margin-left: auto; }
    .vibe-chat-head .vibe-status-wrap ~ .vibe-chat-close { margin-left: 0; }
    /* Статус в строке заголовка — у правого края, перед служебными кнопками */
    .proj-header > .vibe-status-wrap { margin-left: auto; order: 4; }
    .proj-header > .vibe-status-wrap ~ :is(.page-max, .page-close) { margin-left: 2px; }
    /* Распорку до правого края держит только статус — иначе соседний
       .proj-header-right со своим margin-left:auto делил бы её пополам.
       Пустая обёртка (кнопки уехали в таб-бар) съедала бы ещё gap строки */
    .proj-header:has(> .vibe-status-wrap) > .proj-header-right { margin-left: 8px; }
    .proj-header:has(> .vibe-status-wrap) > .proj-header-right:empty { display: none; }
    /* Меню статуса выше липкой шапки с табами (z-index 30). Своего z-index
       ему мало: .proj-header.ani из-за анимации создаёт отдельный слой,
       поэтому поднимаем шапку целиком */
    .proj-header .vibe-status-menu { z-index: 200; }
    .head-card:has(.vibe-status-wrap) { position: relative; z-index: 40; }
    /* Строка работы в «Планировании»: навык и статус чипами, исполнитель
       и часы факт/план — у правого края */
    .work-row { cursor: pointer; }
    .work-row .item-name { flex: 1; min-width: 0; }
    .work-row .item-chips { width: auto; justify-content: flex-start; flex-shrink: 0; }
    .work-row .tr-who { flex-shrink: 0; color: var(--text-secondary); font-size: 12px; }
    /* Часы факт/план — таким же чипом, как навык и статус, и правее них:
       это тоже значение строки, а не подпись к имени */
    .work-row .work-hours {
      order: 7; flex-shrink: 0; text-align: right;
      font-size: 10.5px; font-weight: 400; line-height: 1;
      padding: 3px 8px; border-radius: 5px; white-space: nowrap;
      background: #eef0f4; color: #50607a;
    }
    .proj-header .vibe-status {
      background: #1e2a3a; color: #fff; height: 28px; padding: 0 12px;
      border-radius: 8px; font-size: 12px; font-weight: 600;
    }
    .proj-header .vibe-status:hover { background: #33415a; filter: none; }
    .proj-header .vibe-status-menu { left: auto; right: 0; }
    /* Статус в таб-баре (справа от «Добавить») — той же чёрной кнопкой */
    .tab-bar-actions .vibe-status {
      background: #1e2a3a; color: #fff; height: 28px; padding: 0 12px;
      border-radius: 8px; font-size: 12px; font-weight: 600;
    }
    .tab-bar-actions .vibe-status:hover { background: #33415a; filter: none; }
    .tab-bar-actions .vibe-status-menu { left: auto; right: 0; }

    /* Строка-сводка выполнения: общий ход работ, клик раскрывает список */
    .chat-exec-strip {
      display: flex; align-items: center; gap: 8px; cursor: pointer;
      height: 34px; padding: 0 12px; border: 1px solid var(--border); border-radius: 10px;
      background: #fff; font-size: 12.5px; font-weight: 600; color: #1e2a3a;
      transition: border-color .15s;
    }
    .chat-exec-strip + .chat-exec-strip { margin-top: 6px; }
    .chat-exec-body + .chat-exec-strip { margin-top: 6px; }
    .chat-exec-strip:hover { border-color: var(--border-mid); }
    .chat-exec-strip .cx-pct { font-size: 11px; font-weight: 600; color: var(--text-secondary); flex-shrink: 0; }
    .chat-exec-strip .strip-chev { color: #8a97a8; flex-shrink: 0; transition: transform .15s; }
    .chat-exec-strip.open .strip-chev { transform: rotate(180deg); }
    .chat-exec-body { padding-top: 6px; }

    /* Строка задачи в сводке: имя тянется, статус и исполнитель — справа
       в той же строке; обёртку чипа не растягиваем до 118px общего правила */
    #vibeChatExec .item-row .tr-name { flex: 1; min-width: 0; order: 1; }
    #vibeChatExec .item-row .item-chips { width: auto; justify-content: flex-start; flex-shrink: 0; order: 3; }
    #vibeChatExec .item-row .tr-who { flex-shrink: 0; order: 4; }
    /* Строки сводки — такими же итемами, как участники (.proj-data-field):
       белая карточка со светлой рамкой #e6eaf2 без тени, то же скругление
       и поля, наведение отвечает подложкой, а не рамкой; зазор 6px.
       Списки отбиты слева от заголовка-строки, правые края ровные */
    /* Списки сводок выровнены по левому краю своих строк-заголовков */
    :is(#vibeChatExec, #vibeChatPeople, #vibeChatArts) { margin-left: 0; }
    #vibeChatExec .item-row {
      border: 1px solid #e6eaf2; border-radius: 12px; background: #fff;
      padding: 9px 16px;
    }
    #vibeChatExec .item-row + .item-row { margin-top: 6px; }
    /* Наведение — рамкой и тенью, как у строк участников ниже; фон не трогаем */
    #vibeChatExec .item-row:hover {
      background: #fff; border-color: #aebdd3;
      box-shadow: 0 2px 8px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04);
    }
    /* Чип «···» (меню сущности, виден по наведению) — в первой строке слева
       от статуса: общий order:5 уносил его за полосу прогресса на новую строку.
       Высота — не выше первой строки текста, иначе появление чипа под курсором
       подращивало строку и рамка прыгала на 2px */
    #vibeChatExec .item-row > .item-id.eid-chip { order: 2; height: 18px; }
    #vibeChatExec .item-row .cx-prog { order: 5; }
    /* Иконка строки-сводки — заметнее; flex-сжатие запрещено, иначе полоса
       прогресса ужимала её обратно */
    .chat-exec-strip > svg:first-child { width: 16px; height: 16px; flex-shrink: 0; }

    /* Карточка задачи, поставленной из чата, — живёт в ленте на месте поручения */
    .chat-task-card {
      border: 1px solid var(--border); border-radius: 10px; background: #fff;
      padding: 9px 12px; margin: 6px 0; cursor: pointer; max-width: 440px;
      transition: border-color .15s, box-shadow .15s;
    }
    .chat-task-card:hover { border-color: var(--border-mid); box-shadow: 0 2px 8px rgba(15,30,60,.06); }
    .chat-task-card .ct-top { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: #1e2a3a; }
    .chat-task-card .ct-sub { font-size: 11.5px; color: var(--text-secondary); margin-top: 2px; }
    .chat-task-card .cx-prog { display: block; margin-top: 7px; }
    /* Карточка результата — файлом, следом за задачей */
    .chat-res-card {
      display: flex; align-items: center; gap: 8px; max-width: 440px;
      border: 1px solid var(--border); border-radius: 10px; background: #fff;
      padding: 8px 12px; margin: 6px 0; font-size: 12.5px; color: #1e2a3a; cursor: pointer;
      transition: border-color .15s;
    }
    .chat-res-card:hover { border-color: var(--border-mid); }

    /* Ручка на правой грани карточки страницы: тянет границу с колонкой чата.
       Занимает штатный зазор ряда отрицательными полями, линия — по центру */
    .vibe-chat-resizer {
      flex: 0 0 8px; margin: 0 -8px; align-self: stretch;
      position: relative; cursor: col-resize; z-index: 30; touch-action: none;
    }
    .vibe-chat-resizer::before {
      content: ''; position: absolute; top: 0; bottom: 0; left: 50%; width: 1px;
      background: transparent; transition: background .12s;
    }
    .vibe-chat-resizer:hover::before,
    body.sidebar-resizing .vibe-chat-resizer::before { background: #b9c2d0; }
    body.vibe-chat-hidden .vibe-chat-resizer { display: none; }

    /* Чат-панель: колонка чата сущности рядом с контентом текущей страницы.
       Внутри фрейма — vibe-страница сущности в режиме «только чат» */
    .chat-dock {
      /* Той же ширины, что родная колонка чата vibe-страниц: панель встаёт
         на её место и область чата остаётся одной */
      flex: 0 0 var(--left-col-def, 460px); min-width: 0;
      position: relative; display: none;
    }
    .chat-dock.open { display: block; }
    .chat-dock-frame { width: 100%; height: 100%; border: none; }
    .chat-dock-x {
      position: absolute; top: 12px; right: 14px; z-index: 5;
      width: 26px; height: 26px; border: none; border-radius: 8px;
      background: transparent; color: #7c8aa0; cursor: pointer;
      display: flex; align-items: center; justify-content: center;
    }
    .chat-dock-x:hover { background: #eef1f6; color: #33415a; }
    /* Крестик переехал в шапку чата внутри фрейма (.vibe-chat-close) — свой
       плавающий у дока скрыт, но остаётся целью для vibeChatDockClose */
    .chat-dock > .chat-dock-x { display: none; }
    /* Ручка панели видна только вместе с ней; во время движения фрейм не
       перехватывает указатель — иначе ручка «отлипает» */
    .chat-dock-resizer { display: none; }
    /* Док теперь слева от карточки, ручка идёт следом за ним */
    .chat-dock.open + .chat-dock-resizer { display: block; }
    body.sidebar-resizing .chat-dock-frame { pointer-events: none; }

    /* Строка дерева — ссылка на vibe-страницу своей сущности: о переходе
       говорит курсор, подчёркивание имени было лишним */
    .gantt-row.tr-row:hover .tr-name { cursor: pointer; }

    /* ── Дерево работ ───────────────────────────────────────────────────────
       Потоки — папки, задачи — файлы: одна строка на любой уровень, вложенность
       рисуется отступом и направляющей линией. Три варианта итема отличаются
       только тем, какие колонки показаны, — разметка строки общая */
    /* Ширина колонки имени — как у диаграммы, её тянет тот же резайзер */
    /* «Все работы» — та же панель, что «Выполнение», только список плоский:
       все задачи разом, без захода в папки. Поэтому оформление у них общее */
    /* Ширина колонки имени — в абсолютных единицах, а не в процентах: её же
       значение служит липким отступом колонки итогов, а проценты там считаются
       от ширины скроллера, тогда как ширина колонки — от ширины строки. Строка
       шире скроллера, и колонки разъезжались при горизонтальной прокрутке */
    /* Колонка названий — треть ширины таблицы, тянется ручкой до двух третей */
    :is(#wt-tree, #wt-all) { --gantt-label-w: 33.333%; }
    :is(#wt-tree, #wt-all) .gantt-label { max-width: 66.666%; }

    /* ── Колонка итогов — вторая, сразу за именем ──
       План и факт читают вместе с названием, диаграмма уезжает правее.
       Липнет она теперь к левому краю, за колонкой имени, а не к правому */
    :is(#wt-tree, #wt-all) .gantt-meta {
      right: auto; left: var(--gantt-label-w);
      border-radius: 0;
      /* Ширина — по самому широкому содержимому: её считает fitMetaWidth() и
         кладёт в переменную на панели. Одна на все строки и шапку, иначе
         колонки разъехались бы между собой */
      width: var(--gantt-meta-w, 280px); min-width: var(--gantt-meta-w, 280px);
    }
    /* Черта справа — такой же разделитель, как слева от колонки: диаграмма за
       ней начинается с чистого края и не липнет к цифрам */
    /* Цвет задаём обеим сторонам: в строках левая черта осталась без своего
       цвета и бралась от currentColor — тёмной линией вместо тонкой серой */
    :is(#wt-tree, #wt-all) :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-meta {
      border-left: 1px solid var(--border);
      border-right: 1px solid var(--border);
    }
    /* Правый край строки держит теперь трек: на нём скругление и рамка,
       которые раньше были на колонке итогов */
    :is(#wt-tree, #wt-all) .tr-row > .gantt-meta { border-radius: 0; }
    :is(#wt-tree, #wt-all) .tr-row > .gantt-track {
      border-right: 1px solid transparent; border-radius: 0 var(--r) var(--r) 0;
    }
    :is(#wt-tree, #wt-all) .tr-row:hover > .gantt-track { border-right-color: var(--border-mid); }
    :is(#wt-tree, #wt-all) .tr-node.folder > .tr-row > .gantt-track { border-right-color: var(--border); }
    :is(#wt-tree, #wt-all) .tr-node.folder > .tr-row:hover > .gantt-track { border-right-color: var(--border-mid); }
    .tr-list { padding: 0 0 8px; }
    /* Рамка собрана из сторон самих колонок, а не строки: строка шире экрана,
       и при горизонтальном скролле её левый и правый края уезжали за кадр.
       Колонки имени и итогов прилипшие — их вертикальные стороны видны всегда,
       верх и низ продолжает трек. Промежутка между колонками нет, иначе рамка
       рвалась бы в этих зазорах (отступы живут внутри самих колонок) */
    :is(#wt-tree, #wt-all) .gantt-head, #trList .gantt-row { gap: 0; }
    /* Высота строки фиксированная — списки папок и задач стоят одной сеткой */
    .tr-row { border: 0; height: 48px; padding: 0; margin-bottom: 4px; }
    .tr-row > .gantt-label,
    .tr-row > .gantt-track,
    .tr-row > .gantt-meta { border-top: 1px solid transparent; border-bottom: 1px solid transparent; transition: border-color .12s; }
    .tr-row > .gantt-label { border-left: 1px solid transparent; border-radius: var(--r) 0 0 var(--r); }
    .tr-row > .gantt-meta { border-right: 1px solid transparent; border-radius: 0 var(--r) var(--r) 0; }
    /* Подсветку наведения даём рамкой — заливка тут спорила бы с выделением */
    .tr-row:hover { background: var(--area-bg); }
    .tr-row:hover > * { border-top-color: var(--border-mid); border-bottom-color: var(--border-mid); }
    .tr-row:hover > .gantt-label { border-left-color: var(--border-mid); }
    .tr-row:hover > .gantt-meta { border-right-color: var(--border-mid); }
    /* В папку (направление, поток) можно войти — она карточкой с рамкой,
       задачи-файлы остаются простыми строками */
    .tr-node.folder > .tr-row { background: var(--card); }
    .tr-node.folder > .tr-row > * { border-top-color: var(--border); border-bottom-color: var(--border); }
    .tr-node.folder > .tr-row > .gantt-label { border-left-color: var(--border); }
    .tr-node.folder > .tr-row > .gantt-meta { border-right-color: var(--border); }
    .tr-node.folder > .tr-row:hover > * { border-top-color: var(--border-mid); border-bottom-color: var(--border-mid); }
    .tr-node.folder > .tr-row:hover > .gantt-label { border-left-color: var(--border-mid); }
    .tr-node.folder > .tr-row:hover > .gantt-meta { border-right-color: var(--border-mid); }
    .tr-node.sel > .tr-row { background: #eaf1fb; }
    /* Отложенная строка — имя серым: работа по ней сейчас не идёт, и тёмный
       заголовок тянул на себя внимание наравне с активными */
    #trList .tr-main:has(.st-deferred) > .tr-name { color: var(--text-secondary); }
    /* Имя и подпись — в колонке имени, итоги и статус — в колонке сумм */
    #trList .gantt-label { padding-left: 12px; }
    /* Строка фильтров ближе к шапке страницы: 30px пустоты между вкладками и
       фильтрами разрывали таблицу с её заголовком */
    /* Строка фильтров начинается сразу под вкладками — своего верхнего
       отступа ей не нужно */
    :is(#wt-tree, #wt-all) .plan-filter-bar { margin-top: 0; }
    /* Колонка итогов спрятана. Столбик под кнопку возврата тут больше не нужен —
       кнопка живёт в тулбаре, — поэтому ужимаем его в ноль. Сам столбик остаётся
       в разметке: он прилипший, и его правая граница держит край рамки строки
       у края экрана. Без него рамка обрывалась бы где-то в конце шкалы */
    :is(#wt-tree, #wt-all).meta-hidden .gantt-meta {
      width: 0; min-width: 0; padding-left: 0; padding-right: 0; border-left: none;
    }
    :is(#wt-tree, #wt-all).meta-hidden .gantt-meta > :not(.meta-toggle) { display: none; }
    /* Шеврон смотрит в сторону действия: колонка открыта — влево, «свернуть»;
       свёрнута — вправо, «развернуть». Поворачиваем поэтому развёрнутое
       состояние, а не свёрнутое */
    :is(#wt-tree, #wt-all):not(.meta-hidden) .meta-toggle svg { transform: rotate(180deg); }
    /* Шапка дерева без нижней линии (строки-карточки и так отделены рамками)
       и прижата к списку: снизу ровно 4px, как между самими строками */
    /* align-items не трогаем: колонки должны растягиваться на всю высоту шапки,
       иначе прилипшая колонка названий не перекрывает уезжающую под неё шкалу */
    /* Панель — флекс-колонка, и список отъедал у шапки высоту: её 32px
       схлопывались до 20px, месяцы обрезались снизу, а строки начинались
       вплотную к шкале. Шапке запрещаем сжиматься */
    :is(#wt-tree, #wt-all) > .gantt-headwrap { flex-shrink: 0; }
    /* Скроллбар списка съедал ширину строк, и вертикальные линии шкалы в шапке
       расходились с линиями строк. Жёлоб резервируем всегда и у списка, и у
       шапки — ширина колонок совпадает со скроллбаром и без него */
    :is(#wt-tree, #wt-all) > .gantt-headwrap { overflow-y: auto; scrollbar-gutter: stable; }
    :is(#wt-tree, #wt-all) > .gantt.tr-list { scrollbar-gutter: stable; }
    :is(#wt-tree, #wt-all) .gantt-head {
      /* 10px до первого ряда — заметно больше 4px между самими рядами,
         поэтому шкала читается как заголовок таблицы, а не как ещё одна строка */
      box-shadow: none; height: 32px; padding-top: 0; padding-bottom: 0; margin-bottom: 10px;
    }
    /* Групповая задача раскрывается на месте, как на «Задачах»: задания идут
       теми же строками с отступом, шеврон поворачивается вниз */
    .tr-kids { display: none; }
    .tr-node.group.open > .tr-kids { display: block; padding: 0 0 6px; }
    .tr-node.group.open > .tr-row .tr-into svg { transform: rotate(90deg); }
    /* Ширина группы — со строку, а не с видимую область: иначе при горизонтальном
       скролле её содержимое уезжало из-под шкалы месяцев */
    .tr-node.group, .tr-kids { min-width: 1006px; }
    /* Общей подложки у раскрытой группы нет: задания и так видно по отступу,
       а лишнее пятно спорило с рамками самих строк. Отмечаем только заголовок —
       той же заливкой, что и выбранная кликом строка (.tr-node.sel) */
    .tr-node.group.open > .tr-row { background: #eaf1fb; }
    .tr-kids .tr-row { background: var(--card); }
    /* Задания идут во всю ширину строки: боковые полоски-вставки читались как мусор,
       а сдвиг колонок ломал вертикальные линии сетки. Вложенность — отступом имени */
    /* Никаких боковых вставок: любая полоска между краем группы и белой строкой
       читается как результат работы. Вложенность передаём только отступом содержимого
       (id-правило выше перебивало класс, поэтому селектор с #trList) */
    /* 12px отступа строки + 22px вложенности — та же ступень, что у вложенных
       строк диаграммы. Прежние 18px давали всего 6px разницы, и задания внутри
       составной задачи не читались как вложенные */
    #trList .tr-kids .gantt-label { padding-left: 34px; }
    .tr-kids .tr-name { font-weight: 400; }
    /* Шеврон «войти» — только у папок и только заметный при наведении */
    .tr-into { display: inline-flex; align-items: center; justify-content: center; width: 12px; flex-shrink: 0; color: #c2cedd; }
    .tr-row:hover .tr-into { color: #7f8ea3; }
    /* Возврат на уровень выше — в шапке таблицы, в колонке названий */
    .tr-up {
      display: flex; align-items: center; gap: 6px; min-width: 0;
      padding: 3px 6px; margin-left: -6px;
      font-size: 11.5px; font-weight: 500; color: var(--text-secondary); cursor: pointer;
      border-radius: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      text-transform: none; letter-spacing: 0;
    }
    .tr-up:hover { background: rgba(15,30,60,.06); color: var(--text-primary); }
    .tr-up svg { color: #8b95a5; flex-shrink: 0; }
    .tr-empty { padding: 18px 10px; font-size: 12.5px; color: var(--text-muted); }
    /* Процент выполнения — сразу за плановой полосой */
    .tr-pct {
      position: absolute; top: 50%; transform: translateY(-50%);
      font-size: 10.5px; color: var(--text-secondary); white-space: nowrap; pointer-events: none;
    }
    /* Крошка-ссылка на уровень пути. Ширину ограничиваем: длинное имя папки
       раздувало шапку, и «В работу» переносилась на вторую строку */
    .breadcrumb .bc-link, .breadcrumb .bc-cur { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
    .bc-link { color: #7f93ab; font-weight: 500; cursor: pointer; border-radius: 5px; padding: 2px 3px; }
    .bc-link:hover { background: rgba(15,30,60,.06); color: var(--purple); }
    /* Вторая строка под названием: у потока — сколько исполнителей внутри,
       у задачи — имя исполнителя; статус стоит тут же */
    .tr-main { flex: 1; min-width: 0; }
    .tr-name { display: block; font-size: 13px; font-weight: 500; color: var(--text-primary);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .tr-node[data-kind="dir"] > .tr-row .tr-name { font-weight: 600; }
    .tr-node[data-kind="asg"] > .tr-row .tr-name { color: var(--text-secondary); }
    .tr-sub { display: flex; align-items: center; gap: 10px; min-width: 0; margin-top: 3px; }
    .tr-who { font-size: 11.5px; color: var(--text-muted);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Обёртка чипов в списке задач шириной 118px и с центрированием (правило по id
       выше) — в дереве она должна облегать статус, иначе слева зияет пустота */
    #viewWorkTasks .tr-list .item-chips {
      flex-shrink: 0; display: inline-flex; width: auto; min-width: 0; margin: 0; padding: 0;
      justify-content: flex-start;
    }
    /* Месяцы в шапке — по центру её высоты */
    :is(#wt-tree, #wt-all) .gantt-head .gantt-track { align-items: center; }
    /* Высота чипа одна для всех состояний, текст по центру: при inline-раскладке
       и line-height: 1 надпись садилась выше середины, а высота гуляла от статуса.
       Обводки и жирного нет — рядом с именем они читались как вторая рамка */
    :is(.tr-sub, #vibeChatExec) .ichip-status {
      display: inline-flex; align-items: center; height: 18px;
      /* Верхний отступ сдвигает надпись вниз: у прописных нет нижних выносных,
         и при точном центрировании текст читается прижатым кверху */
      padding: 2px 8px 0; box-shadow: none; font-weight: 400;
    }
    /* Белая заливка на карточке потока пропадала — берём фон страницы,
       а в строках задач и в сводке чата (там белая плашка) — на тон темнее,
       иначе чип сольётся */
    .tr-sub .ichip-status:is(.st-done, .st-aborted, .st-rejected) { background: var(--bg); }
    :is(.tr-node:not(.folder) .tr-sub, #vibeChatExec) .ichip-status:is(.st-done, .st-aborted, .st-rejected) { background: #e9ecf3; }

    .tr-variants { margin-left: auto; }

    /* «Все работы» — список без карточки: рамка, заливка и тень панели тут
       только дробили страницу, содержимое и так на светлом фоне */

    /* Кнопка «спрятать колонку» стоит в шапке таблицы, у правого края первой
       колонки: прямо над границей с колонкой итогов, которой она и управляет.
       z-index — поверх ручки изменения ширины: та лежит на том же краю */
    .gantt-head .gantt-label > .tr-meta-toggle {
      margin-left: auto; margin-right: 2px;
      position: relative; z-index: 7; flex-shrink: 0;
    }
    /* Лента активности: вместо аватаров — иконка сущности события */
    .notif-ico {
      display: inline-flex; align-items: center; justify-content: center;
      width: 32px; height: 32px; flex-shrink: 0;
      border-radius: 9px; background: #eef1f7; color: #6b7a8f;
    }

    /* Колонка итогов в шапке: кнопка прижата к левому краю, заголовок по центру */
    .gantt-head .gantt-meta:has(> .tr-meta-toggle) { justify-content: center; }
    .gantt-head .gantt-meta > .tr-meta-toggle { position: absolute; left: 8px; margin: 0; }
    /* Кнопка закрытия страницы — возвращает в корень раздела «Работы» */
    .page-close {
      margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
      width: 28px; height: 28px; flex-shrink: 0;
      border: none; border-radius: 7px; background: transparent;
      color: #7f8ea3; cursor: pointer; transition: background .12s, color .12s;
    }
    .page-close:hover { background: #eceff4; color: var(--text-primary); }

    /* Чип «···» — кнопка меню сущности: пока не наведён, его нет в потоке
       вовсе (display: none), иначе он держал место и при появлении сдвигал
       текст. Показывается после названия — порядком во флексе */
    .eid-chip { order: 5; display: none; }
    /* Когда строка не помещается, на вторую строку уходят чипы, а не кнопка
       «···»: она стоит в порядке раньше и остаётся в первой строке */
    .item-row > .item-chips { order: 6; }
    /* Место под «···» — у правого края строки, за чипами: там же, где у
       раскрывающихся строк стоит шеврон. Пока курсора нет, в этой клетке
       нарисован шеврон «открыть», под курсором на его месте — само «···».
       Клетка одна на оба состояния, поэтому строка не дёргается */
    .item-row > .item-id.eid-chip {
      display: inline-flex; visibility: visible; position: relative;
      order: 7; margin-left: 8px;
      /* Пока в клетке шеврон, подложки нет: она читалась бы кнопкой,
         хотя нажимать там нечего. Возвращаем её вместе с «···» */
      background: transparent;
    }
    .item-row:hover > .item-id.eid-chip { background: rgba(15, 30, 60, .05); }
    .item-row > .item-id.eid-chip::after {
      content: ''; position: absolute; inset: 0; transition: opacity .12s;
      background: center / 14px 14px no-repeat url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%238a97a8%27 stroke-width=%272.2%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpolyline points=%279 18 15 12 9 6%27/%3E%3C/svg%3E");
    }
    .item-row:hover > .item-id.eid-chip::after { opacity: 0; }
    /* Строки без чипа сущности (кода у них нет) — тот же шеврон в той же
       клетке: иначе в списке часть строк со стрелкой, часть без */
    .items-list > .item-row[onclick]:not(:has(> .item-id.eid-chip)):not(:has(> .item-chevron))::after {
      content: ''; width: 22px; height: 22px; margin-left: 8px; order: 7; flex-shrink: 0;
      background: center / 14px 14px no-repeat url("data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%238a97a8%27 stroke-width=%272.2%27 stroke-linecap=%27round%27 stroke-linejoin=%27round%27%3E%3Cpolyline points=%279 18 15 12 9 6%27/%3E%3C/svg%3E");
    }
    .item-row:not(:hover) > .item-id.eid-chip > .eid-ico { opacity: 0; }
    /* Крестик — последним в строке, за чипами и меню «···»: без порядка он
       вставал сразу после названия, перед правами ключа */
    .item-row > .proj-data-del { order: 8; }
    /* В строках работ меню сущности не нужно — и место под него тоже */
    .item-row.work-row > .item-id.eid-chip { display: none; }
    /* В подключениях — тоже: меню сущности у внешнего ресурса нечем наполнить */
    .item-row > .item-id.eid-chip[data-eid-key="РС"] { display: none; }
    .gantt-label .tr-into { order: 6; }

    /* Результаты работы потока: у самих карточек есть рамки, внешняя обводка области
       была третьей вложенной рамкой подряд — убираем */
    #flow-artifacts > .proj-data-section { border: none; border-radius: 0; }

    /* Ручка на границе чата — левый край правой панели: после перетаскивания
       фиксируется ширина панели, а колонка чата занимает всё остальное */
    body.chat-col-open.main-col-sized:has(> #mainTopbar) {
      grid-template-columns: auto minmax(320px, 1fr) var(--main-col-w, 720px);
    }
    body.sb-hidden.chat-col-open.main-col-sized:has(> #mainTopbar) {
      grid-template-columns: 0 minmax(320px, 1fr) var(--main-col-w, 720px);
    }
    body.chat-col-open.main-col-sized > #chat-panel.task-panel,
    body.chat-col-open.main-col-sized > #chat-panel.proj-panel { width: auto; }

    /* ── Колонка чата справа от контента (chat-col-right) ──
       Прежняя механика сажала чат слева; теперь он занимает свою колонку
       после контента, ширину держит --chat-col-w (ручка на левом краю) */
    body.chat-col-right.chat-col-open:has(> #mainTopbar) {
      grid-template-columns: auto minmax(0, 1fr) var(--chat-col-w, var(--left-col-def, 460px));
    }
    body.chat-col-right.chat-col-open:has(> #mainTopbar) > .content-col { grid-column: 2; }
    body.chat-col-right.chat-col-open:has(> #mainTopbar) > #chat-panel { grid-column: 3; grid-row: 2; margin-right: 8px; }
    /* Ручка ширины — на левом краю правой колонки */
    body.chat-col-right > #chat-panel > .chat-col-resizer { right: auto; left: 0; }
    body.chat-col-right > #chat-panel > .chat-col-resizer::before { right: auto; left: 3px; }

    /* «Активность» — последним пунктом раздела: порядок в списке задаёт order,
       а не разметка (у .dash-list display: contents и свои порядки внутри) */
    .exec-section > .nav-item[data-page="activity"] { order: 8; }
    /* «Страницы» — сразу за «Активностью»: тот же order, дальше решает разметка */
    .exec-section > .tree-node:has(> .nav-item[data-page="pages"]) { order: 8; }

    /* Значок типа и чекбокс — одно место в строке: по умолчанию виден значок,
       при наведении на строку (и когда строка отмечена) — чекбокс */
    .row-mark {
      position: relative; width: 18px; height: 18px; flex-shrink: 0;
      display: inline-flex; align-items: center; justify-content: center;
    }
    .row-mark > * { position: absolute; transition: opacity .12s; }
    .row-mark > .item-check { opacity: 0; }
    .tr-row:hover .row-mark > .item-check,
    .item-row:hover .row-mark > .item-check,
    .gantt-row:hover .row-mark > .item-check,
    .row-mark:hover > .item-check,
    .row-mark > .item-check.checked { opacity: 1; }
    .tr-row:hover .row-mark > .eid-name-ico,
    .item-row:hover .row-mark > .eid-name-ico,
    .gantt-row:hover .row-mark > .eid-name-ico,
    .row-mark:hover > .eid-name-ico,
    .row-mark:has(> .item-check.checked) > .eid-name-ico { opacity: 0; }
    /* В строке исполнителя место значка занимает аватар — клетка под него шире */
    .row-mark:has(> .mini-ava) { width: 22px; height: 22px; }
    .gantt-row:hover .row-mark > .mini-ava,
    .row-mark:hover > .mini-ava,
    .row-mark:has(> .item-check.checked) > .mini-ava { opacity: 0; }

    /* «Список дел»: слева значок типа строки — пункт работы или замечание.
       Чекбокс проявляется только под курсором на самом значке: наведение на
       строку его не трогает, иначе он мигал бы при проводке вдоль списка */
    .todo-ico { color: #8b95a5; display: inline-flex; align-items: center; justify-content: center; }
    .todo-ico.ico-bug { color: #c98a2e; }
    /* Нарушение и ожидающее решения — в одном списке «Проблемы»: цвет значка
       разводит их между собой (правило .problem-ico выше по файлу, поэтому
       цвет задаём здесь ещё раз) */
    .todo-ico.problem-ico { color: #c23a35; }
    /* Сигнал исполнителя менеджерам — поднятый флаг, серый: сам по себе он
       ничего не нарушает, цветом выделены только его особые признаки —
       перечёркнутый круг (отказ) и пауза (просьба прервать работу) */
    .todo-ico.ico-signal { color: #8b95a5; }
    .todo-ico.ico-reject { color: #b4275a; }
    .todo-ico.ico-stop   { color: #d9822b; }
    /* Вторая строка сигнала: кому направлен и когда. Встаёт под именем
       (flex-basis: 100% переносит её на свою строку) с отступом под значок.
       У решённого сигнала не показываем — вопрос закрыт, адресат не важен */
    .sig-meta {
      flex: 0 0 100%; margin: 2px 0 0 28px;
      display: flex; align-items: center; gap: 6px;
      font-size: 11.5px; color: var(--text-muted);
    }
    .sig-to { color: var(--text-secondary); }
    .sig-date::before { content: '·'; margin-right: 6px; color: #b9c2d0; }
    .item-row.done .sig-meta { display: none; }
    /* Имя занимает первую строку целиком (28px — место значка с зазором),
       подпись и «Решено» делят вторую: подпись слева, кнопка у правого края */
    .item-row:has(> .sig-meta) > .item-name { flex: 1 1 calc(100% - 28px); }
    /* Высота второй строки — под кнопку «Решено» (20px): без запаса строка
       подрастала в момент наведения */
    .item-row:has(> .sig-meta) > .sig-meta { flex: 0 1 auto; order: 2; min-height: 20px; }
    .item-row:has(> .sig-meta) > :is(.row-resolve, .row-done-chip) {
      order: 3; margin-left: auto;
    }
    /* У решённого сигнала второй строки нет (подпись скрыта) — имя перестаёт
       занимать её целиком, и чип «Решено» встаёт справа в первой строке */
    .item-row.done:has(> .sig-meta) > .item-name { flex: 1 1 auto; }
    /* Имя нарушения красное: это не пункт работы, а сорванное условие */
    .item-row:has(.problem-ico) > .item-name { color: #c23a35; }
    /* :not(:hover) на самом значке обязателен: под курсором на значке строка
       тоже считается наведённой, и правило строки (оно специфичнее) гасило бы
       чекбокс обратно */
    .todo-list .item-row:hover .row-mark:not(:hover) > .item-check:not(.checked) { opacity: 0; }
    .todo-list .row-mark:hover > .item-check { opacity: 1; }
    .todo-list .row-mark:hover > .todo-ico,
    .todo-list .row-mark:has(> .item-check.checked) > .todo-ico { opacity: 0; }

    /* Отмеченная строка дерева — циановая рамка по всему итему, тем же цветом,
       что и сам чекбокс. Рамка собрана из сторон колонок, поэтому красим их */
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-label,
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-track,
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-meta { border-top-color: #0098a6; border-bottom-color: #0098a6; }
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-label { border-left-color: #0098a6; }
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-track { border-right-color: #0098a6; }
    :is(#wt-tree, #wt-all) .tr-node > .tr-row.selected > .gantt-meta { border-right-color: #0098a6; }

    /* В шапке страницы «···» стоит сразу за названием, а не в конце строки:
       порядок задаём всем соседям, иначе order чипа уводит его за кнопки */
    .proj-header > .proj-title { order: 1; }
    .proj-header > .proj-id.eid-chip { order: 2; }
    /* Шапка: значок типа и чип-меню «···» делят одно место перед именем —
       обычно виден значок, при наведении на шапку его сменяет кнопка команд */
    /* Значок и подпись типа — единый блок-кнопка: подсветка по наведению,
       клик в любом месте открывает меню сущности */
    .head-mark {
      position: relative; display: inline-flex; align-items: center;
      gap: 4px; min-width: 22px; height: 24px; flex-shrink: 0;
      padding: 0 8px 0 3px; border-radius: 7px; cursor: pointer;
      /* Центр значка стоял на 1px выше центра заголовка */
      transform: translateY(1px);
    }
    .head-mark:hover { background: #eef1f6; }
    .head-mark > .eid-name-ico { margin-right: 0; width: 22px; justify-content: center; }
    /* Чип-меню растянут на весь блок — клик везде; многоточие в слоте значка */
    .head-mark > .proj-id.eid-chip {
      position: absolute; inset: 0; width: auto; margin: 0;
      justify-content: flex-start; padding: 0 0 0 3px;
    }
    .head-mark > .proj-id.eid-chip .eid-ico { width: 22px; justify-content: center; }
    .head-mark:hover > .eid-name-ico { opacity: 0; }
    /* Пока имя правят, значок остаётся значком — чип скрыт правилом ниже */
    .proj-header.editing .head-mark:hover > .eid-name-ico { opacity: 1; }
    .proj-header > .tab-bar { order: 3; }
    .proj-header > .title-edit { order: 4; }
    /* Правая группа шапки: тумблер выполнения (внутри .proj-header-right)
       встаёт вплотную слева от крестика — распорку несёт сама группа */
    .proj-header > .proj-header-right { order: 5; margin-left: auto; }
    .proj-header:has(> .proj-header-right) > .page-close { margin-left: 2px; }
    /* Название типа сущности — тихой подписью внутри блока значка, сразу
       за иконкой. Блок из-за подписи не фиксирован по ширине */
    .head-mark > .head-type {
      font-size: 12px; font-weight: 500; color: #8a97a8; white-space: nowrap;
    }
    /* Правая группа шапки: кнопка панели (page-max) и крестик. Распорку
       несёт первый из них — на страницах без page-max это сам крестик */
    .proj-header > .page-max { order: 6; margin-left: auto; }
    .proj-header > .page-close { order: 7; margin-left: auto; }
    .proj-header > .page-max + .page-close { margin-left: 2px; }

    /* «Наверх» — слева в первой ячейке, кнопка колонки итогов — у её правого края */
    .gantt-head .gantt-label > .tr-meta-toggle { margin-left: auto; }
    /* Масштаб шкалы — в первой ячейке шапки таблицы, над именами строк:
       переключатель стоит рядом с самой шкалой, а не в строке фильтров */
    .gantt-head .gantt-label > .seg-pills { margin: 0; flex-shrink: 0; }

    /* Стык колонок — одна линия: разделитель рисует колонка названий, у колонки
       итогов левую границу снимаем, а в свёрнутом виде и правую (её 1px стоял
       вплотную к разделителю и читался как двойная линия) */
    :is(#wt-tree, #wt-all) :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-meta { border-left: 0; }
    :is(#wt-tree, #wt-all).meta-hidden :is(.gantt-head, .gantt-row, .gantt-group-head) > .gantt-meta { border-right: 0; }

    /* «···» проявляется, как только курсор вошёл в область строки (не только
       на само имя) — так до кнопки меню легче дотянуться. В шапке — наоборот:
       чип отвечает только на наведение на сам значок, а не на имя рядом */
    .gantt-label:hover .eid-chip,
    .tr-row:hover .eid-chip,
    .item-row:hover .eid-chip,
    .head-mark:hover .eid-chip { display: inline-flex; }
    /* Пока имя правят, чип «···» не показываем: заголовок скрыт, и чип
       выскакивал бы слева от поля ввода при каждом движении мыши */
    .proj-header.editing .head-mark:hover .eid-chip { display: none; }
    /* В строках работ меню сущности не нужно — строка целиком открывает работу */
    .item-row.work-row:hover .eid-chip { display: none; }

    /* Кнопка колонки итогов ближе к разделителю: 12px поля первой ячейки
       отодвигали её от линии, к которой она относится */
    :is(#wt-tree, #wt-all) .gantt-head > .gantt-label { padding-right: 4px; }

    /* «···» встаёт на место шеврона «войти»: при наведении шеврон уходит,
       кнопка меню занимает его место у правого края колонки названий */
    .tr-row:hover .tr-into,
    .gantt-label:hover .tr-into { display: none; }

    /* В ряду служебных кнопок крестик той же высоты, что и соседи */
    .tab-bar-actions > .page-close { width: 26px; height: 26px; margin-left: 2px; }

    /* «?» — сразу за названием страницы, а не у правого края */
    /* Между названием и «?» ровно 5px: у шапки свой gap 10px, добираем полем */
    .proj-header > .hint-toggle { order: 2; margin-left: -5px; }
    /* «Мои работы»: подсказка скрыта, а её верхний отступ оставался пустой полосой */

    /* Кнопка «Добавить» в шапке — только плюс: подпись дублировала иконку,
       а название сущности всё равно выбирается в меню по шеврону */
    body .tab-bar-actions .new-btn-split .new-btn-main { font-size: 0; gap: 0; padding: 0 8px; }
    body .tab-bar-actions .new-btn-split .new-btn-ico { display: flex; }

    /* Кнопка «свернуть/развернуть» рядом с крестиком */
    .page-max {
      display: inline-flex; align-items: center; justify-content: center;
      width: 26px; height: 26px; flex-shrink: 0;
      border: none; border-radius: 7px; background: transparent;
      color: #7f8ea3; cursor: pointer; transition: background .12s, color .12s;
    }
    .page-max:hover { background: #eceff4; color: var(--text-primary); }
    /* Восстановленный размер: слева панель управления — колонкой, устроенной
       ровно как колонка чата в задаче (своя ширина, без карточки и тени,
       ручка ширины на правом краю) */
    body.page-split:has(> #mainTopbar) { grid-template-columns: auto auto minmax(0, 1fr); }
    body.sb-hidden.page-split:has(> #mainTopbar) { grid-template-columns: 0 auto minmax(0, 1fr); }
    body.page-split:has(> #mainTopbar) > #dashPane { grid-column: 2; grid-row: 2; }
    body.page-split:has(> #mainTopbar) > .content-col { grid-column: 3; grid-row: 2; }
    body.page-split > #dashPane {
      position: relative; display: flex; flex-direction: column; min-height: 0;
      width: var(--dash-col-w, var(--left-col-def, 460px)); padding: 0; overflow: hidden;
      background: transparent; box-shadow: none; border-radius: 0;
    }
    body.sb-hidden.page-split > #dashPane { margin-right: 8px; }
    #dashPane > .view { display: flex; flex-direction: column; min-height: 0; flex: 1; }
    /* В панели плитки действий прижаты к низу — посреди колонки они висели.
       Распорки-блоки (greet/tail растут на «Начале») здесь не растут: свободное
       место делят auto-поля — приветствие с композером остаются по центру */
    #dashPane .dash-greet { flex: 0 0 auto; margin-top: auto; margin-bottom: 16px; }
    /* В узкой панели знак и заголовок складываются в столбик — разносим их
       и подсказки с композером по вертикали, а не в слипшийся перенос */
    #dashPane .dash-greet .proj-header {
      flex-direction: column; align-items: center; text-align: center; gap: 12px;
    }
    #dashPane .dpx-sugs.dash-sugs { margin-bottom: 10px; }
    #dashPane .dash-tail { flex: 0 0 auto; }
    #dashPane .dash-actions { margin-top: auto; }
    body:not(.page-split) > #dashPane { display: none; }

    /* «Добавить» — та же кнопка, что «Сохранить базовый план»: 32×32, круглая
       циановая подложка при наведении, серый значок, без подписи и шеврона */
    body .tab-bar-actions .new-btn-split .nba-chev { display: none; }
    body .tab-bar-actions .new-btn-wrap .new-btn-split {
      background: transparent; box-shadow: none; border: none; padding: 0; height: 32px;
    }
    body .tab-bar-actions .new-btn-split .new-btn-main {
      width: 32px; height: 32px; padding: 0; border-radius: 50%; color: #8b95a5;
    }
    body .tab-bar-actions .new-btn-split .new-btn-main:hover { background: #d3ecef; color: #056470; }
    body .tab-bar-actions .new-btn-split .new-btn-ico { color: inherit; }
    #dashPane > .view { min-width: 0; overflow: auto; }

    /* Строка фильтров начинается от края области, как заголовок страницы */
    :is(#wt-tree, #wt-all) > .plan-filter-bar { padding-left: 0; }

    /* Панель управления стоит между сайдбаром и правым окном: её содержимое
       ужимается по ширине колонки, а не тянется макетом дашборда */
    #dashPane > .view,
    #dashPane .content,
    #dashPane .body-area,
    #dashPane .dash-groups { min-width: 0; width: 100%; box-sizing: border-box; }
    #dashPane .body-area { overflow-y: auto; }
    #dashPane .dash-greet .proj-header { flex-wrap: wrap; }
    /* Тянем левый край правого окна — фиксируется его ширина, панель берёт остаток */
    body.page-split.main-col-sized:has(> #mainTopbar) {
      grid-template-columns: auto minmax(320px, 1fr) var(--main-col-w, 720px);
    }
    body.sb-hidden.page-split.main-col-sized:has(> #mainTopbar) {
      grid-template-columns: 0 minmax(320px, 1fr) var(--main-col-w, 720px);
    }
    body.page-split.main-col-sized > #dashPane { width: auto; }

    /* В разделённом виде правое окно живёт строго в своей колонке: без min-width: 0
       содержимое (широкие строки диаграммы, ряд кнопок шапки) распирало колонку
       и уезжало за правый край экрана */
    body.page-split > .content-col { min-width: 0; }
    body.page-split > .content-col > .main { min-width: 0; }

    /* ── Панель управления справа (page-split-right) ──
       Открывается кнопкой чата в шапке: контент остаётся гибким слева,
       ширину панели держит --dash-col-w (ручка на её левом краю) */
    body.page-split-right.page-split:has(> #mainTopbar) { grid-template-columns: auto minmax(0, 1fr) var(--dash-col-w, 520px); }
    body.sb-hidden.page-split-right.page-split:has(> #mainTopbar) { grid-template-columns: 0 minmax(0, 1fr) var(--dash-col-w, 520px); }
    body.page-split-right.page-split:has(> #mainTopbar) > .content-col { grid-column: 2; }
    body.page-split-right.page-split:has(> #mainTopbar) > #dashPane { grid-column: 3; margin-right: 8px; }
    body.page-split-right > #dashPane > .chat-col-resizer { right: auto; left: 0; }
    body.page-split-right > #dashPane > .chat-col-resizer::before { right: auto; left: 3px; }

    /* Шкала месяцев в дереве и «Всех работах» не должна наезжать на первую строку:
       внутри своей прокрутки она стоит в потоке, а на странице липнет к её верху */
    :is(#wt-tree, #wt-all).scroll-host > .gantt-headwrap { position: static; flex-shrink: 0; }
    :is(#wt-tree, #wt-all):not(.scroll-host) > .gantt-headwrap { top: 0; }
    /* Справа от чекбокса столько же, сколько слева от него до края колонки */
    .gantt-label > .row-mark { margin-right: 4px; }

    /* Узкая область (меньше 560px): диаграмме места не остаётся — прячем
       полосы, её полосу прокрутки и переключатель масштаба. Дерево со
       статусами и исполнителями занимает всю ширину */
    @media (max-width: 559px) {
      .wt-panel .seg-pills.tr-variants,
      .wt-panel .gantt-track,
      .wt-panel .gantt-scrollbar { display: none; }
      /* Колонка названий занимает всю ширину области: ограничения ширины
         держали её на месте диаграммы, а той больше нет */
      .wt-panel .gantt-label { flex: 1 1 auto; width: auto; max-width: none; }
      :is(#wt-tree, #wt-all).wt-panel .gantt-label { max-width: none; }
      .wt-panel #trList .tr-node.wf2 > .tr-row > .gantt-label { flex-basis: auto; width: auto; }
      /* Ширину строкам задавала диаграмма — без неё горизонтальной
         прокрутке взяться неоткуда */
      .wt-panel :is(.gantt-head, .gantt-group, .gantt-group-head, .gantt-row, .gantt-weekgrid) { min-width: 0; }
      .wt-panel :is(.tr-node.group, .tr-kids) { min-width: 0; }
      .wt-panel :is(.gantt, .gantt-headwrap) { overflow-x: hidden; }
    }

    /* ══ Шеврон раскрытия: «вниз» — развернуть, «вверх» — свернуть ══════
       Раньше одни шевроны лежали боком (>), другие смотрели вниз в обоих
       состояниях, и по значку нельзя было понять, что сделает клик.
       Теперь правило одно на весь интерфейс */

    /* Секции списков: значок в разметке смотрит вниз, раскрытая секция его
       переворачивает. Свёрнутой считаем и ту, у которой тело скрыто стилем,
       — класс .expanded после collapseAroundRazdel() остаётся висеть */
    body .section.expanded > .section-head > .sec-chevron { transform: rotate(180deg); }
    body .section:has(> .section-body[style*="display: none"]) > .section-head > .sec-chevron { transform: none; }
    /* Карточные секции — тем же правилом */
    body .proj-data-section:not(.collapsed) > .proj-data-section-head > .sec-chevron { transform: rotate(180deg); }

    /* Группы на диаграмме */
    body .gantt-chevron { transform: rotate(180deg); }
    body .gantt-group.collapsed .gantt-chevron { transform: none; }

    /* Стрелки деревьев в сайдбаре: в разметке они смотрят вправо —
       доворачиваем вниз, а раскрытые вверх */
    body .tree-arrow { transform: rotate(90deg); }
    body .tree-node.open > .tree-item > .tree-arrow,
    body .tree-node.open > .nav-item > .tree-arrow,
    body .tree-node.open > .nav-head > .tree-arrow,
    body .ws-nav .tree-node.open > .nav-item > .tree-arrow { transform: rotate(-90deg); }

    /* Дерево работ на «Прогрессе выполнения». В обычном дереве .tr-into —
       значок «зайти внутрь», его не трогаем: там стрелка вправо по смыслу */
    body .tr-node.wf2 .tr-into.wf2-chev svg { transform: rotate(90deg); }
    body .tr-node.wf2.group.open > .tr-row .tr-into.wf2-chev svg { transform: rotate(-90deg); }

    /* Список работ потока: плотным набраны только вложенные сценарии и вызов
       сценария — у них внутри своя ветка, остальные строки простые задачи.
       Выполненные тише: работа сделана, глаз ведём по оставшимся */
    .scenario-list .items-list .item-row > .item-name { font-weight: 400; }
    .scenario-list .items-list .item-row.item-row-parent > .item-name { font-weight: 600; }
    .scenario-list .items-list .item-row:has(.ichip-status.st-done) > .item-name { color: var(--text-muted); }
    .scenario-list .items-list .item-row:has(.ichip-status.st-done) .item-chips .ichip { opacity: .65; }
