/*
 * Хром Ганта плана работ (GL-214, Ф2 — спайк GL-191 `docs/projects/TZ_work_plan_architecture.md`
 * §3 «весь хром на --gl-* (обе темы)»). СВОЙ ассет (public/css), НЕ theme.css. Каркас/раскладку даёт
 * DHTMLX-CSS (public/css/vendor/dhtmlxgantt.css); здесь — ТОЛЬКО визуал поверх наших ролей
 * (Brand::rootTokens) — тема свет/тёмная переключается САМА (проекция ролей), своих `.dark`-правил
 * здесь нет (анти-island GL-053/094).
 *
 * Классы DHTMLX (сверено с package/codebase/dhtmlxgantt.css вендоренной v10.0.0): `.gantt_grid*` —
 * левая панель (WBS-дерево), `.gantt_task_*`/`.gantt_row`/`.gantt_scale_*` — правая (timeline),
 * `.gantt_link_*` — связи (Ф4, но стили тут же, на будущее).
 */

[x-cloak] { display: none !important; }

.gl-wp-gantt-wrap {
    display: block;
    width: 100%;
}

/* ── Тулбар зума (мокап §3: "Зум: Неделя ▾") ─────────────────────────────── */
.gl-wp-gantt-toolbar {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.6rem;
}

.gl-wp-gantt-toolbar__label {
    font-size: 0.76rem;
    font-weight: 600;
    color: var(--gl-muted);
    margin-right: 0.15rem;
}

.gl-wp-gantt-zoom-btn {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--gl-hairline);
    background: var(--gl-surface-2);
    color: var(--gl-text);
    border-radius: 999px;
    padding: 0.3rem 0.75rem;
    font-size: 0.76rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}

.gl-wp-gantt-zoom-btn:hover { background: var(--gl-app-bg); }

.gl-wp-gantt-zoom-btn.is-active {
    background: var(--gl-chip);
    /* ⚠ ТЕКСТ — роль `--gl-link-strong` («зелёный НА ТИНТЕ», 4.69:1 на композите #d7ebe0), а НЕ
       `--gl-primary` и не `--gl-link`. История трёх замеров, чтобы никто не «упростил» обратно:
         · `--gl-primary` #009A44 (GL-214) — заливочная роль, взятая текстом: 3.68:1 на белом,
           а после появления тинта под текстом — 2.95:1;
         · `--gl-link` #007f36 (GL-224) — 5.14:1, но ЭТО НА БЕЛОМ; на подложке чипа лишь 4.12:1;
         · `--gl-link-strong` #007532 (GL-225) — 4.69:1 на реальном композите чип-над-app-bg.
       Порог 4.5 (мелкий текст: 0.76rem/600). КОНТУР остаётся на `--gl-primary` — к рамке порог
       текста не применяется (та же логика, что у `--gl-warn-border` в Brand). */
    color: var(--gl-link-strong);
    border-color: var(--gl-primary);
}

/* ── GL-269: группа зума + пружина тулбара ───────────────────────────────────
   Группа масштаба — ОДИН флекс-элемент тулбара (внутренний gap = тулбарный 0.4rem); x-show гасит
   её целиком в режиме «Таблица» (кнопки зума осмысленны лишь при видимой timeline-панели).
   Пружина (flex-grow) прижимает правый блок (+ Узел / фуллскрин) к краю тулбара в любом режиме
   вида — при её наличии `margin-left:auto` кнопки «+ Узел» (ниже) резолвится в 0 и не спорит. */
.gl-wp-gantt-zoom-group {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.gl-wp-gantt-spring {
    flex: 1 1 auto;
}

/* ── GL-262: добавление узлов (кнопка тулбара «+ Узел», «+» строки, меню типов) ──
   Все цвета — существующими ролями (обе темы проецируются в Brand::rootTokens); текст-акцент —
   `--gl-link-strong` (тот же контраст-проверенный зелёный, что у активной кнопки зума выше:
   4.69:1 на композите), НЕ `--gl-primary` (заливочная, 3.68:1 текстом — провалила бы порог). */
.gl-wp-gantt-add-btn {
    display: inline-flex;
    align-items: center;
    margin-left: auto; /* тулбар: прижать кнопку добавления к правому краю, отдельно от зума */
    border: 1px solid var(--gl-primary);
    background: var(--gl-chip);
    color: var(--gl-link-strong);
    border-radius: 999px;
    padding: 0.3rem 0.85rem;
    font-size: 0.76rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}

.gl-wp-gantt-add-btn:hover { background: var(--gl-app-bg); }

/* Кнопка «+» строки грида — компактная, проявляется на строке; глиф на акцентной роли. */
.gl-wp-add-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 1px solid var(--gl-hairline);
    background: var(--gl-surface-2);
    color: var(--gl-link-strong);
    border-radius: 6px;
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}

