/* styles/dashboard.css
 *
 * [2026-08-15] Персональный дашборд главной страницы — три зоны:
 * Задачник / Проекты / Инструменты-рабочий-стол. Отдельный файл, а не
 * дописывание в home.css: канон «максимальная фрагментация кода», home.css
 * обслуживает наследие модульной сетки и шапки.
 *
 * Все значения — токены из styles/themes.css (канон «Tokens > literals»).
 * Селекторы заскоуплены на #dashboard, чтобы глобальные правила styles.css
 * (`header`, `header h1`, `.home-main h2`) не перебивали вёрстку и наоборот.
 *
 * Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md (P1/P2/P3),
 * wiki/decisions/adr-018-personal-dashboard-home.md.
 * Chat: personal-dashboard-2026-08-15.
 */

/* ===================================================================
   Каркас трёх зон (P1)
   =================================================================== */

/* [2026-08-15] Раскладка — КАНОН модуля активностей (wbs-panel.css:45-119):
   flex-контейнер, левая панель примыкает вплотную, контент занимает остаток.
   Никаких grid-колонок с зазором и никакой «плавающей карточки» — панель
   отделена от контента только `border-right`, как WBS.
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P1/P2. Chat: personal-dashboard-2026-08-15. */
/* [2026-08-16] Страница НЕ скроллится — скроллится содержимое.
   Это канон модуля активностей: `.page-content-wrapper { flex: 1; overflow: hidden }`
   (wbs-panel.css:45-50), а прокрутка живёт внутри панели и таблицы. Раньше зоны
   выкладывались в столбик и суммарно перерастали экран: 505px задачник + 255px
   проекты + паддинги = 1028px при экране 750px, отсюда лишний вертикальный
   скролл при пустом месте на экране (скрин PO).

   `height` ограничивает (а не растягивает, как запрещённый `min-height: 100vh`):
   дашборд занимает ровно свободную высоту под шапкой, внутренности скроллятся.
   Ref: DESIGN.md §«Лэйаут страницы». Chat: personal-dashboard-2026-08-15. */
/* [2026-08-18] Высоту рабочей области отдаём flex-контейнеру страницы: фактическая
   высота Header может меняться при локализации/переносе, поэтому фиксированный
   вычет 62px обрезал контент на узких экранах.
   Ref: docs/QA_INDEX_UI_UX_AUDIT_2026-08-18.md P1-5. Chat: index-ui-ux-audit-2026-08-18. */
html {
    height: 100%;
}

body.dashboard-page {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
    overflow: hidden;
}

body.dashboard-page > header {
    flex: 0 0 auto;
}

.home-main {
    /* Высота = окно минус шапка. Нижние 70px, которые `bottom-action-bar.css`
       резервирует через `body { padding-bottom }`, НЕ вычитаем: иначе внизу
       остаётся мёртвая полоса и линия левой панели обрывается, не доходя до
       края (скрин PO 2026-08-16). Резерв под фиксированную нижнюю полосу даёт
       сам контент своим `padding-bottom`, а панель идёт до самого низа. */
    height: auto;
    flex: 1 1 auto;
    min-height: 0;
    box-sizing: border-box;
    overflow: hidden;
    /* Отступов у страницы нет: левая панель обязана прилегать к краю окна и
       её разделительная линия — идти до самого низа. Воздух добавляет
       контент справа, а не общий padding. */
    padding: 0;
    /* home.css задаёт `max-width: 1200px; margin: 0 auto` — на дашборде это
       центрировало страницу и оставляло пустую полосу слева, из-за чего левая
       панель висела в воздухе, а не у края окна (скрин PO 2026-08-16).
       Сбрасываем ОБА свойства, иначе margin:auto продолжает центрировать. */
    max-width: none;
    margin: 0;
    width: 100%;
}

.home-main .modules-wrapper {
    height: 100%;
    min-height: 0;
}

#dashboard.dashboard-body {
    display: flex;
    /* stretch, а НЕ flex-start: панель тянется на всю высоту области, и её
       `border-right` доходит до низа — как у WBS в активностях. С flex-start
       линия обрывалась по высоте содержимого (замечание PO 2026-08-16). */
    align-items: stretch;
    gap: 0;
    height: 100%;
    min-height: 0;
    overflow: hidden;
}

/* Правая часть — аналог `.right-content`: тулбар + зоны в колонку. */
#dashboard .dash-content {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    /* Место под фиксированную нижнюю полосу — здесь, а не у `body`. */
    padding: var(--space-4) var(--space-5) calc(var(--bottom-bar-height, 42px) + var(--space-3));
    /* min-height: 0 обязателен — без него flex-ребёнок не даёт себя сжать и
       внутренний скролл не включается, страница снова вылезает за экран. */
    min-height: 0;
    overflow-y: auto;
    gap: var(--space-5);
}

/* Тулбар контента — здесь живёт кнопка панели, ровно как в активностях
   она живёт в `.module-controls-row`, а не сбоку от самой панели. */
#dashboard .dash-content-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* ── Сама панель: 1-в-1 механика `.wbs-panel` ── */
#dashboard .dash-tools-panel {
    height: 100%;
    /* [2026-08-20] Ширина берётся из переменной, которую ставит
       modules/home/DashboardPanel.js: край панели тянется мышью и стрелками,
       значение помнится между сессиями — как у правой панели (PO 2026-08-20).
       Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    width: var(--dash-panel-w, 260px);
    min-width: var(--dash-panel-w, 260px);
    max-width: var(--dash-panel-w, 260px);
    position: relative;
    background: var(--bg-primary);
    border-right: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    transition:
        width 0.3s ease,
        min-width 0.3s ease,
        margin-left 0.3s ease,
        opacity 0.3s ease;
    overflow: hidden;
    flex-shrink: 0;
}

/* Схлопнутое состояние — как у WBS, вместе с `margin-left:-1px`,
   который прячет собственный бордер панели. */
#dashboard .dash-tools-panel.collapsed {
    width: 0;
    min-width: 0;
    margin-left: -1px;
    opacity: 0;
    pointer-events: none;
}

/* [2026-08-16] Иконка из шапки раздела убрана (PO: «у разделов убери иконки»),
   поэтому и правило `.dash-tools-panel-icon` удалено, а не оставлено мёртвым.
   Горизонтальный отступ выровнен с ярлыками и заголовком нижнего раздела (16px),
   иначе «Tools» висел левее «Settings».
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P2. Chat: personal-dashboard-2026-08-15. */
#dashboard .dash-tools-panel-header {
    display: flex;
    align-items: center;
    padding: 1rem 16px;
    box-sizing: border-box;
    background: var(--bg-primary);
    flex-shrink: 0;
}

#dashboard .dash-tools-panel-title {
    margin: 0;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: normal;
    white-space: nowrap;
}

#dashboard .dash-tools-panel-content {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    flex: 1;
    /* [2026-08-15] Резерв под fixed-баннер BreadcrumbPath — В КОНТЕНТЕ, не вычетом
       высоты лэйаута (канон аннотации выше: вычет обрывал линию панели — прошлый
       скрин PO): прижатый Settings (rev.24.3) уходил ПОД баннер (новый скрин PO).
       Ref: docs/QA_SBS_BOOTSTRAP_PARALLEL_PREAMBLE_2026-08-13.md §4h rev.24.3.
       Chat: sbs-bootstrap-parallel-preamble-2026-08-13. */
    padding-bottom: var(--bottom-bar-height, 42px);
    box-sizing: border-box;
}

/* ── Кнопка-переключатель: копия `.wbs-toggle-btn` ── */
#dashboard .dash-tools-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    cursor: pointer;
    /* [2026-09-18] Перечень вместо `all` (аудит Д1, закрытие хвоста).
       Ref: docs/AUDIT_UI_MOTION_2026-09-17.md Д1. Chat: ui-motion-fixes-2026-09-17. */
    transition:
        background-color var(--transition-base),
        border-color var(--transition-base),
        color var(--transition-base),
        box-shadow var(--transition-base),
        transform var(--transition-base);
}