.gl-wp-add-btn:hover {
    background: var(--gl-chip);
    border-color: var(--gl-primary);
}

/* Плавающее меню выбора типа (position:fixed — координаты ставит фабрика по кнопке-триггеру). */
.gl-wp-add-menu {
    position: fixed;
    z-index: 50;
    display: flex;
    flex-direction: column;
    min-width: 140px;
    padding: 0.25rem;
    background: var(--gl-surface);
    border: 1px solid var(--gl-hairline);
    border-radius: var(--gl-radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}

.gl-wp-add-menu__item {
    text-align: left;
    padding: 0.4rem 0.6rem;
    background: transparent;
    color: var(--gl-text);
    border: none;
    border-radius: 6px;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
}

.gl-wp-add-menu__item:hover { background: var(--gl-chip); }

/* ── GL-316: колонка действий строки (+ добавить · ⇤ влево · ⇥ вправо · 🗑 удалить) ──
   Кластер компактных icon-кнопок в грид-ячейке. Все цвета — ролями (обе темы). «+» реюзит
   .gl-wp-add-btn выше; остальные — тот же компактный вид, удаление несёт негативную роль. */
.gl-wp-row-actions {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    justify-content: flex-end;
    width: 100%;
}

.gl-wp-act-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 1px solid var(--gl-hairline);
    background: var(--gl-surface-2);
    color: var(--gl-muted);
    border-radius: 6px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}

.gl-wp-act-btn svg { width: 14px; height: 14px; }

.gl-wp-act-btn:hover {
    background: var(--gl-chip);
    border-color: var(--gl-primary);
    color: var(--gl-link-strong);
}

/* Удаление — негативная роль на hover (тот же `--gl-tone-negative`, что критический путь). */
.gl-wp-act-btn.gl-wp-del-btn:hover {
    border-color: var(--gl-tone-negative);
    color: var(--gl-tone-negative);
    background: var(--gl-surface-2);
}

/* ── GL-316: редактируемые ячейки грида (дата начала/завершения, ответственный) ──
   Кликабельны, когда сервер разрешил правку (флаги date_editable/owner_editable) — курсор-указатель
   и лёгкая акцент-подложка на hover, чтобы «правка одним кликом» была видна. Нередактируемые ячейки
   класса не несут (обычный текст). */
.gl-wp-edit-cell {
    display: inline-flex;
    align-items: center;
    /* GL-368: колонка несёт align:'center' (DHTMLX ставит text-align инлайн-стилем на РОДИТЕЛЬСКУЮ
       .gantt_cell), но НАШ span шириной 100% сам не центрирует содержимое — без justify-content он
       безусловно flex-start (левый край), поэтому нередактируемые (текстовые, без обёртки) строки
       центрировались text-align'ом родителя, а редактируемые (в этом span'е) — нет. */
    justify-content: center;
    gap: 4px;
    width: 100%;
    height: 100%;
    padding: 0 2px;
    border-radius: 5px;
    cursor: pointer;
    color: var(--gl-text);
}

.gl-wp-edit-cell:hover {
    background: var(--gl-chip);
    color: var(--gl-link-strong);
}

.gl-wp-edit-cell.gl-wp-empty { color: var(--gl-muted); }

/* ── GL-316: плавающий редактор ответственного (пикер сотрудников, position:fixed) ──
   Свой DOM в масть Filament (обе темы, роли), position:fixed → не клипается overflow грида;
   координаты ставит фабрика по кликнутой ячейке. Зеркалит визуал .gl-wp-add-menu. */
.gl-wp-owner-picker {
    position: fixed;
    z-index: 50;
    display: flex;
    flex-direction: column;
    width: 240px;
    max-height: 320px;
    padding: 0.4rem;
    background: var(--gl-surface);
    border: 1px solid var(--gl-hairline);
    border-radius: var(--gl-radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
    /* GL-366: без overflow:hidden список сотрудников (flex-child без явной высоты) рос ЗА пределы
       max-height коробки — пункты списка выглядели обрезанными/наложенными на контент под флайаутом.
       overflow:hidden клипует коробку по границе; сам скролл списка несёт .gl-wp-owner-list ниже. */
    overflow: hidden;
}

.gl-wp-owner-search {
    width: 100%;
    /* GL-662: поле поиска — прямой flex-child column-коробки, то есть по умолчанию СЖИМАЕМО
       (flex-shrink:1) ровно так же, как были сжимаемы пункты списка ниже. Сегодня сжатие целиком
       забирает .gl-wp-owner-list (её flex-basis:auto по содержимому на порядок больше), но это
       зависимость от длины списка, а не инвариант. Фиксируем явно: сжимается ТОЛЬКО список. */
    flex: 0 0 auto;
    margin-bottom: 0.35rem;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--gl-hairline);
    border-radius: 6px;
    background: var(--gl-surface-2);
    color: var(--gl-text);
    font-size: 0.82rem;
}

.gl-wp-owner-search:focus {
    outline: none;
    border-color: var(--gl-primary);
}

.gl-wp-owner-list {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    /* GL-366: flex-child в column-контейнере по умолчанию min-height:auto — растёт ПО СОДЕРЖИМОМУ и
       игнорирует overflow-y родителя (классическая грабля flexbox); min-height:0 включает реальное
       сжатие/скролл списка внутри max-height родителя. */
    min-height: 0;
    flex: 1 1 auto;
}

.gl-wp-owner-item {
    /* ⚠⚠ GL-662 — РЕЦИДИВ дефекта GL-366, вылеченный с ДРУГОЙ стороны, и снимать это объявление
       нельзя. `.gl-wp-owner-list` — column-флекс, а `flex-shrink` у его детей по умолчанию 1:
       при десятках сотрудников браузер СЖИМАЛ пункты по высоте вместо того, чтобы включить
       скролл списка. Живой замер на 53 сотрудниках (1440×900, тёмная тема): высота пункта
       11.19 px при `line-height` 18.74 px и паддингах 5.6+5.6 px (естественные 29.94 px) —
       текст не помещался в собственный бокс, и `overflow:hidden` ниже, поставленный ради
       ГОРИЗОНТАЛЬНОГО ellipsis, резал имена уже по ВЕРТИКАЛИ: ровно «слипшиеся и обрезанные
       пункты» со скриншота заказчика (и дословно та же картина, что описана в комментарии
       GL-366 выше — та починка держала только габарит коробки, но не габарит пункта).
       `flex: 0 0 auto` возвращает сжатие туда, где ему место — в скролл `.gl-wp-owner-list`.
       Сторож инварианта — tests/Feature/WorkPlan/WorkPlanOwnerPickerLayoutGl662Test.php. */
    flex: 0 0 auto;
    text-align: left;
    padding: 0.35rem 0.5rem;
    background: transparent;
    color: var(--gl-text);
    border: none;
    border-radius: 6px;
    font-size: 0.82rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gl-wp-owner-item:hover,
.gl-wp-owner-item.is-active { background: var(--gl-chip); color: var(--gl-link-strong); }

.gl-wp-owner-item.gl-wp-owner-clear { color: var(--gl-muted); }

/* ── GL-316: плавающий редактор дат — обёртка ФИРМЕННОГО <x-gl-datepicker> (Тип-4, со временем) ──
   Тот же приём position:fixed по кликнутой ячейке. Внутри — центральный датапикер (буквально та
   же панель-календарь Filament-визуала, обе темы), фабрика читает выбранное значение и шлёт
   updateNodeDates. */
.gl-wp-date-editor {
    position: fixed;
    z-index: 50;
    padding: 0.4rem;
    background: var(--gl-surface);
    border: 1px solid var(--gl-hairline);
    border-radius: var(--gl-radius);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}

/* GL-662: редактор ДАТЫ выводит только панель-календарь центрального датапикера (режим
   `:triggerless`), поэтому обёртка перестаёт быть видимой поверхностью и остаётся ЧИСТЫМ якорем
   координат по кликнутой ячейке — иначе над панелью висел бы пустой второй слой (ровно дефект,
   на который указал заказчик). ⚠ Модификатор адресный: числовой редактор «Дни»/«%»
   (.gl-wp-metric-editor) наследует базовый .gl-wp-date-editor и своей поверхности НЕ теряет —
   у него внутри голый <input>, которому подпись и коробка по-прежнему нужны. */
.gl-wp-date-editor--bare {
    padding: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
}

/* Подпись флайаута. GL-662: у редактора ДАТ снята (дублировала имя колонки, была верхним из двух
   лишних слоёв) — правило продолжает обслуживать числовой редактор «Дни»/«%» (GL-374). */
.gl-wp-date-editor__label {
    display: block;
    margin-bottom: 0.3rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--gl-muted);
}