#dashboard .dash-tools-toggle-btn:hover {
    background-color: var(--bg-hover);
    color: var(--brand-primary);
}

#dashboard .dash-tools-toggle-btn.active {
    color: var(--brand-primary);
}

#dashboard .dash-tools-toggle-btn .dash-tools-toggle-icon {
    font-size: 20px;
    transition: transform 0.2s ease;
}

#dashboard .dash-tools-toggle-btn.active .dash-tools-toggle-icon {
    transform: rotate(180deg);
}

/* [2026-08-16] Разделы лэйаута — БЕЗ контейнеров-боксов: ни рамки, ни фона,
   ни скругления (PO 2026-08-16 + DESIGN.md:368 «Decorative borders/shadows
   removed on cards/panels», themes.css:402+). Секция отделяется заголовком и
   воздухом, как в модулях (activities/tracker), а не нарисованной коробкой.
   Ref: DESIGN.md §«Лэйаут». Chat: personal-dashboard-2026-08-15. */
#dashboard .dash-zone {
    min-width: 0;
    background: none;
    border: 0;
    border-radius: 0;
    padding: 0;
}

#dashboard .dash-zone-header {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
    flex-wrap: wrap;
}

/* Перебивает глобальное `.home-main h2` (uppercase + letter-spacing),
   которое рассчитано на прежние секции модульной сетки. */
#dashboard .dash-zone-title {
    margin: 0;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: normal;
}

#dashboard .dash-zone-hint {
    margin: 0;
    font-size: var(--font-size-xs);
    color: var(--text-tertiary);
}

#dashboard .dash-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 20px;
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    background-color: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
}

#dashboard .dash-zone-filters {
    display: flex;
    gap: var(--space-1);
    margin-left: auto;
}

/* ===================================================================
   Зона 1 — Задачник (P3)
   =================================================================== */

/* [2026-08-15] Свёрнуто и развёрнуто — взаимоисключающие состояния (PO:
   «Show должен обрезать текст и не должно быть скролла; нажал — список
   расширился, Show исчез и появился скролл, а внизу Hide»).

   Свёрнутый список НЕ имеет ни max-height, ни своего скролла: он ровно по
   семи строкам, и кнопка «Показать ещё» видна сразу, без вылавливания её
   скроллом. Скролл появляется ТОЛЬКО в развёрнутом состоянии.
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P3. Chat: personal-dashboard-2026-08-15. */
#dashboard .dash-tasks-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

#dashboard .dash-tasks-list.expanded {
    max-height: 420px;
    overflow-y: auto;
}

/* Панель тоже скроллится внутри себя, а не тянет страницу. */
#dashboard .dash-tools-panel-content {
    min-height: 0;
}

/* Кнопка живёт ВНЕ списка: в развёрнутом состоянии она не уезжает вместе
   с его скроллом, а остаётся прижатой снизу зоны. */
#dashboard .dash-tasks-more {
    display: flex;
}

#dashboard .dash-tasks-more:empty {
    display: none;
}

#dashboard .dash-task-row {
    display: grid;
    /* [2026-08-15] 5-я колонка: кнопка «Перейти к активности» (rev.24) добавилась в
       строку, а grid был на 4 — пятый элемент (папка) падал на вторую строку и
       раздувал карточку (замечание PO). Ref:
       docs/QA_SBS_BOOTSTRAP_PARALLEL_PREAMBLE_2026-08-13.md §4h rev.24.2.
       Chat: sbs-bootstrap-parallel-preamble-2026-08-13. */
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: none;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
    transition: background-color var(--transition-fast);
}

#dashboard .dash-task-row:hover {
    background-color: var(--bg-hover);
}

#dashboard .dash-task-row:focus-visible {
    outline: 2px solid var(--brand-primary);
    outline-offset: -2px;
}

/* [2026-08-18] Ошибка загрузки визуально и семантически отличается от штатного
   пустого списка; повтор использует обычную кнопку без декоративного контейнера.
   Ref: docs/QA_INDEX_UI_UX_AUDIT_2026-08-18.md P1-4. Chat: index-ui-ux-audit-2026-08-18. */
#dashboard .dash-error,
#dashboard .frames-load-error {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    min-height: 72px;
    padding: var(--space-4);
    /* [2026-08-22, найдено ревью] Было `var(--color-danger, …)` — такого токена
       в проекте НЕТ (themes.css определяет `--color-error`, строки 106 и 333).
       Переменная не резолвилась, срабатывал запасной `--text-secondary`, и текст
       ошибки красился ровно как обычный пустой список — то есть правило не
       выполняло того, ради чего написано (аннотация выше: «ошибка визуально
       отличается от штатного пустого списка»). Токен исправлен на существующий.
       Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    color: var(--color-error);
    text-align: center;
}

#dashboard .dash-error .material-icons,
#dashboard .frames-load-error .material-icons {
    font-size: 20px;
}

/* [2026-08-16] Жёлтая/оранжевая левая кромка rework-таска УБРАНА по прямому указанию PO
   («убери эти корешки»). Ранее: `border-left: 3px solid var(--color-warning)` («как в
   step-by-step»). Класс `.is-rework` оставлен на строке (может использоваться логикой),
   но визуального «корешка» больше нет. Ref: указание PO в чате. Chat: universal-sidebar-embed-2026-08-16. */
#dashboard .dash-task-row.is-rework {
    /* no left accent bar */
}

#dashboard .dash-task-main {
    min-width: 0;
}

#dashboard .dash-task-name {
    display: block;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#dashboard .dash-task-path {
    display: block;
    font-size: var(--font-size-xs);
    color: var(--text-tertiary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#dashboard .dash-task-date {
    font-size: var(--font-size-xs);
    color: var(--text-tertiary);
    white-space: nowrap;
}

#dashboard .dash-task-files-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1);
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-tertiary);
    cursor: pointer;
}

#dashboard .dash-task-files-toggle:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
}

#dashboard .dash-task-files-toggle .material-icons {
    font-size: 18px;
}

/* Файлы конкретного таска (work-секция, ?section=work&taskId=…). */
#dashboard .dash-task-files {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: var(--space-1) 0 var(--space-2) var(--space-6);
}

#dashboard .dash-task-file {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: var(--font-size-xs);
    text-decoration: none;
}

#dashboard .dash-task-file:hover {
    background-color: var(--bg-hover);
    color: var(--text-primary);
}

#dashboard .dash-task-file .material-icons {
    font-size: 16px;
}

#dashboard .dash-task-files-empty {
    font-size: var(--font-size-xs);
    color: var(--text-tertiary);
    padding: var(--space-1) var(--space-2);
}

/* Статус-пилюли — цвета по DESIGN.md §Status pills. */
#dashboard .dash-status {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

#dashboard .dash-status-pending {
    background-color: var(--color-warning-bg);
    color: var(--color-warning);
}
#dashboard .dash-status-in_progress {
    background-color: var(--color-info-bg);
    color: var(--color-info);
}
#dashboard .dash-status-active {
    background-color: var(--color-info-bg);
    color: var(--color-info);
}
#dashboard .dash-status-completed {
    background-color: var(--color-success-bg);
    color: var(--color-success);
}
#dashboard .dash-status-cancelled {
    background-color: var(--color-error-bg);
    color: var(--color-error);
}

#dashboard .dash-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-8) var(--space-4);
    color: var(--text-tertiary);
    text-align: center;
    font-size: var(--font-size-sm);
}

#dashboard .dash-empty .material-icons {
    font-size: 48px;
}

#dashboard .dash-loader {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-6);
    color: var(--text-tertiary);
    font-size: var(--font-size-sm);
}