/* ── GL-371: инлайн-редактор имени (DHTMLX tree-column editor) — выровнять с ячейкой ──
   Вендор рисует placeholder БЕЗ фона (прозрачный) → исходный текст строки просвечивал сквозь инпут
   (наложение), и БЕЗ дерево-индента → текст ввода прилипал к левому краю ячейки (смещение). Даём
   placeholder'у НЕПРОЗРАЧНЫЙ фон в масть строке (исходный текст перекрыт), а инпуту — цвет/шрифт
   ячейки. ЛЕВЫЙ отступ под дерево-индент зависит от ГЛУБИНЫ узла (статикой не выразить) —
   проставляет JS по факту (alignTextEditor, public/js/work-plan-gantt.js); здесь fallback 4px до
   его срабатывания. */
.gl-wp-gantt .gantt_grid_editor_placeholder {
    background: var(--gl-surface);
}

.gl-wp-gantt .gantt_grid_editor_placeholder input {
    padding-left: 4px;
    padding-right: 4px;
    color: var(--gl-text);
    background: transparent;
    font-size: var(--dhx-gantt-font-size);
}

/* ── GL-374: числовой редактор «Дни»/«%» (реюзит контейнер .gl-wp-date-editor) ── */
.gl-wp-metric-editor__row {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.gl-wp-metric-input {
    width: 88px;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--gl-hairline);
    border-radius: 6px;
    background: var(--gl-surface-2);
    color: var(--gl-text);
    font-size: 0.82rem;
}

.gl-wp-metric-input:focus {
    outline: none;
    border-color: var(--gl-primary);
}

/* Кнопка подтверждения — вид компактной пилюли зума (акцент-контур), тот же контраст-проверенный
   зелёный `--gl-link-strong`, что у активной кнопки зума/«+ Узел». */
.gl-wp-metric-ok {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--gl-primary);
    background: var(--gl-chip);
    color: var(--gl-link-strong);
    border-radius: 999px;
    padding: 0.3rem 0.7rem;
    font-size: 0.76rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.12s;
}

.gl-wp-metric-ok:hover { background: var(--gl-app-bg); }

/* ── GL-316: подтверждение удаления (реюзит контейнер .gl-wp-owner-picker) ── */
.gl-wp-confirm {
    width: 260px;
    max-height: none;
    gap: 0.6rem;
}

.gl-wp-confirm__text {
    margin: 0;
    font-size: 0.82rem;
    line-height: 1.35;
    color: var(--gl-text);
}

.gl-wp-confirm__actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.4rem;
    margin-top: 0.5rem;
}

/* Кнопка удаления — негативная роль (тот же `--gl-tone-negative`, что критический путь/удаление). */
.gl-wp-confirm__delete {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--gl-tone-negative);
    background: transparent;
    color: var(--gl-tone-negative);
    border-radius: 999px;
    padding: 0.3rem 0.85rem;
    font-size: 0.76rem;
    font-weight: 700;
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}

.gl-wp-confirm__delete:hover {
    background: var(--gl-tone-negative);
    color: var(--gl-surface);
}

/* ── Контейнер Ганта ─────────────────────────────────────────────────────── */
.gl-wp-gantt {
    width: 100%;
    height: 520px;
    border: 1px solid var(--gl-hairline);
    /* GL-373: без скругления углов — блок грид+Гант занимает область карточки вплотную (в масть
       «Таблице Тип 1»: таблица заполняет карточку без собственного скруглённого бокса внутри). */
    border-radius: 0;
    overflow: hidden;
    background: var(--gl-surface);
}

/* ── GL-373: блок вплотную к нижней границе карточки ─────────────────────────
   Страница-карточка (`.fi-page-main`) несёт штатный нижний паддинг (~14px) — из-за него блок
   грид+Гант не доходил до нижней границы окна-карточки (зазор). Гасим ЭТОТ паддинг ТОЛЬКО на
   странице, где живёт план (`:has(.gl-wp-gantt-wrap)`), — прочие страницы панели не затронуты
   (магического числа нет: убираем сам паддинг, а не компенсируем его отрицательным margin). */
.fi-page-main:has(.gl-wp-gantt-wrap) {
    padding-bottom: 0;
}

/* ── GL-269: фуллскрин карточки (реюз центрального .gl-fullscreen из GL-268) ──
   Оверлей-роль `.gl-fullscreen` (position:fixed;inset:0;display:flex;flex-direction:column) приходит
   из <x-gl-fullscreen-assets />; здесь — потребитель-специфика: контейнер Ганта несёт ФИКС-высоту
   520px (выше), в оверлее она НЕ заполнит вьюпорт. Родитель `.gl-wp-gantt-wrap.gl-fullscreen` уже
   флекс-колонка (центр. роль) → flex:1 тянет контейнер на всю оставшуюся высоту, min-height:0
   включает сжатие/внутренний скролл DHTMLX. Селектор (0,3,0) уверенно бьёт базовый
   `.gl-wp-gantt{height:520px}` (0,1,0). Эталон — КП `.gl-cp-scroller-frame.gl-fullscreen` (GL-268).
   ⚠ DHTMLX не следит за CSS-ресайзом — JS зовёт setSizes()+render() на смене `fullscreen` (resizeGantt). */
.gl-wp-gantt-wrap.gl-fullscreen .gl-wp-gantt {
    height: auto;
    flex: 1 1 auto;
    min-height: 0;
    border-radius: 0;
}

/* ── GL-272: внешний контур в масть ──────────────────────────────────────────
   Наш `.gl-wp-gantt` несёт `border: var(--gl-hairline)`, НО вендор рисует поверх собственный
   бордер на `.gantt_container` (`border:1px solid var(--dhx-gantt-base-colors-border)`) —
   а `--dhx-gantt-base-colors-border` в public/css/vendor/dhtmlxgantt.css задан ЛИТЕРАЛЬНЫМ
   серым (#DFE0E1 свет / #cecece тёмная), не в масть. Перемапливаем вендор-переменные на нашу
   роль `--gl-hairline` (сама тема-зависимая) на КОНТЕЙНЕРЕ-обёртке — CSS-custom-props наследуются
   вниз к `.gantt_container` и всем внутренним бордерам. Vendor-файл не трогаем (только читаем);
   переопределение аддитивно в НАШЕМ ассете. `--dhx-gantt-default-border` = `1px solid
   var(--dhx-gantt-base-colors-border)` — перемапливается автоматически через базовую переменную,
   но задаём его явно, чтобы не зависеть от порядка объявления в вендоре. */