#dashboard .dash-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border-primary);
    border-top-color: var(--brand-primary);
    border-radius: var(--radius-full);
    /* [2026-09-18] Д10: скорость — из общего токена (значение прежнее).
       Ref: docs/AUDIT_UI_MOTION_2026-09-17.md Д10. Chat: ui-motion-fixes-2026-09-17. */
    animation: dash-spin var(--spinner-duration) linear infinite;
}

@keyframes dash-spin {
    to {
        transform: rotate(360deg);
    }
}

#dashboard .dash-more-btn {
    align-self: flex-start;
    margin-top: var(--space-2);
    padding: var(--space-1) var(--space-2);
    border: none;
    background: none;
    color: var(--brand-primary);
    font-size: var(--font-size-xs);
    font-family: inherit;
    cursor: pointer;
}

/* ===================================================================
   Зона 3 — Инструменты: ЛЕВАЯ ПАНЕЛЬ (P2)

   [2026-08-15] Плиточный «рабочий стол» заменён левой панелью по прямому
   указанию PO. Классы и геометрия — КАНОН редакторов
   (modules/documents/css/documents.css:35-124: `.editor-tools-panel`,
   `.tools-panel-section/-label/-arrow/-items/-btn`). Здесь описаны те же
   имена, заскоупленные на `#dashboard`, потому что documents.css неотделим
   от layout'а страницы-редактора (`.editor-canvas-wrapper` и соседи) и
   тянуть его на главную ради панели нельзя. Значения держим синхронными с
   каноном: 36px высота строки, gap 10px, padding 0 16px, иконка 20px
   `--brand-primary`, ярлык 11px `--text-tertiary`.
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P2. Chat: personal-dashboard-2026-08-15.
   =================================================================== */

/* [2026-08-16] Два раздела панели, разделённые ЛИНИЕЙ (PO по скрину
   2026-08-16): верхний — инструменты, нижний — «Settings». Линия — это
   `border-top` у второго раздела, а не отдельный элемент-разделитель и не
   рамка вокруг раздела: коробки в лэйауте запрещены (DESIGN.md §«Лэйаут
   страницы»). У одного раздела линии нет вовсе — не за что зацепиться глазу.
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P2. Chat: personal-dashboard-2026-08-15. */
#dashboard .dash-tools-section {
    display: flex;
    flex-direction: column;
}

#dashboard .dash-tools-section + .dash-tools-section {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-color);
}

/* [2026-08-15] Settings прижат к НИЗУ панели (приказ PO). Правило стоит НИЖЕ
   соседнего `+`-правила: специфичность равная, каскад решает порядок — выше
   по файлу margin-top:auto перебивался его var(--space-3) (пойман live-замером
   под админом: computed 12px, gap до низа 370px).
   Ref: docs/QA_SBS_BOOTSTRAP_PARALLEL_PREAMBLE_2026-08-13.md §4h rev.24.3.
   Chat: sbs-bootstrap-parallel-preamble-2026-08-13. */
#dashboard .dash-tools-section[data-section='settings'] {
    margin-top: auto;
}

/* Заголовок раздела — слово БЕЗ иконки (PO: «у разделов убери иконки»).
   Выравнен по левому краю подписи шапки панели: тот же горизонтальный
   отступ 16px, что у ярлыков. */
#dashboard .dash-tools-section-title {
    margin: 0 0 var(--space-1);
    padding: 0 16px;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: normal;
}

/* Строка-ярлык: иконка + подпись, как `.tools-panel-btn` в редакторах.
   Здесь это ссылка (`<a href>`), чтобы работали средний клик и «открыть в
   новой вкладке» — ярлык ведёт на страницу модуля, а не выполняет действие. */
#dashboard .dash-tool-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: 36px;
    padding: 0 16px;
    background: transparent;
    border: none;
    color: var(--text-primary);
    cursor: pointer;
    transition: background var(--transition-fast);
    font-size: var(--font-size-sm);
    text-align: left;
    text-decoration: none;
}

#dashboard .dash-tool-item:hover {
    background: var(--bg-hover);
}

#dashboard .dash-tool-item .material-icons {
    font-size: 20px;
    color: var(--brand-primary);
    flex-shrink: 0;
    width: 24px;
    text-align: center;
}

#dashboard .dash-tool-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===================================================================
   Адаптив — одна колонка, порядок Задачник → Проекты → Инструменты
   =================================================================== */

@media (max-width: 1279px) {
    /* [2026-08-15] Узкий экран: панель не занимает колонку постоянно —
       контент важнее. Ширина уменьшена, отступ контента сжат.
       Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P2. Chat: personal-dashboard-2026-08-15. */
    /* [2026-08-22, найдено вторым ревью] Ширина берётся ИЗ ПЕРЕМЕННОЙ, а 200px
       остаются лишь умолчанием этого экрана. Прежние литеральные 200px убивали
       растягивание края целиком: селектор тот же (`#dashboard .dash-tools-panel`,
       специфичность 1:1 с базовым правилом), медиазапрос веса не добавляет, но
       стоит НИЖЕ по файлу — значит на ЛЮБОМ окне до 1280px включительно правило
       перебивало `var(--dash-panel-w)`. Пользователь тянул край, значение
       уходило в localStorage, а панель не двигалась вовсе — требование PO
       «край панели растягивается, настройки с памятью» молча не работало на
       ноутбуке 1280×800 и в окне на пол-экрана.
       Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    #dashboard .dash-tools-panel {
        width: var(--dash-panel-w, 200px);
        min-width: var(--dash-panel-w, 200px);
        max-width: var(--dash-panel-w, 200px);
    }

    #dashboard .dash-content {
        padding-left: var(--space-4);
    }
}

/* [2026-08-18] На телефоне панель инструментов становится overlay: её открытие
   больше не сжимает рабочую область и не обрезает фильтры/строки задач.
   Ref: docs/QA_INDEX_UI_UX_AUDIT_2026-08-18.md P1-5. Chat: index-ui-ux-audit-2026-08-18. */
@media (width <= 767.98px) {
    #dashboard.dashboard-body {
        position: relative;
    }

    /* [2026-08-22] Телефон: панель-overlay. Пользовательская ширина уважается,
       но зажата шириной экрана — `min(...)` не даёт выехать за край, а умолчание
       остаётся прежним (260px или меньше на узком экране). Раньше здесь тоже
       стояла литеральная ширина, гасившая растягивание.
       Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    #dashboard .dash-tools-panel {
        position: absolute;
        inset: 0 auto 0 0;
        z-index: var(--z-sticky);
        width: min(var(--dash-panel-w, 260px), calc(100% - var(--space-16)));
        min-width: min(var(--dash-panel-w, 260px), calc(100% - var(--space-16)));
        max-width: min(var(--dash-panel-w, 260px), calc(100% - var(--space-16)));
        box-shadow: var(--shadow-lg);
    }

    #dashboard .dash-tools-panel.collapsed {
        width: 0;
        min-width: 0;
        margin-left: -1px;
        box-shadow: none;
    }

    #dashboard .dash-content {
        padding-right: var(--space-3);
        padding-left: var(--space-3);
    }

    /* Toggle остаётся снаружи overlay и доступен для закрытия панели. */
    #dashboard .dash-tools-toggle-btn {
        position: relative;
        z-index: calc(var(--z-sticky) + 1);
    }

    #dashboard .dash-tools-toggle-btn.active {
        background: var(--bg-primary);
        box-shadow: var(--shadow-sm);
        transform: translateX(min(260px, calc(100vw - var(--space-16))));
    }

    #dashboard .dash-zone-filters,
    #dashboard #frames-filter-select {
        width: 100%;
        max-width: 100%;
        margin-left: 0;
    }

    #dashboard .dash-task-row {
        grid-template-columns: auto minmax(0, 1fr) auto auto;
        gap: var(--space-2);
    }

    #dashboard .dash-task-date {
        grid-row: 2;
        grid-column: 2;
    }
}