.gl-wp-gantt {
    --dhx-gantt-base-colors-border: var(--gl-hairline);
    --dhx-gantt-base-colors-border-light: var(--gl-hairline);
    --dhx-gantt-default-border: 1px solid var(--gl-hairline);
    /* ⚠ GL-272 (живой замер): hover строк ГРИДА (WBS) вендор красит своим правилом
       `.gantt_grid_data .gantt_row:hover` (0,3,0) через `--dhx-gantt-base-colors-hover-color`
       (литерал #e0e0e0) — оно БЬЁТ наш `.gantt_row:hover` (0,2,0), поэтому одной подмены имени
       роли в правиле НЕДОСТАТОЧНО (грид-строки остались бы на сером). Перемапливаем и эту
       вендор-переменную на `--gl-surface-hover` — тогда СОБСТВЕННОЕ правило вендора отдаёт наш
       hover, без гонки за специфичность. Строки таймлайна (`.gantt_task_row:hover`) вендор не
       перекрывает — там работает наше правило ниже. */
    --dhx-gantt-base-colors-hover-color: var(--gl-surface-hover);
    /* ⚠ GL-316 (живой замер, обе темы): выделенную строку вендор красит ОДНИМ правилом
       `.gantt_row.gantt_selected,.gantt_task_row.gantt_selected{background-color:
       var(--dhx-gantt-base-colors-select)}` (литерал #EFF3FF свет / серый тёмная) — в ТЁМНОЙ теме
       это давало почти-белый фон под светлым текстом (нечитаемо). Перемапливаем вендор-переменную
       на нашу роль `--gl-chip` (акцент-тинт, тема-зависимая, эталон подсветки списков) — СОБСТВЕННОЕ
       правило вендора отдаёт наш цвет, без гонки за специфичность (как hover/border выше). Текст
       ячейки остаётся `--gl-text` (`.gantt_cell` ниже) — контраст на `--gl-chip` проверен аудитом
       glContrastAudit() в обеих темах. */
    --dhx-gantt-base-colors-select: var(--gl-chip);
    /* GL-367: вендор-дефолт 14px — крупнее компактного стандарта «Таблица Тип 1» (эталон плотности —
       Инвентаризация), из-за чего дата/иконки действий не помещались в ширину колонок. Компактный
       размер выравнивает грид/Гант с остальными списками CRM (перемап той же вендор-переменной, что
       цвета/бордер выше — паттерн GL-272). */
    --dhx-gantt-font-size: 12px;
    /* GL-375: вендор-дефолт `--dhx-gantt-font-family: Inter, …` — им head-ячейки грида и метки шкалы
       Ганта рисовались НЕ фирменным шрифтом (грид-ячейки/бары уже наследовали Golos Text через
       `.gantt_container{font-family:inherit}`, но head/scale берут ИМЕННО эту вендор-переменную).
       Перемапливаем её на центральный токен бренда `--font-family` (Brand::rootTokens) — тот же
       приём перемапа вендор-переменных, что цвета/бордер/размер выше (GL-272). ⚠ НЕ `inherit`:
       у custom-property значение `inherit` НАСЛЕДУЕТ значение ЭТОЙ ЖЕ переменной от предка (:root),
       т.е. снова вернуло бы Inter — нужен именно конкретный токен. */
    --dhx-gantt-font-family: var(--font-family);
}

.gantt_container {
    background: var(--gl-surface);
    color: var(--gl-text);
    font-family: inherit;
}

/* ── Заголовки грида/шкалы ───────────────────────────────────────────────── */
.gantt_grid_scale,
.gantt_grid_head_cell,
.gantt_task_scale .gantt_scale_cell,
.gantt_scale_line {
    background: var(--gl-surface-2);
    color: var(--gl-muted);
    border-color: var(--gl-hairline);
    font-weight: 700;
    font-size: 0.72rem;
}

/* ── Строки/ячейки ───────────────────────────────────────────────────────────
   Фон строк — РОЛЬ `--gl-surface` (как ячейки «Таблицы Тип 1»: тот же нейтральный surface,
   разделение строк несёт хайрлайн-бордюр, без зебры). ⚠ GL-260: вендор DHTMLX задаёт
   `.gantt_task_row,.gantt_row{background:var(--dhx-gantt-task-row-background)}` = БЕЛЫЙ (#FFF),
   спецификпость (0,1,0). Наш прежний блок ставил строкам только `border-color`, фон не трогал —
   в СВЕТЛОЙ теме белый совпадал с surface и дефект был невидим, а в ТЁМНОЙ чётные строки
   (без `.odd`) светились белым (нечётные перекрывались нашим `.odd`-правилом). Задаём фон здесь
   тем же (0,1,0)-селектором, что и вендор: наш CSS грузится ПОСЛЕ → выигрывает; чётные и
   нечётные строки одинаково ложатся на `--gl-surface` в обеих темах (зебра снята — «Таблица
   Тип 1» по умолчанию не полосатая, полоса — opt-in `.gl-table-zebra`). */
.gantt_row,
.gantt_task_row {
    border-color: var(--gl-hairline);
    background: var(--gl-surface);
}

/* ⚠ Вендор красит нечётные строки ОТДЕЛЬНЫМ правилом `.gantt_task_row.odd` (0,2,0) — оно бьёт
   базовое (0,1,0) выше, поэтому без этого дубля нечётные строки светились бы вендорным белым
   (та же болезнь, зеркально). Кладём тот же surface тем же (0,2,0)-селектором: зебры нет,
   все строки в обеих темах на `--gl-surface`. */
.gantt_row.odd,
.gantt_task_row.odd {
    background: var(--gl-surface);
}

/* GL-272: hover строки — роль `--gl-surface-hover` (эталон «Таблицы Тип 1»), НЕ `--gl-chip`
   (акцент-тинт чипов/баров бил не в масть общесистемному hover списков).
   GL-370: подсветка красилась НА ВСЮ высоту строки (background без инсета). `box-shadow: inset`
   со СПРЕДОМ рисует рамку базового surface ВНУТРИ подсветки РАВНОМЕРНО со всех 4 сторон (0-смещение +
   спред) — подсветка «плавает» с одинаковым отступом сверху/снизу И слева/справа одним правилом,
   без раздельных пседоэлементов/паддингов. */
.gantt_row:hover,
.gantt_task_row:hover {
    background: var(--gl-surface-hover);
    box-shadow: inset 0 0 0 4px var(--gl-surface);
}

.gantt_cell,
.gantt_task_cell {
    border-color: var(--gl-hairline);
    color: var(--gl-text);
    /* GL-367: вендор-дефолт 6px/сторона — на узких колонках (действия/даты) съедал полезную ширину,
       из-за чего иконки-кнопки не помещались, а даты обрезались. Компактнее, в масть Тип-1. */
    padding-left: 4px;
    padding-right: 4px;
}

.gl-wp-wbs {
    color: var(--gl-muted);
    font-variant-numeric: tabular-nums;
    font-size: 0.76rem;
    margin-right: 0.2rem;
}

/* ── Незапланированные узлы (нет эффективных дат, §1.5) — приглушённая строка грида ── */
/* GL-316: курсив снят (заказчик) — узлы рисуются обычным начертанием; приглушение цветом остаётся. */
.gl-wp-row-unscheduled .gantt_cell {
    color: var(--gl-muted);
}

/* GL-316: узлы-этапы (summary — есть подчинённые) выделяются ПОЛУЖИРНЫМ начертанием (заголовки
   WBS-дерева читаются как разделы). Класс вешает g.templates.grid_row_class по task.$has_child
   (public/js/work-plan-gantt.js). Приоритет цвета/веса у ячейки — селектор (0,2,0) кроет базовый
   `.gantt_cell` (0,1,0). */
.gl-wp-row-summary .gantt_cell {
    font-weight: 700;
}

/* ── Бары timeline: задача / summary («project») / веха — роли, не литералы ─ */
.gantt_task_line.gl-wp-node-task {
    background: var(--gl-chip);
    border: 1px solid var(--gl-hairline-strong);
    border-radius: 6px;
}

/* ⚠ Заливка — роль `--gl-progress-bar-strong`, а НЕ `--gl-primary`: поверх полосы лежит подпись
   бара (`--gl-text`), и она МЕНЯЕТ цвет с темой, а `--gl-primary` — нет. Из-за этой асимметрии в
   тёмной теме светлый текст падал до 3.72:1 при пороге 4.5 (светлая при этом проходила — 4.74).
   Роль объявлена в Brand::rootTokens() с проекцией на `.dark`, значения подобраны ЗАМЕРОМ — там же
   числа и обоснование. `opacity` НЕ трогаем: она композитит зелень с подложкой бара и как раз
   вытягивает светлую тему; замер ведётся ПО КОМПОЗИТУ, а не по «чистому» цвету — именно этой
   разницей был занижен первый замер (3.99 вместо 4.74). */
.gantt_task_line.gl-wp-node-task .gantt_task_progress {
    background: var(--gl-progress-bar-strong);
    opacity: 0.85;
}

.gantt_task_line.gl-wp-node-task .gantt_task_content {
    color: var(--gl-text);
    font-weight: 600;
    font-size: 0.72rem;
}

.gantt_task_line.gantt_project,
.gantt_task_row.gantt_row_project .gantt_task_line {
    background: var(--gl-accent);
    border-radius: 3px;
}

.gantt_task_line.gantt_project .gantt_task_progress {
    background: var(--gl-accent);
    opacity: 0.7;
}

.gantt_task_line.gantt_milestone,
.gl-wp-node-milestone.gantt_task_line {
    background: var(--gl-accent);
}