/* [2026-08-18] Уважаем системное предпочтение уменьшенного движения во всех
   интерактивных элементах главной, включая loader.
   Ref: docs/QA_INDEX_UI_UX_AUDIT_2026-08-18.md P2-2. Chat: index-ui-ux-audit-2026-08-18. */
@media (prefers-reduced-motion: reduce) {
    #dashboard .dash-tools-panel,
    #dashboard .dash-tools-toggle-btn,
    #dashboard .dash-tools-toggle-icon,
    #dashboard .dash-task-row,
    #dashboard .dash-tool-item {
        transition: none !important;
    }

    #dashboard .dash-spinner {
        animation: none !important;
    }
}

/* [2026-08-16] Список проектов на дашборде — ПО СОДЕРЖИМОМУ.
   `.frames-list` из activity-modal.css несёт `min-height: 300px` и
   `max-height: 500px` — это размеры для МОДАЛКИ выбора фрейма. На главной они
   давали пустую дыру под двумя проектами (стрелка PO 2026-08-16) и лишнюю
   высоту страницы со скроллом на пустом месте. Здесь список живёт по своему
   содержимому, а прокрутка появляется только когда проектов реально много.
   Ref: DESIGN.md §«Лэйаут» (запрет вёрстки выше вьюпорта без нужды).
   Chat: personal-dashboard-2026-08-15. */
#dashboard .frames-list {
    min-height: 0;
    max-height: 420px;
}

#dashboard .frames-empty {
    min-height: 0;
    padding: var(--space-6) var(--space-4);
}

/* [2026-08-16] Снимаем резерв `body.has-bottom-action-bar { padding-bottom: 70px }`
   из bottom-action-bar.css: на дашборде страница не скроллится, и этот резерв
   превращался в пустую полосу внизу под панелью — линия панели обрывалась выше
   низа окна, а документ становился на 70px выше вьюпорта (лишний вертикальный
   скролл). Селектор — `html body.has-bottom-action-bar`: bottom-action-bar.css
   подключён в index.html ПОСЛЕ dashboard.css (строки 35 и 29), поэтому при
   равной специфичности выигрывал бы он — лишний `html` поднимает вес. Реальная
   нижняя полоса — `position: fixed`, высотой 42px; место под неё даёт
   `.dash-content { padding-bottom: 56px }` (см. выше), а не отступ `body`.
   Ref: DESIGN.md §«Лэйаут страницы». Chat: personal-dashboard-2026-08-15. */
html body.has-bottom-action-bar {
    padding-bottom: 0;
}

/* [2026-08-16] ФИЛЬТР-СЕЛЕКТОРЫ вместо псевдо-вкладок (PO 2026-08-16).
   Ширина — по содержимому, а не на всю строку: растянутый на всю ширину
   контрол это ровно та же болезнь, что и прежние вкладки-простыни.
   `.searchable-select` по умолчанию `width: 100%` (styles/searchable-select.css),
   поэтому ограничиваем здесь, точечно для дашборда.
   Ref: docs/TZ_PERSONAL_DASHBOARD_2026-08-15.md P1/P3. Chat: personal-dashboard-2026-08-15. */
#dashboard .dash-zone-filters,
#dashboard #frames-filter-select {
    width: 200px;
    flex: 0 0 auto;
}

/* Фильтр задачника прижат к правому краю шапки зоны (там же, где были вкладки). */
#dashboard .dash-zone-filters {
    margin-left: auto;
}

/* [2026-08-16] Фильтр проектов встал НА ЛИНИЮ ЗАГОЛОВКА (PO: «поменяй местами…
   у тасков фильтр-селектор стоит на одной линии с заголовком»), а Create и поиск
   переехали строкой ниже — над списком. */
#dashboard #frames-filter-select {
    margin-left: auto;
}

#dashboard .homepage-actions-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* ===================================================================
   [2026-08-20] РАЗДЕЛ «ПРОЕКТЫ» В ЛЕВОЙ ПАНЕЛИ

   Переезд из центра страницы (PO, скрин 2026-08-20). Задачи — лента, по
   которой работают, и она остаётся в середине; проекты — навигация, её место
   у края. Правила ниже держат три вещи: раздел растягивается на свободную
   высоту панели, список скроллится ВНУТРИ себя (страница не растёт), а
   «Настройки» остаются прижатыми к низу — теперь они в своём контейнере,
   потому что между ними и инструментами встал новый раздел.

   Коробок нет: разделы отделяет та же одна линия (`border-top`), что уже
   разделяла инструменты и настройки. DESIGN.md §«Лэйаут страницы».
   Ref: docs/TZ_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §3.
   Chat: projects-to-left-panel-2026-08-20.
   =================================================================== */
#dashboard .dash-tools-panel > .dash-zone-projects {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    margin-top: var(--space-3);
    padding: var(--space-3) 0 0;
    border-top: 1px solid var(--border-color);
    /* Внутри панели зона не рисует собственный фон/рамку — это раздел, не карточка. */
    background: none;
    box-shadow: none;
}

/* [2026-08-20] Тело раздела делит высоту панели, а не выдавливает соседей.
   Обёртка `[data-panel-section-body]` появилась ради сворачивания и встала между
   flex-секцией и списком: список перестал быть flex-ребёнком и считал высоту по
   себе. Живой замер под ролью, которой видны «Настройки»: секция проектов
   313→784px (471), тело 404→1558px (1154) — на 774px ниже секции, поверх
   «Настроек» (скрин PO «settings наезжают на раздел проектов и смешиваются»).
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-panel-section > [data-panel-section-body] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

/* [2026-08-22] Правило «инструменты по содержимому» (`flex: 0 0 auto`) ОБЪЕДИНЕНО
   с блоком ниже по файлу: после починки мёртвого селектора оба правила стали
   целить одним и тем же селектором, и два объявления одного и того же
   расходились бы при следующей правке. Единственное место — там же, где
   `overflow` и `padding-bottom`.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */

/* [2026-08-22, отменено] Здесь стояло `position: relative; z-index: 2` у шапки —
   попытка вылечить «прозрачное меню фильтра» слоями. Она НЕ помогла (PO прислал
   тот же скрин) и вредила: шапка становилась контекстом наложения, и z-index
   выпадающего списка схлопывался с 1000 до 2, конкурируя со всем, что на
   дашборде лежит между 3 и 1020. Цвет слоями не чинится — правка снята, причина
   лечится фоном самого меню (правило ниже по файлу).
   Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .dash-zone-header {
    flex: 0 0 auto;
    padding: 0 16px;
}

/* Подпись раздела на узкой панели только отнимает высоту у списка. */
#dashboard .dash-tools-panel > .dash-zone-projects .dash-zone-hint {
    display: none;
}

#dashboard .dash-tools-panel > .dash-zone-projects .homepage-actions-row {
    flex: 0 0 auto;
    padding: var(--space-2) 16px;
}

/* Фильтр-селектор сужается до ширины панели: 200px из центра сюда не влезут. */
#dashboard .dash-tools-panel > .dash-zone-projects #frames-filter-select {
    width: 100%;
    min-width: 0;
    margin-left: 0;
}