/* ── GL-372: гант-бар «плавает» — симметричный ГОРИЗОНТАЛЬНЫЙ отступ ──────────
   Вертикальный отступ уже есть (высота бара < высоты строки, DHTMLX центрирует по вертикали), но по
   горизонтали бар примыкал ВПЛОТНУЮ к краям крайних ячеек периода. DHTMLX задаёт `left`/`width` бара
   ИНЛАЙН-стилем (позиция по датам) — CSS-шириной/маргином симметричный инсет не сделать. `clip-path:
   inset(...)` КЛИПует ВЕСЬ бар (контур + заливку + прогресс-полосу) на 3px слева/справа, `round 6px`
   сохраняет скругление — бар получает равный отступ со всех сторон, не меняя раскладку/позицию.
   ⚠ Селектор — по РЕНДЕР-классам DHTMLX (`gantt_bar_task`/`gantt_bar_project`), а НЕ по нашим
   `gl-wp-node-{type}` (те отражают ХРАНИМЫЙ node_type: лист с типом summary рисуется как бар-задача,
   но несёт класс `gl-wp-node-summary` — по нему бы не поймался). Веха-диамант (`gantt_bar_milestone`)
   в набор НЕ входит — её не клипуем. */
.gl-wp-gantt .gantt_task_line.gantt_bar_task,
.gl-wp-gantt .gantt_task_line.gantt_bar_project {
    clip-path: inset(0 3px round 6px);
}

/* ── Связи (зависимости) — GL-227, Ф4 ───────────────────────────────────── */
.gantt_link_line,
.gantt_link_arrow {
    border-color: var(--gl-muted);
}

/* ── GL-227 (Ф4): критический путь ───────────────────────────────────────────
   Цвет — существующая роль `--gl-tone-negative` (#b42318 / on-dark #ff8a80): она уже объявлена в
   ОБЕИХ темах и уже проверена по контрасту (см. Brand::rootTokens, тоновая тройка КП). Новой роли
   намеренно НЕ заводим: у неё был бы ровно один потребитель, а лишняя роль в палитре — это тот
   самый дрейф, который лечили GL-094/GL-224 (и её пришлось бы вручную проецировать на `.dark`).
   ⚠⚠ Красим ТОЛЬКО КОНТУР — ни заливку бара, ни полосу прогресса. Первая версия GL-227 красила
   ещё и `.gantt_task_progress`, и ЖИВОЙ ЗАМЕР это отклонил: подпись бара (`--gl-text` #1f2937) над
   красной полосой дала **2.23:1** при пороге 4.5 (замер 20.07.2026, обе критические работы
   демо-плана). К РАМКЕ порог контраста текста не применяется — та же логика, что у
   `--gl-warn-border` выше, — поэтому сигнал несёт она, а подпись остаётся на прежней подложке.
   Правило CLAUDE.md в действии: CSS «читался правильно», ошибку показал только замер.
   Смысл подсветки: «у работы нет резерва», не «работа провалена». */
.gantt_task_line.gl-wp-critical {
    border-color: var(--gl-tone-negative);
    border-width: 2px;
}

.gantt_link_line.gl-wp-link-critical,
.gl-wp-link-critical .gantt_link_line,
.gl-wp-link-critical .gantt_link_arrow {
    border-color: var(--gl-tone-negative);
}

/* ── Скроллбары/линии сетки таймлайна ────────────────────────────────────── */
.gantt_data_area,
.gantt_grid_data {
    background: var(--gl-surface);
}

/* ── GL-215 (Ф3): баннер отказа сервера (нет прав / цикл в дереве / даты вне границ) ──
   Показывается, когда бар откатился на место — «явный отказ с причиной», не тихий откат.
   Цвет — РОЛЯМИ `--gl-warn`/`--gl-warn-border` (определены централизованно в Brand::rootTokens()
   и спроецированы на `.dark`, GL-094), не литералами и не `var(--role, #fallback)`. Заливки нет
   сознательно: подложка баннера — поверхность секции, роли тинта под warn в палитре сейчас нет,
   а изобретать её ради одного потребителя — тот самый дрейф, который лечила GL-094. */
.gl-wp-gantt-error {
    margin: 0 0 0.5rem;
    padding: 0.4rem 0.65rem;
    border: 1px solid var(--gl-warn-border);
    border-radius: 6px;
    color: var(--gl-warn);
    font-size: 0.82rem;
    line-height: 1.35;
}