/* Скроллер РОВНО ОДИН — сам список. Обёртка пикера только растягивается:
   живой замер показал два вложенных скролла (обёртка 438px и список 420px из-за
   `max-height`, оставшегося от центральной раскладки) — в панели шириной 260px
   это две полосы прокрутки подряд и мёртвая щель между ними.
   Ref: docs/TZ_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §3. Chat: projects-to-left-panel-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects #frame-selection-modal {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
    overflow: visible;
    padding: 0 16px var(--space-3);
    /* [2026-08-22] Содержимое раздела прижато НИЖЕ фильтра.
       Скрин PO с открытым меню и текстом «Loading frames…» ПОВЕРХ пункта показал,
       что перекрывает меню не список, а любой элемент тела раздела: у класса
       `.loader` (`#frames-loader`) в проекте нет НИ ОДНОГО правила — он не
       позиционирован и своего слоя не имеет, но всё равно рисуется выше. Значит
       шапка и тело конкурировали за порядок, и подъёма одного фильтра не хватало.
       Собственный контекст с нулевым уровнем гарантирует, что ВСЁ внутри тела
       (загрузчик, список, пустое состояние) ниже фильтра (z-index 20).
       Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    position: relative;
    /* `!important` ОБЯЗАТЕЛЕН и вот почему (замер в браузере 2026-08-22):
       `activity-modal.css:2153` объявляет `#frame-selection-modal { z-index: 1900
       !important }` — уровень МОДАЛЬНОГО ОКНА, нужный, когда пикер открыт как
       модалка поверх страницы. В левой панели тот же пикер встроен в раздел, и
       модальный уровень поднимал ВСЁ его содержимое над фильтром (20): замер
       `elementFromPoint` в центре открытого меню возвращал `frame-row-name`, то
       есть строку списка, а не меню. Без `!important` перебить чужое
       `!important` нельзя. */
    z-index: 0 !important;
}

#dashboard .dash-tools-panel > .dash-zone-projects #frames-list {
    flex: 1 1 auto;
    min-height: 0;
    /* Потолок 420px — из центральной раскладки; в панели список занимает всю
       свободную высоту, иначе внизу остаётся пустое место. */
    max-height: none;
    overflow-y: auto;
    /* [2026-08-22] Зазор между строками ужат вдвое (PO 2026-08-22, скрин:
       «нужно уменьшить зазор между строками проектов, сейчас большой разрыв»).
       Список наследовал `gap: var(--space-2)` из ЦЕНТРАЛЬНОЙ модалки выбора
       фрейма, где строки крупнее и воздух между ними уместен; в узкой панели
       навигации он давал разрыв, из-за которого в список помещалось меньше
       проектов. В модалке прежний зазор сохраняется — правило заскоуплено.
       Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md §1.3.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    gap: var(--space-1);
}

/* [2026-08-20, по живому скрину] Инструменты занимают ВЫСОТУ ПО СОДЕРЖИМОМУ.
   Общее правило `.dash-tools-panel-content { flex: 1; overflow-y: auto }` писалось
   под панель из одного списка: когда ниже встал растягивающийся раздел «Проекты»,
   инструменты сжались до одной строки со своей полосой прокрутки (замер: высота 42px
   при содержимом 186px — на скрине видно только «Document»).
   [2026-08-22, найдено ревью] Селектор с прямым потомком (`.dash-tools-panel >
   #dash-tools-grid`) СТАЛ МЁРТВЫМ 2026-08-20: ради сворачивания сетку обернули
   в `<div class="dash-panel-section" data-panel-section="tools">` (index.html),
   и прямым потомком панели она быть перестала. Из трёх объявлений уцелело
   только `flex` (правило выше по файлу, привязанное к разделу), а
   `padding-bottom: 0` и `overflow: visible` потерялись — сетка снова забирала
   `padding-bottom: var(--bottom-bar-height, 42px)` от общего правила
   `.dash-tools-panel-content` (строка ~189), которое рассчитано на ПОСЛЕДНИЙ
   блок панели, стоящий над фиксированной нижней полосой. В середине панели это
   давало пустую полосу в 42px+ между ярлыками и разделом «Проекты» и отнимало
   столько же высоты у списка проектов. Селектор приведён к фактической
   вложенности.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-panel-section > #dash-tools-grid {
    flex: 0 0 auto;
    overflow: visible;
    padding-bottom: 0;
}

/* Настройки в своём контейнере: прижаты к низу и отделены той же линией.
   Резерв под фиксированную нижнюю полосу оставляем ЗДЕСЬ (у последнего раздела),
   иначе «Настройки» уходят под неё — этот случай уже ловился скрином PO. */
#dashboard .dash-panel-settings {
    flex: 0 0 auto;
    margin-top: 0;
    overflow: visible;
}

#dashboard .dash-panel-settings .dash-tools-section[data-section='settings'] {
    /* Прижатие к низу теперь даёт растянутый раздел «Проекты», а не auto-margin
       внутри общей сетки: иначе настройки уезжали бы вверх к инструментам. */
    margin-top: 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--border-color);
}

/* [2026-08-20] Строка «Create + поиск» внутри панели живёт по ширине панели.
   Она приехала из центра страницы со своими размерами: раскрытое поле там
   фиксировано на 200px, сама строка прижата вправо и не переносится. Живой
   замер в панели: панель 340px, строка 405px, правый край поля 389px — вылет
   49px, поле обрезано границей панели (скрин PO «поле поиска не видит границы
   левой панели и обрезается»). Правила ограничены панелью — в центре и в
   step-by-step прежняя раскладка не меняется.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .homepage-actions-row {
    flex-wrap: wrap;
    margin-left: 0;
    min-width: 0;
    max-width: 100%;
}

/* [2026-08-20] Фильтр, «Create» и поиск — ОДНОЙ ЛИНИЕЙ, кнопки компактные
   (PO 2026-08-20: «сделай фильтр, кнопку добавить и поиск в одну линию, кнопки
   сделай меньше по стилю» + скрин).

   [2026-08-22] Раскладка строки ПЕРЕСМОТРЕНА, прежнее описание («фильтр
   забирает свободное место», «раскрытое поле уходит на свою строку») больше не
   действует — PO 2026-08-22 потребовал обратного: «поле поиска также в одну
   строку с кнопками после раскрытия» и «меню фильтра такое длинное и
   растягивается и всё место занимает». Действующее распределение строки:
   фильтр — компактный по содержимому (grow 0, потолок 140px), «Create» и лупа —
   иконки по 28px, раскрытое поле поиска — забирает ВЕСЬ остаток строки
   (grow 1, базис 60px). Четыре контрола в одном ряду стали возможны после
   снятия двух блокировок: `flex: 1 0 100%` у фильтра (он занимал строку
   целиком) и коробки-посредника `.homepage-actions-row` (`display: contents`).
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .dash-zone-title {
    order: 0;
    flex: 1 1 auto;
}

#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .dash-section-caret {
    order: 1;
    margin-left: auto;
}

/* Разрыв строки: название со значком забирают первую линию целиком, фильтр и
   кнопки встают на вторую — все три в один ряд, как просил PO.

   [2026-08-22, найдено вторым ревью] Добавлен `margin-top: calc(-1 * …gap)`.
   Псевдоэлемент с базисом 100% не «дописывается» к первой линии, а образует
   СВОЮ, пустую flex-линию: шапка получает три линии вместо двух, и вертикальный
   зазор между заголовком и строкой контролов удваивался (два gap'а по 8px
   вокруг пустой линии вместо одного). Отрицательный отступ гасит ровно один
   лишний зазор. В свёрнутом разделе он же убирает пустую полосу под заголовком:
   правило скрытия гасит фильтр и кнопки, но не псевдоэлемент.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header::after {
    content: '';
    order: 2;
    flex: 0 0 100%;
    height: 0;
    margin-top: calc(-1 * var(--space-2));
}

/* [2026-08-22] Фильтр — КОМПАКТНЫЙ, по своему содержимому (PO 2026-08-22:
   «меню фильтра проектов такое длинное и растягивается и всё место занимает»).
   `flex-grow: 0` — он больше не забирает свободную ширину строки; остаток
   строки принадлежит полю поиска (правило ниже). `width: auto` перебивает
   `width: 100%`, доставшееся фильтру от прежней раскладки, где он занимал
   строку целиком. Потолок 140px не даёт длинной подписи («My Favorites»)
   выдавить кнопки, `flex-shrink: 1` + `min-width: 0` позволяют ужаться на
   самой узкой панели вместо переноса.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > #frames-filter-select {
    order: 3;
    flex: 0 1 auto;
    width: auto;
    min-width: 0;
    max-width: 140px;
}

/* [2026-08-22] `display: contents` — ЭТО и есть «одна линия» (PO: «сделай фильтр,
   кнопку добавить и поиск в одну линию», повторно 2026-08-22 со скрином).

   Причина прежних провалов: «Create», лупа и поле поиска лежат во ВЛОЖЕННОМ
   контейнере `.homepage-actions-row`. Для шапки раздела это ОДИН flex-элемент,
   поэтому фильтр и кнопки в принципе не могли делить строку: они на разных
   уровнях вложенности. Хуже того, раскрытое поле (`flex: 1 1 100%`) переносилось
   ВНУТРИ этого контейнера, растягивало его на две строки — и кнопки уезжали
   ОТДЕЛЬНОЙ строкой над фильтром (скрин PO). Никакая настройка `flex`/`order` у
   самого контейнера этого не чинит — чинит только устранение уровня вложенности.

   `display: contents` убирает коробку контейнера из раскладки, оставляя разметку
   и все обработчики нетронутыми: `#create-frame-btn`, `#frame-search-toggle-btn`
   и `#frame-search-wrapper` становятся ПРЯМЫМИ flex-элементами шапки и встают в
   один ряд с фильтром. Порядок задаём явно (order 4/5/6): по умолчанию у них
   `order: 0`, и они бы перепрыгнули на строку заголовка.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .homepage-actions-row {
    display: contents;
}

#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .homepage-actions-row > #create-frame-btn {
    order: 4;
    flex: 0 0 auto;
}

#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .homepage-actions-row > #frame-search-toggle-btn {
    order: 5;
    flex: 0 0 auto;
}

/* Поле поиска — четвёртый элемент строки. Свёрнутое занимает 0 по ширине
   (`width: 0` из home.css) и не мешает.

   [2026-08-22] Раскрытое состояние описано ТЕМ ЖЕ семейством селекторов, а не
   отдельным более слабым правилом — иначе базовое правило (2 ID) перебивало
   `.search-input-wrapper.expanded` (1 ID) и навязывало раскрытому полю
   `flex: 0 0 auto`, то есть ширину по содержимому. Поле переставало ужиматься и
   не влезало в остаток строки — на скрине PO оно снова стояло СТРОКОЙ НИЖЕ.
   Отдельно: jsdom этот конфликт разрешает НЕВЕРНО (отдал победу правилу с 1 ID),
   поэтому unit-проверка была зелёной на сломанной раскладке — геометрию строки
   проверяет e2e/dashboard-panel-layout.spec.js.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .homepage-actions-row > #frame-search-wrapper {
    order: 6;
    flex: 0 0 auto;
}

#dashboard
    .dash-tools-panel
    .dash-zone-projects
    .dash-zone-header
    > .homepage-actions-row
    > #frame-search-wrapper.expanded {
    /* Забирает весь остаток строки.

       [2026-08-22, найдено вторым ревью] `min-width: 0` ЗАМЕНЕН на 96px. С нулём
       поле ужималось до любой ширины, и при панели по умолчанию (260px) на него
       оставалось ~60px, из которых 40px съедал `padding-right: 2.5rem` — резерв
       под кнопку очистки (step-by-step-base.css). Видимого текста оставалось
       ~20px, а на узкой панели и при длинной подписи фильтра — ноль: набранное
       слово не было видно вообще, хотя фильтрация работала. Теперь поле либо
       читаемо, либо (когда строка совсем узкая) честно переносится на свою
       строку — вместо того чтобы притворяться полем шириной в два символа.
       Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    flex: 1 1 96px;
    width: auto;
    min-width: 96px;
}

/* [2026-08-22, найдено вторым ревью] Резерв под кнопку очистки в панели меньше,
   чем в полосе во всю ширину страницы: сама кнопка занимает 26px
   (иконка 18px + padding 2×4px, step-by-step-base.css) и стоит на `right: 8px`,
   поэтому 34px достаточно, а канонические 40px (`2.5rem`) в узкой панели
   отнимали у текста лишнее. Правило ограничено панелью — в step-by-step резерв
   не меняется.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .homepage-actions-row .search-input {
    padding-right: 34px;
}

/* Размер и вид кнопок берутся из дизайн-системы (`btn-secondary`, `btn-ghost`,
   `btn-xs` — DESIGN.md §Buttons, styles/components.css). Здесь остаётся только
   то, чего в каноне нет: иконка внутри малой кнопки и квадрат у иконочной. */
#dashboard .dash-tools-panel .homepage-actions-row .btn .material-icons {
    font-size: 16px !important;
    margin-right: var(--space-1) !important;
}

#dashboard .dash-tools-panel .homepage-actions-row .search-toggle-btn {
    width: 28px;
    padding: 0;
}

/* [2026-08-22, найдено вторым ревью] `!important` добавлен НАМЕРЕННО: правило
   выше (`… .homepage-actions-row .btn .material-icons`) имеет ровно ту же
   специфичность (1,4,0) и несёт `font-size: 16px !important`, поэтому без
   `!important` эти 18px были мертвы — иконки «+» и лупы рисовались 16px, и
   любая попытка подогнать здесь размер не давала эффекта вовсе. Обе кнопки
   несут классы `btn … search-toggle-btn` (index.html), то есть подпадают под
   оба селектора одновременно.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .homepage-actions-row .search-toggle-btn .material-icons {
    font-size: 18px !important;
    margin-right: 0 !important;
}

/* [2026-08-22] «Прозрачное меню фильтра» (PO, два скрина подряд).
 *
 * Что проверено по коду, чтобы не гадать: правило
 * `.searchable-select-dropdown` (styles/searchable-select.css) задаёт
 * `background-color: var(--bg-primary)`, токен объявлен и в светлой (`:root`),
 * и в тёмной (`[data-theme='dark']`) теме, атрибут темы ставится на
 * `document.documentElement` (styles/theme-switcher.js), а сам файл подключён
 * к index.html. Фон применяется — измерено computed-стилем на РЕАЛЬНОМ
 * SearchableSelect. То есть меню не полупрозрачное.
 *
 * Причин видимого дефекта две, и лечим обе:
 *
 * 1. МЕНЮ ОКАЗЫВАЛОСЬ ПОД СПИСКОМ. Шапка с фильтром и тело раздела — соседи;
 *    тело идёт позже по потоку и несёт собственный скроллер (`#frames-list`,
 *    `overflow-y: auto`), который браузер выносит в отдельный слой. Поднимаем
 *    ТОЧЕЧНО сам фильтр, а не всю шапку: `z-index` на шапке зажимал бы
 *    выпадающий список (его собственные 1000) в чужой контекст — эта попытка
 *    уже делалась и была отменена, см. аннотацию у `.dash-zone-header`.
 * 2. МЕНЮ СЛИВАЛОСЬ С ПАНЕЛЬЮ: `.dash-tools-panel` красится ТЕМ ЖЕ токеном
 *    `--bg-primary`, поэтому граница между меню и панелью не читалась, и
 *    строки под ним выглядели «просвечивающими». Даём меню цвет всплывающей
 *    поверхности и тень — так его край виден на любом фоне.
 *
 * Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
 * Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel #frames-filter-select {
    position: relative;
    z-index: 20;
}

#dashboard .dash-tools-panel #frames-filter-select .searchable-select-dropdown {
    background-color: var(--bg-secondary);
    box-shadow: var(--shadow-lg);
    /* [2026-08-23] Меню фильтра не должно наследовать узкую ширину триггера.
       Компонент раскрывает список в `left: 0; right: 0` (styles/searchable-select.css:88),
       то есть ровно по кнопке. В панели кнопка намеренно сжата
       (`max-width: 140px`, чтобы фильтр не съедал строку с Create и поиском),
       и по факту она ужимается до 77px по слову «Active» — замер в браузере.
       Из-за этого подпись «My Favorites» ломалась на две строки, а пункт
       вырастал с 37px до 58px. Ширину задаём по САМОЙ ДЛИННОЙ подписи
       (`max-content`), а не числом: подписи локализуются, и в русской локали
       («Избранные») ширина другая. Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
       Chat: dashboard-panel-collapse-resize-2026-08-20. */
    min-width: max-content;
}

/* [2026-08-23] Подписи пунктов фильтра — одной строкой. Перенос делал пункты
   разной высоты (58px против 37px) и рвал слово посередине.
   Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel #frames-filter-select .searchable-select-option {
    white-space: nowrap;
}

#dashboard .dash-tools-panel #frames-filter-select .searchable-select-trigger {
    min-height: 28px;
    height: 28px;
    padding: 0 var(--space-2);
    font-size: var(--font-size-xs);
}

#dashboard .dash-tools-panel #frames-filter-select .searchable-select-value {
    font-size: var(--font-size-xs);
}

#dashboard .dash-tools-panel #frames-filter-select .searchable-select-arrow {
    font-size: 16px;
}

#dashboard .dash-tools-panel .dash-zone-projects .dash-zone-header > .homepage-actions-row {
    padding: 0;
    align-items: center;
}

/* Свёрнутый раздел прячет и строку управления: у закрытого раздела нечем
   управлять, а фильтр без списка вводит в заблуждение.
   [2026-08-22] В селектор добавлен `.dash-tools-panel`, чтобы правило заведомо
   ПЕРЕБИВАЛО `display: contents` выше (иначе специфичность совпадала 1:1 и всё
   держалось лишь на порядке правил в файле — при перестановке блоков свёрнутый
   раздел молча показывал бы кнопки). `display: none` на контейнере прячет и
   детей, даже когда его собственная коробка убрана `contents`.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel .dash-panel-section.collapsed .dash-zone-header > #frames-filter-select,
#dashboard .dash-tools-panel .dash-panel-section.collapsed .dash-zone-header > .homepage-actions-row {
    display: none;
}

/* [2026-08-22, найдено вторым ревью] ДУБЛЬ-ПРАВИЛО УДАЛЕНО. Здесь стояла вторая,
   более слабая копия правил для раскрытого поля
   (`… .homepage-actions-row .search-input-wrapper.expanded`, 1 ID + 4 класса).
   В браузере она проигрывала основному правилу (2 ID + 5 классов, см. блок
   `#frame-search-wrapper.expanded` выше), но jsdom разрешает каскад ТОЛЬКО по
   порядку правил в файле (node_modules/jsdom/.../style-rules.js: «specificity is
   only implemented by the order in which the matching rules appear») и брал
   именно эту копию — последнюю. Из-за этого unit-проверка раскрытого поля
   зеленела даже тогда, когда в настоящем, побеждающем правиле стояло
   `flex: 0 0 100%` — то есть ровно тот дефект, на который PO присылал скрин
   повторно. Единственное правило убирает и расхождение, и ложную зелень.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */

/* [2026-08-20, по живому скрину] Строка проекта в узкой панели: горизонтального
   скролла быть не должно. Замер: содержимое списка 418px при видимых 217px —
   строка тянулась своей внутренней раскладкой из модалки выбора фрейма.
   Имя переносится, длинное слово рвётся, лишнее по горизонтали обрезается.
   Ref: docs/TZ_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §3. Chat: projects-to-left-panel-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects #frames-list {
    overflow-x: hidden;
}

/* [2026-08-22] Внутренний отступ строки ужат по вертикали (PO: «нужно уменьшить
   зазор между строками проектов, сейчас большой разрыв»). По горизонтали
   оставляем `--space-2`, чтобы текст не прилипал к краю панели.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .frame-row {
    min-width: 0;
    padding: var(--space-1) var(--space-2);
}

/* [2026-08-22, найдено ревью] Правило `flex-wrap: wrap` УДАЛЕНО как мёртвое, а
   его объяснение — как устаревшее. Оно описывало прежнюю раскладку, где блок
   действий был ПРЯМЫМ ребёнком `.frame-row` и четыре кнопки по 36px не влезали
   рядом с названием. С 2026-08-22 кнопки лежат внутри `.frame-row-content >
   .frame-row-info > .frame-row-title`, и у `.frame-row` остался ровно ОДИН
   ребёнок (`.frame-row-content`, `flex: 1 1 100%`) — переносить нечего.
   Заодно снят дубль селектора: тот же `.frame-row` объявлялся дважды подряд, и
   `padding` стоял только в одном — ровно то расщепление, от которого этот файл
   предостерегает выше. Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-content {
    flex: 1 1 100%;
    min-width: 0;
}

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-info {
    min-width: 0;
}

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-actions {
    flex: 0 0 auto;
    gap: var(--space-1);
}

/* [2026-08-23] Кнопки строки раскрываются НЕ ТОЛЬКО по наведению мыши, но и
   когда фокус пришёл с КЛАВИАТУРЫ.

   `activity-modal.css:2029` держит блок действий в `opacity: 0` и снимает гейт
   единственным правилом `.frame-row:hover`. Замерено в браузере: пользователь,
   дошедший до кнопки табом, получал `document.activeElement === кнопка` при
   `opacity: 0` — фокус на невидимом элементе. Это ровно тот дефект, ради
   которого заведён канон «тест проверяет ВИДИМОСТЬ, а не наличие в DOM»
   (CLAUDE.md, PO 2026-08-16).

   Правило добавлено в scope ЛЕВОЙ ПАНЕЛИ, а не в общий `activity-modal.css`:
   тот файл обслуживает центральную модалку выбора фрейма — чужой режим, и
   задача про панель не даёт права его править.
   Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md §1.3.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .frame-row:focus-within .frame-row-actions {
    opacity: 1;
}

/* [2026-08-22] Кнопки строки проекта — МАЛОГО размера (PO 2026-08-22, скрин:
   «кнопки по работе с проектом довольно крупные, надо уменьшить и привести к
   канону малых кнопок по дизайну»).

   Приехали из ЦЕНТРАЛЬНОЙ модалки выбора фрейма (`activity-modal.css`: 36×36,
   иконка 20px) — там строка широкая и такой размер уместен. В узкой панели такой
   размер раздувал высоту каждой записи.

   [2026-08-22, найдено ревью] Из объяснения убрана устаревшая посылка про «пять
   кнопок» и перенос строки: с 2026-08-22 кнопок в строке ДВЕ (правка и
   избранное), остальные действия переехали, а `flex-wrap` у строки удалён как
   мёртвый. Следующий, кто будет подбирать размер, рассуждал бы от раскладки,
   которой уже нет.

   Размер берём тот же, что у соседей по этой же панели — «Create» и лупа
   (28×28, иконка 18px, канон `.btn-xs`), чтобы в разделе не было двух шкал
   иконочных кнопок. Правило заскоуплено на панель: в центральной модалке
   прежний размер сохраняется.
   Ref: docs/QA_PROJECT_ROW_ACTIONS_2026-08-22.md §1.3.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-btn-icon {
    width: 28px;
    height: 28px;
}

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-btn-icon .material-icons {
    font-size: 18px;
}

/* [2026-08-20, поймано скриншотом] Перенос — `break-word`, НЕ `anywhere`.
   `anywhere` уменьшает минимальную ширину содержимого до ОДНОГО СИМВОЛА, и
   контейнер схлопывается: название «easykawa 2» встало столбиком по букве
   (высота списка при этом раздулась до 8606px). `break-word` рвёт только
   слово, которое реально не влезает, и на минимальную ширину не влияет.
   Ref: docs/TZ_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §3. Chat: projects-to-left-panel-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-name,
#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-owner {
    overflow-wrap: break-word;
}

/* [2026-08-20, по скрину PO «разные размеры шрифта»] Внутри панели действует ОДНА
   шкала — та же, что у заголовка панели и подписей ярлыков: 14px основной текст,
   12px вторичная подпись. Раздел «Проекты» приехал из центра страницы и принёс
   оттуда крупные размеры: заголовок 18px против 14px у «Tools», название проекта
   16px против 14px у ярлыка «Document» (замер на живой странице). В центре
   крупная шкала остаётся — там она уместна, поэтому правила ограничены панелью.
   Ref: docs/TZ_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §3. Chat: projects-to-left-panel-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects .dash-zone-title {
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-name {
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

#dashboard .dash-tools-panel > .dash-zone-projects .frame-row-owner {
    font-size: var(--font-size-xs);
    line-height: 1.4;
}

/* Фильтр и поле поиска — тем же кеглем, иначе строка управления спорит
   с заголовком раздела.
   [2026-08-22] `#create-frame-btn` УБРАН из этого правила: ID-селектор
   (`#dashboard … #create-frame-btn`, специфичность 2 ID + 2 класса) перебивал
   канон `.btn-xs` (font-size: var(--font-size-xs), components.css) навязывая
   кнопке `--font-size-sm` (14px вместо 12px) — правило писалось ДО перехода
   кнопки на канонические классы `btn-secondary btn-xs` в этой же сессии и не
   было убрано. PO: «кнопки не выровнены, все еще крупные» — именно этот
   конфликт специфичности держал текст кнопки крупнее канона `.btn-xs`, хотя
   высота/паддинг уже брались из canon. Размер кнопки теперь целиком из
   `.btn-xs`, без точечного override.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-tools-panel > .dash-zone-projects #frames-filter-select,
#dashboard .dash-tools-panel > .dash-zone-projects .search-input {
    font-size: var(--font-size-sm);
}

/* ===================================================================
   [2026-08-20] СВОРАЧИВАНИЕ РАЗДЕЛОВ И РАСТЯГИВАНИЕ КРАЯ ПАНЕЛИ
   PO 2026-08-20: «сделай разделы сворачиваемыми, а также чтобы край левой
   панели можно было растягивать, как у правой панели, все настройки с памятью».
   Поведение — modules/home/DashboardPanel.js, здесь только внешний вид.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md.
   Chat: dashboard-panel-collapse-resize-2026-08-20.
   =================================================================== */

/* Заголовок раздела — кликабельная строка: название слева, значок состояния
   справа. Значок — иконка набора, не символ-заменитель. */
#dashboard .dash-panel-section > [data-panel-section-header] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    user-select: none;
}

/* [2026-08-22] УДАЛЕНО правило «фильтр в шапке занимает свою строку»
   (`flex: 1 0 100%; order: 2`) — оно и было корнем жалобы PO «сделай в одну
   линию» (повторно 2026-08-22 со скрином): базис 100% приказывал фильтру
   занять ВСЮ ширину шапки, то есть отдельную строку, и кнопки физически не
   могли встать с ним в ряд. Правило писалось 2026-08-20, когда «Create» и
   поиск ещё стояли строкой ниже, внутри тела раздела, и фильтр в шапке был
   один. Раскладка строки контролов теперь задаётся выше по файлу
   (order 3/4/5/6 + `display: contents` у контейнера кнопок).
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */

#dashboard .dash-panel-section > [data-panel-section-header] .dash-section-caret {
    margin-left: auto;
    font-size: 20px;
    color: var(--text-tertiary);
    flex-shrink: 0;
}

#dashboard .dash-panel-section > [data-panel-section-header]:hover .dash-section-caret {
    color: var(--text-primary);
}

#dashboard .dash-panel-section > [data-panel-section-header]:focus-visible {
    outline: 2px solid var(--brand-primary);
    outline-offset: 2px;
}

/* Свёрнутый раздел не претендует на свободную высоту — её забирает открытый. */
#dashboard .dash-tools-panel > .dash-panel-section.collapsed,
#dashboard .dash-tools-panel .dash-panel-section.collapsed {
    flex: 0 0 auto;
}

/* Ручка растягивания на правом краю панели — механика и вид как у правой панели. */
/* [2026-08-22, найдено ревью] Ручка ЦЕЛИКОМ ВНУТРИ панели.
   Было `right: -3px; width: 6px` — половина ручки торчала наружу, но панель
   несёт `overflow: hidden` (dashboard.css, правило `.dash-tools-panel`) и сама
   же является содержащим блоком для абсолютной ручки. Наружные 3px просто
   отрезались: и подсветка, и попадание курсора оставались лишь на трёх
   пикселях вместо шести — по краю приходилось «целиться», особенно на HiDPI.
   Теперь ручка прижата к внутреннему краю и видна на всю свою ширину.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-panel-resize {
    position: absolute;
    top: 0;
    right: 0;
    width: 6px;
    height: 100%;
    cursor: ew-resize;
    background: transparent;
    z-index: 5;
}

/* [2026-08-22, найдено ревью] У свёрнутой панели ручка не должна ловить фокус.
   `opacity: 0` + `pointer-events: none` убирают её от мыши, но НЕ из порядка
   табуляции: ручка несёт `tabindex="0"` (DashboardPanel.js), и пользователь
   клавиатуры упирался в невидимый разделитель посреди страницы. `display: none`
   исключает её из обхода полностью. */
#dashboard .dash-tools-panel.collapsed .dash-panel-resize {
    display: none;
}

#dashboard .dash-panel-resize:hover,
#dashboard .dash-panel-resize:focus-visible,
.dash-panel-resizing #dashboard .dash-panel-resize {
    background: var(--brand-primary);
    opacity: 0.35;
    outline: none;
}

/* [2026-08-20] Свёрнутый раздел ОБЯЗАН убрать содержимое с экрана.
   Браузерное `[hidden] { display: none }` имеет нулевую специфичность, а у тела
   инструментов стоит `#dashboard .dash-tools-panel-content { display: flex }` —
   оно побеждало, и «Tools» помечался свёрнутым, оставаясь на экране (поймано PO:
   «tools не сворачивается»; живой замер: класс collapsed = true, hidden = true,
   высота тела 186px).

   [2026-08-22, найдено вторым ревью] ПРЕЖНИЙ КОММЕНТАРИЙ ЗДЕСЬ ВРАЛ: он
   утверждал, что правило ниже «сильнее по специфичности». Это неверно —
   `#dashboard .dash-panel-section [data-panel-section-body][hidden]` весит
   (1,3,0) РОВНО СТОЛЬКО ЖЕ, сколько `#dashboard .dash-tools-panel
   .dash-panel-section > [data-panel-section-body]` выше по файлу. Побеждает оно
   исключительно потому, что стоит НИЖЕ. Опасность не теоретическая: любая
   перестановка блоков (или вынос «сворачивания» в отдельный файл, подключаемый
   раньше) молча вернёт баг «tools не сворачивается», а комментарий убеждал, что
   так делать безопасно. Поэтому зависимость от порядка снята явно: `!important`
   ставит исход вне зависимости от места правила в файле.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md §4ter.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
#dashboard .dash-panel-section [data-panel-section-body][hidden] {
    display: none !important;
}

/* [2026-08-20] Пока тянут край — ширина без плавного перехода: у панели стоит
   `transition: width/min-width 0.3s`, и при перетаскивании она отставала от
   курсора.
   Ref: docs/QA_PROJECTS_TO_LEFT_PANEL_2026-08-20.md.
   Chat: dashboard-panel-collapse-resize-2026-08-20. */
.dash-panel-resizing #dashboard .dash-tools-panel {
    transition: none;
}

/* Пока тянут — не выделять текст и не ловить наведение содержимым. */
.dash-panel-resizing,
.dash-panel-resizing * {
    user-select: none !important;
}

/* Заголовок панели («Инструменты») — такой же кликабельный, как остальные. */
#dashboard .dash-panel-section > .dash-tools-panel-header {
    padding-right: 16px;
}
