/* Override themes.css body padding for fish module */
body {
    padding: 0 !important;
    margin: 0;
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: var(--font-family);
}

/* [2026-08-16] МЕСТО ПОД НИЖНЮЮ ПАНЕЛЬ-ХЛЕБНЫЕ-КРОШКИ.
   Дефект: правая панель обрезалась нижним баннером. Причина видна прямо здесь, в двух
   строках выше:
     1. `padding: 0 !important` глушит канонический резерв
        `body.has-bottom-action-bar { padding-bottom: 70px }` (styles/bottom-action-bar.css:243),
        который ставит сам компонент баннера (components/BreadcrumbPath.js:94);
     2. `height: 100vh` + `overflow: hidden` — страница не прокручивается, поэтому нижняя
        полоса раскладки просто оказывается ПОД панелью (`position: fixed; bottom: 0;
        z-index: 1000`), а правая панель тянется на всю высоту холста и режется.
   Решение — ровно то же, что уже применено в модуле Documents для той же жалобы PO:
   вычитаем ФАКТИЧЕСКУЮ высоту панели, которую она публикует сама
   (BreadcrumbPath._publishHeight → `--bottom-bar-height`), а не подгоняем магическое число.
   Сравнить: modules/documents/css/documents.css:1159-1161 и
   modules/documents/css/pdf-documents.css:33-35.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §J. Chat: fish-icons-styles-audit-2026-08-16. */
body.has-bottom-action-bar {
    height: calc(100vh - var(--bottom-bar-height, 44px));
}

/* Инвентарь скрывает нижнюю панель целиком. Её резерв нужен обычной сцене,
   но не открытому игровому экрану: иначе под каталогом остаётся пустая полоса. */
body.has-bottom-action-bar.fish3d-inventory-open {
    height: 100vh;
}

/* Canvas container */
/* [2026-08-16] Снята `box-shadow` с холста. Холст — РАЗДЕЛ ЛЭЙАУТА, а железное правило PO
   от 2026-08-16 (DESIGN.md §«Лэйаут страницы», п.1) прямо запрещает разделам рамку,
   скругление, тень и собственный фон-коробку: разделы разделяются заголовком, воздухом и
   максимум одной линией. Тень давала серую полосу-обод под лентой вкладок; в тёмной теме её
   и так гасили отдельным правилом — то есть оформление уже признавали лишним.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §I. Chat: fish-icons-styles-audit-2026-08-16. */
#canvasContainer {
    background-color: var(--bg-primary);
}

/* [2026-10-04] Правила холста схемы (#diagramCanvas) сняты: холст ушёл в Slides вместе со вкладкой
   «Схема». Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* Modal container large variant for diagrams modal */
.modal-container-lg {
    max-width: 900px;
}

/* [2026-10-04] Правила собственного списка диаграмм (строка, плитка, действия строки) сняты как
   мёртвые: с 0cf63fbd7 окно «Открыть» рисует общий ActivityDocumentBrowser модуля Documents, и
   узлов этих классов в fish.html нет. Ref: js/__tests__/fishDeadCode.guard.test.js.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */

.empty-state {
    text-align: center;
    padding: var(--space-8) 0;
}

.empty-state-icon {
    font-size: 3rem;
    color: var(--text-tertiary);
    margin-bottom: var(--space-2);
}

.empty-state-text {
    color: var(--text-secondary);
}

.error-state {
    text-align: center;
    padding: var(--space-8) 0;
}

/* [2026-08-16] Токена --danger в проекте НЕТ (проверено по styles/themes.css) — правило
   было невалидным, и иконка с текстом ошибки наследовали обычный цвет вместо красного.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §B1. Chat: fish-icons-styles-audit-2026-08-16. */
.error-state-icon {
    font-size: 3rem;
    color: var(--color-error-text);
    margin-bottom: var(--space-2);
}

.error-state-text {
    color: var(--color-error-text);
}

.error-state-detail {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
    margin-top: var(--space-2);
}

/* [2026-10-04] Сняты правила холста схемы (кости, точки, рамка выделения, режим рисования) и плавающей
   панели трансформации (отражение, поворот, масштаб): они ушли в Slides вместе со вкладкой «Схема».
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* ======================= WIDTH EDITOR PANEL ======================= */

/* [2026-08-16] УДАЛЕНЫ правила `#widthEditorPanel` и `#widthEditorPanel.hidden`: такого
   элемента нет ни в fish.html, ни в JS — js/elements.js его не кэширует, поэтому
   `elements.widthEditorPanel` всегда undefined. Редактор ширины давно живёт секцией
   Properties правой панели (.width-editor-content). CSS был мёртвым.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §D1. Chat: fish-icons-styles-audit-2026-08-16. */

/* [2026-08-16] УДАЛЕНЫ правила плавающей шапки редактора ширины: .width-editor-header,
   .width-editor-drag, .width-editor-title, .width-editor-save-btn, .width-editor-close-btn.
   Ни один из этих классов не встречается в разметке и в JS-генерации — плавающая панель
   заменена секцией Properties правой панели. Обработчики перетаскивания в js/floatingPanel.js
   (317, 387) остались, но их querySelector('.width-editor-header') не находит элемента и
   выходит по guard'у — это отдельный дефект «мёртвый JS», зафиксирован в аудите.
   Оставлены живые: .width-editor-content, .width-editor-controls-row, .width-editor-chart-container.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §D2. Chat: fish-icons-styles-audit-2026-08-16. */

.width-editor-content {
    /* No padding - parent .sidebar-section-body already has padding */
    overflow-y: auto;
    overflow-x: hidden;
    flex: 1;
}

/* [2026-10-04] Сняты правила профиля ширины «Свойств» (поля, кривая, ячейки ширины): профиль ушёл в Slides
   вместе со вкладкой «Схема». Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* [2026-10-04] Сняты правила поповера кости, кнопок «сетка / центрировать», контекстных меню холста,
   резиновой линии и маркера первого клика, графика асимметрии и пометки «разные значения» профиля:
   всё это — инструменты вкладки «Схема», ушедшей в Slides.
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* ======================= RIGHT SIDEBAR PANEL ======================= */

/* Main container for sidebar management */
.fish-main-container {
    /* [2026-10-03] Ширина правой панели по умолчанию; ручка у её кромки (rightSidebar.js) пишет
       сюда же выбранное значение. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
       Chat: fish-model-composition-sidebar-section-2026-10-02. */
    --fish-right-sidebar-width: 340px;
    position: relative;
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

/* `#fishModelComposition` is a sibling of `#fish3dHud`: it stays outside the HUD wrapper so
   the full-screen inventory can hide it independently. That also meant F1 hid the wrapper and
   the editor sidebar but left this one HUD panel in the supposedly clean world. Keep the panel's
   ownership explicit at the scene-shell boundary; the second F1 removes this class and restores
   its native open/closed state without rebuilding it. */
.fish-main-container.fish3d-ui-hidden #fishModelComposition,
.fish-main-container.fish3d-ui-hidden #fish3dTwoDimensionalOnlyNotice {
    display: none;
}

/* F1 — именно чистый игровой кадр. Шапка, файловая панель, вкладки и контекст
   чертежа являются siblings `#fish-main-container`, поэтому одного скрытия HUD
   или правого инспектора недостаточно: до этой двери человек по-прежнему видел
   офисный редактор над миром. Состояние ставится только в 3D через Fish3DUi и
   повторным F1 снимается без перестройки страницы. */
body.fish3d-ui-hidden > header,
body.fish3d-ui-hidden > .module-controls-row.fish-toolbar,
body.fish3d-ui-hidden > #tabsBar,
body.fish3d-ui-hidden > #breadcrumb-bar {
    display: none !important;
}

/* Right sidebar panel */
/* [2026-08-16] Фон панели приведён к канону Word. Замер обеих страниц (1500×950) по
   вопросу PO «правая панель соответствует другим панелям Word и PDF по дизайну и стилям?»:
   у `.editor-sidebar` (modules/documents/css/sidebar.css:6) тело БЕЛОЕ (--bg-primary), а серый
   только заголовок секции; у Fish было наоборот — тело серое (--bg-secondary), а заголовок
   ещё темнее (--bg-tertiary). Слои были перепутаны, из-за чего панель читалась «тяжелее»
   словной. Ref: docs/QA_FISH_RIGHT_PANEL_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16. */
.right-sidebar {
    position: absolute;
    top: 0;
    right: 0;
    /* [2026-10-03] Ширину задаёт ручка у левой кромки (#fishRightSidebarResize, rightSidebar.js),
       по умолчанию прежние 340px. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
       Chat: fish-model-composition-sidebar-section-2026-10-02. */
    width: var(--fish-right-sidebar-width, 340px);
    background-color: var(--bg-primary);
    border-left: 1px solid var(--border-primary);
    z-index: 50;
    display: flex;
    flex-direction: column;
    overflow: hidden; /* No scroll on sidebar itself - sections handle their own scrolling */
    transition:
        transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
        opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
    /* Height set dynamically by JS to match canvas height */
}

.fish-main-container.fish-right-sidebar-resizing .right-sidebar {
    transition: none;
}

/* Collapsed state */
.fish-main-container.right-sidebar-collapsed .right-sidebar {
    transform: translateX(100%);
    opacity: 0;
    pointer-events: none;
}

/* Sidebar section */
.sidebar-section {
    border-bottom: 1px solid var(--border-primary);
    flex-shrink: 0;
}

.sidebar-section:last-child {
    border-bottom: none;
}

/* Sidebar section header (button) */
/* [2026-08-16] Фон заголовка — `--bg-secondary`, как у `.sidebar-panel-header` Word
   (sidebar.css:46). Было `--bg-tertiary` — на тон темнее канона.
   Ref: docs/QA_FISH_RIGHT_PANEL_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16. */
.sidebar-section-header {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    background-color: var(--bg-secondary);
    border: none;
    cursor: pointer;
    transition: background-color var(--transition-base);
}

.sidebar-section-header:hover {
    background-color: var(--bg-hover);
}

/* [2026-08-16] Заголовок секции — типографика панели Word. Замер обеих страниц по замечанию
   PO «не выглядит как модуль Word»: у Fish заголовок был 16 px обычным регистром цветом
   --text-primary, а `.sidebar-panel-header` в modules/documents/css/sidebar.css:36-48 —
   12 px, ПРОПИСНЫМИ, с разрядкой 0.5px и цветом --text-secondary. Отступы (12px 16px) и фон
   у Fish уже совпадали, расходилась именно надпись.
   Ref: docs/QA_FISH_TO_WORD_ICONS_2026-08-16.md §6. Chat: fish-icons-styles-audit-2026-08-16. */
.sidebar-section-title {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
}

/* Строка заголовка: переключатель секции + иконочное действие справа (канон «Pages» в Word). */
.sidebar-section-headline {
    display: flex;
    align-items: center;
    background-color: var(--bg-secondary);
}

.sidebar-section-headline .sidebar-section-header {
    flex: 1;
    min-width: 0;
    background-color: transparent;
}

/* [2026-10-02] СТРЕЛКА СВОРАЧИВАНИЯ — ВСЕГДА В ОДНОЙ КОЛОНКЕ У ПРАВОГО КРАЯ. Действие раздела
   («+» у Layers, «i» у Bill of materials) стояло ПРАВЕЕ стрелки, и стрелки разделов с действием
   уезжали влево — зигзаг по колонке (снимок и замечание PO: «кнопка сворачивания всегда справа,
   она статична, а остальные кнопки слева от неё»). Заголовок-переключатель занимает всю строку,
   как у разделов без действий, поэтому стрелка стоит ровно там же; действие ложится поверх
   строки слева от стрелки, а заголовок резервирует под него место справа.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
.sidebar-section-headline {
    position: relative;
}
/* Место под действие резервирует ПОДПИСЬ, а не кнопка-заголовок: отступ на кнопке сдвигал
   стрелку влево (замер в окне: 1442 px против 1502 px у разделов без действия). */
.sidebar-section-headline .sidebar-section-title {
    min-width: 0;
    margin-inline-end: calc(var(--inspector-control-height) + var(--space-2) * 2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sidebar-section-headline .fish-sidebar-btn {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: calc(var(--space-4) + 20px + var(--space-2));
    margin: 0;
    transform: translateY(-50%);
}

/* Section icon actions share the 34×34/r8 panel target and centered 20px glyph. */
.fish-sidebar-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    min-width: 34px;
    min-height: 34px;
    box-sizing: border-box;
    padding: 0;
    margin-right: var(--space-3);
    border: 1px solid transparent;
    background: transparent;
    border-radius: var(--radius-lg);
    cursor: pointer;
    color: var(--text-secondary);
    transition:
        background-color var(--transition-fast),
        color var(--transition-fast);
}

.fish-sidebar-btn svg {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
}

.fish-sidebar-btn:hover:not(:disabled) {
    background: var(--bg-hover);
    color: var(--text-primary);
}

/* [2026-10-02] «i» Properties — уведомление о недостающем у выбранного элемента: цвет
   предупреждения; без недостающего кнопки нет. Правила стоят ПОСЛЕ канона `.fish-sidebar-btn`,
   иначе его display:flex и цвет вторичного текста перебивали их.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §35. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-sidebar-btn[hidden] {
    display: none;
}
.fish-sidebar-btn.fish-sidebar-notice,
.fish-sidebar-btn.fish-sidebar-notice:hover:not(:disabled) {
    color: var(--color-warning-text);
}

.fish-sidebar-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.sidebar-section-icon {
    width: 20px;
    height: 20px;
    color: var(--text-secondary);
    transition: transform var(--transition-base);
}

/* Rotate icon when section is open */
.sidebar-section.active .sidebar-section-icon {
    transform: rotate(180deg);
}

/* Sidebar section content */
.sidebar-section-content {
    max-height: 0;
    overflow: hidden;
}

.sidebar-section.active .sidebar-section-content {
    max-height: var(--sidebar-content-max-height, 2000px);
    height: var(--sidebar-content-max-height, 2000px);
    display: flex;
    flex-direction: column;
}

/* [2026-08-16] Отступ тела — `--space-2` (8px), как `.sidebar-panel-content` Word
   (sidebar.css:71). Было 16px: содержимое панели стояло вдвое дальше от краёв, чем в
   эталоне. Ref: docs/QA_FISH_RIGHT_PANEL_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16. */
.sidebar-section-body {
    padding: var(--space-2);
    overflow-y: auto;
    overflow-x: hidden;
    flex: 1;
    min-height: 0;
}

/* Custom scrollbar for section bodies */
.sidebar-section-body.custom-scrollbar {
    scrollbar-width: thin;
    scrollbar-color: var(--border-secondary) transparent;
}

.sidebar-section-body.custom-scrollbar::-webkit-scrollbar {
    width: 6px;
}

.sidebar-section-body.custom-scrollbar::-webkit-scrollbar-track {
    background: transparent;
}

.sidebar-section-body.custom-scrollbar::-webkit-scrollbar-thumb {
    background-color: var(--border-secondary);
    border-radius: 3px;
}

.sidebar-section-body.custom-scrollbar::-webkit-scrollbar-thumb:hover {
    background-color: var(--border-primary);
}

/* ======================= MOBILE RESPONSIVE STYLES ======================= */

/* Media query for mobile devices (screens < 768px) */
@media (max-width: 767px) {
    /* [2026-08-16] Мобильное правило #widthEditorPanel удалено вместе с базовым: элемента
       не существует. Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §D1.
       Chat: fish-icons-styles-audit-2026-08-16. */

    /* [2026-10-04] Мобильные правила плавающей панели, профиля ширины и кнопок холста сняты вместе с
       самими элементами «Схемы» (ушли в Slides). Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3.
       Chat: fish-model-composition-sidebar-section-2026-10-02. */

    /* Modal container - reduce max-width on mobile */
    .modal-container-lg {
        max-width: calc(100vw - 32px);
        margin: 16px;
    }

    /* [2026-10-04] Правило действий строки собственного списка диаграмм снято вместе со списком
       (окно «Открыть» — общий браузер Documents). Ref: js/__tests__/fishDeadCode.guard.test.js. */
}

/* Media query for very small screens (< 480px, like iPhone SE) */
@media (max-width: 479px) {
    /* [2026-08-16] Правило #widthEditorPanel удалено — элемента не существует.
       Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §D1. Chat: fish-icons-styles-audit-2026-08-16. */

    /* [2026-10-04] Правила плавающей панели и кнопок холста сняты вместе с элементами «Схемы».
       Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
    .modal-container-lg {
        max-width: calc(100vw - 16px);
        margin: 8px;
    }
}

/* ============================================
   LAYERS UI STYLES
   ============================================ */

/* Layers list container */
.layers-list {
    padding: var(--space-2);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Individual layer item */
.layer-item {
    background-color: var(--bg-tertiary);
    border: 1px solid var(--border-primary);
    border-radius: var(--radius-md);
    padding: var(--space-2) var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-2);
    transition:
        background-color 0.2s ease,
        border-color 0.2s ease;
    overflow: hidden; /* Prevent content from overflowing */
}

.layer-item:hover {
    background-color: var(--bg-secondary);
    border-color: var(--border-secondary);
}

/* Активный слой выделяется всей поверхностью без цветного края или внешнего ореола. */
.layer-item.active {
    border-color: var(--border-primary);
    background-color: var(--brand-primary-bg);
    box-shadow: none;
}

/* Layer name (editable) */
.layer-name {
    flex: 1;
    min-width: 0; /* Allow shrinking */
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--text-primary);
    background: transparent;
    border: none;
    outline: none;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    cursor: text;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* [2026-08-16] Токена --accent-primary в проекте НЕТ — правило было невалидным и рамка
   фокуса у поля имени слоя не появлялась вовсе. Канон фокуса — --brand-primary (DESIGN.md §4).
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §B2. Chat: fish-icons-styles-audit-2026-08-16. */
.layer-name:focus {
    background-color: var(--bg-primary);
    border: 1px solid var(--brand-primary);
}

/* System layer (Default Layer) - non-editable */
.layer-name.system {
    cursor: default;
    font-weight: 600;
    color: var(--text-secondary);
}

.layer-name.system:focus {
    background-color: transparent;
    border: none;
}

/* Layer control buttons */
.layer-controls {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-shrink: 0; /* Prevent shrinking */
}

.layer-control-btn {
    background: transparent;
    border: none;
    padding: 4px; /* Smaller padding for compact layout */
    cursor: pointer;
    color: var(--text-tertiary);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    transition:
        background-color 0.2s ease,
        color 0.2s ease;
    flex-shrink: 0; /* Prevent shrinking */
}

.layer-control-btn:hover {
    background-color: var(--bg-primary);
    color: var(--text-primary);
}

/* [2026-08-16] Значок кнопки слоя — контурный SVG набора модуля. Размер остаётся в CSS,
   потому что зависит от состояния (активный слой — крупнее, правило ниже).
   Ref: docs/DEV_GUIDE_FISH_TO_WORD_CONTRACT_2026-08-16.md §3 шаг 5.
   Chat: fish-icons-styles-audit-2026-08-16. */
.layer-control-btn svg {
    width: 16px;
    height: 16px;
}

/* Active button state */
/* [2026-08-16] Хардкод #10b981 → токены успеха (тема).
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §C1. Chat: fish-icons-styles-audit-2026-08-16. */
/* [2026-08-16] Зелёный → фирменный: состояние «включено» в панелях Word/PDF показывается
   тонированной фирменной подложкой (`.toolbar-btn.active`), а зелёный в системе значит «успех».
   Ref: docs/QA_FISH_TO_WORD_ICONS_2026-08-16.md §6. Chat: fish-icons-styles-audit-2026-08-16. */
.layer-control-btn.active {
    color: var(--brand-primary-text);
    background-color: rgba(var(--brand-primary-rgb), 0.12);
}

/* [2026-08-16] `font-weight: 700` УДАЛЁН — у контурного SVG нет насыщенности шрифта, правило
   было бы мёртвым. Выделение активного слоя даёт цвет и подложка кнопки (правило выше).
   Ref: docs/DEV_GUIDE_FISH_TO_WORD_CONTRACT_2026-08-16.md §3 шаг 3, шаг 5. */
.layer-control-btn.active svg {
    width: 18px;
    height: 18px;
}

.layer-control-btn.active:hover {
    background-color: rgba(var(--brand-primary-rgb), 0.2);
}

/* Hidden state button */
/* [2026-08-16] КРИТИЧНО: состояние переименовано `hidden` → `is-hidden`. Общий утилитарный
   класс `.hidden` объявлен в styles/styles.css:518 как `display: none !important`, поэтому
   кнопка-глаз скрытого слоя ПРОПАДАЛА с экрана — вернуть слою видимость этой кнопкой было
   нельзя. Правило по цвету перебить `!important` не могло. Имя состояния должно быть своим,
   как `.active`/`.locked` рядом. Регрессия закрыта тестом на ВИДИМОСТЬ по реальному каскаду.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §A5. Chat: fish-icons-styles-audit-2026-08-16. */
.layer-control-btn.is-hidden {
    color: var(--text-disabled);
}

/* Locked state button */
/* [2026-08-16] Токена --warning-primary в проекте НЕТ — состояние «замок» не окрашивалось.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §B3. Chat: fish-icons-styles-audit-2026-08-16. */
.layer-control-btn.locked {
    color: var(--color-warning-text);
}

/* Delete button */
/* [2026-08-16] Токенов --danger-primary/--danger-bg в проекте НЕТ — кнопка удаления слоя
   не была красной и не подсвечивалась на hover.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §B4. Chat: fish-icons-styles-audit-2026-08-16. */
.layer-control-btn.delete {
    color: var(--color-error-text);
}

.layer-control-btn.delete:hover {
    background-color: var(--color-error-bg);
}

/* System layer - hide delete button */
.layer-item.system .layer-control-btn.delete {
    display: none;
}

/* Layer bone count badge */
.layer-bone-count {
    font-size: var(--font-size-xs);
    color: var(--text-tertiary);
    background-color: var(--bg-secondary);
    padding: 2px 6px;
    border-radius: var(--radius-full);
    min-width: 20px;
    text-align: center;
    flex-shrink: 0; /* Prevent shrinking */
}

/* ── Виды Fish: 3D (three.js) и 2D-заглушка ── */
#fish3dRoot,
#fish2dRoot {
    position: absolute;
    inset: 0;
    overflow: hidden;
}
#fish3dRoot canvas {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    width: var(--fish3d-playable-width, 100%);
    height: 100%;
}
.fish3d-loading {
    position: absolute;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    /* [2026-10-25] Цвет — токен сцены, а не оболочки: `--text-primary` в светлой теме тёмный, и «Подготовка 3D-сцены…»
       терялась на тёмной подложке (живой прогон 2026-10-25, снимок «занято, свет, 1440»). Поверхности сцены тёмные
       в обеих темах (ТЗ TZ_FISH_3D_MINECRAFT_UX §22.1). Chat: перенос-чата-на-HP-2026-10-24. */
    color: var(--fish3d-hud-text, #e5e7eb);
    background: rgba(10, 17, 27, 0.94);
    font-size: 14px;
    pointer-events: auto;
}
.fish3d-loading.hidden {
    display: none;
}
.fish3d-loading-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid rgba(255, 255, 255, 0.28);
    border-top-color: currentColor;
    border-radius: 50%;
    animation: fish3d-loading-spin 0.8s linear infinite;
}
@keyframes fish3d-loading-spin {
    to {
        transform: rotate(360deg);
    }
}
@media (prefers-reduced-motion: reduce) {
    .fish3d-loading-spinner {
        animation: none;
    }
}
/* Причина пустого мира относится к HUD, но не блокирует ни камеру, ни постановку:
   legacy Fishbone-элемент остаётся доступен в «Схеме», а 3D-компонент можно
   поставить обычным инструментом. */
.fish3d-model-notice {
    position: absolute;
    top: 8px;
    left: 12px;
    z-index: 6;
    pointer-events: none;
    max-width: min(460px, calc(100% - 24px));
    margin: 0;
    padding: 8px 12px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    font-size: 12px;
    line-height: 1.35;
}
/* 08.09.2026, TZ Fish §12.18: local composition, beside the live model. */
.fish-model-composition {
    /* В коротком окне прежние `top: 125px` и `max-height: calc(100% - 235px)`
       давали нулевую высоту: остаётся 2px рамки, а колесо попадает в сцену. Положение
       панели и запас снизу теперь рассчитываются от ФАКТИЧЕСКОЙ высоты 3D-области.
       На обычном desktop это те же 125px / 110px, на низком — видны summary и
       прокручиваемое содержимое, не перекрывая нижнюю навигацию. */
    /* `Fish3DUi` измеряет реальную высоту cue-слоя: в Edit она может вырасти из-за
       имени выбранного компонента или перевода. Фолбэк сохраняет безопасную геометрию
       до первого измерения и в средах без ResizeObserver. */
    --fish-model-composition-bottom: min(100%, max(min(110px, 25%), var(--fish3d-model-composition-bottom, 0px)));
    /* F3 grows with translated labels and catalog names. Its measured lower edge is
       supplied only while the card is visible; the normal 125px anchor then returns. */
    --fish-model-composition-top: clamp(8px, max(125px, var(--fish3d-debug-bottom, 0px)), calc(100% - 104px));
    position: absolute;
    top: var(--fish-model-composition-top);
    left: 12px;
    /* Панель состава — интерактивный HUD. Холст WebGL не имеет права лежать над её кнопками:
       иначе строка выглядит доступной, но клик всегда ловит сцена. */
    z-index: 6;
    pointer-events: auto;
    max-width: min(460px, calc(100% - 24px));
    max-height: calc(100% - var(--fish-model-composition-top) - var(--fish-model-composition-bottom));
    overflow: auto;
    /* [2026-09-22] §22.1 «Тёмный HUD в обеих темах»: панель состава лежит ПОВЕРХ сцены, значит
       она HUD и берёт его токены. Живая проверка 2026-09-22 в открытом окне: при светлой теме
       она становилась белой (измерено rgb(255,255,255)) рядом с тёмной панелью сцены.
       Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. */
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    font-size: 12px;
}
/* A short desktop scene cannot fit a 125px top inset, the live action cue,
   and even the disclosure summary. When opened, let the list occupy the scene
   like a game inventory; it closes again before camera focus or precise editing. */
@media (max-height: 650px) {
    .fish-model-composition[open] {
        top: 8px;
        width: calc(100% - 24px);
        max-width: min(960px, calc(100% - 24px));
        max-height: calc(100% - 16px);
        background: var(--fish3d-hud-control-bg);
    }

    /* [2026-10-03] 340 → переменная ширины панели (тянется за край). Chat: fish-model-composition-sidebar-section-2026-10-02. */
    .fish-main-container:not(.right-sidebar-collapsed) .fish-model-composition[open] {
        width: calc(100% - var(--fish-right-sidebar-width, 340px) - 24px);
        max-width: calc(100% - var(--fish-right-sidebar-width, 340px) - 24px);
    }

    .fish-model-composition[open] > summary {
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--fish3d-hud-control-bg);
    }

    .fish-model-composition[open] table {
        min-width: 820px;
    }
}
@media (max-width: 1100px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish-model-composition {
        /* [2026-10-03] 340 → переменная ширины панели. Chat: fish-model-composition-sidebar-section-2026-10-02. */
        max-width: min(460px, calc(100% - var(--fish-right-sidebar-width, 340px) - 24px));
    }
}
/* The shared max-height reserves the full action cue below a fixed 125px top inset.
   In a short scene that can leave only a few pixels for the closed disclosure.
   Move just its summary into the measured gap and let its full hit target render. */
.fish-model-composition:not([open]) {
    top: max(8px, min(var(--fish-model-composition-top), calc(100% - var(--fish-model-composition-bottom) - 48px)));
    max-height: none;
    overflow: visible;
}
.fish-model-composition > summary {
    box-sizing: border-box;
    min-height: 44px;
    padding: 10px 14px;
    cursor: pointer;
}
.fish-model-composition-content {
    padding: 0 12px 12px;
}
.fish-model-composition table {
    width: 100%;
    border-collapse: collapse;
}
.fish-model-composition th,
.fish-model-composition td {
    padding: 6px;
    border-bottom: 1px solid var(--border-primary);
    text-align: left;
    vertical-align: top;
}
.fish-model-composition small {
    display: block;
    overflow-wrap: anywhere;
}
.fish-model-composition [data-model-composition-instance] {
    box-sizing: border-box;
    min-height: 40px;
    margin: 3px 4px 3px 0;
    padding: 6px 10px;
    border: 1px solid color-mix(in srgb, var(--fish3d-hud-text) 40%, transparent);
    border-radius: 5px;
    background: color-mix(in srgb, var(--fish3d-hud-control-bg) 78%, #000);
    color: var(--fish3d-hud-text);
    font: inherit;
    font-weight: 600;
    line-height: 1.25;
    cursor: pointer;
}
.fish-model-composition [data-model-composition-instance]:hover {
    border-color: var(--fish3d-hud-accent);
    background: color-mix(in srgb, var(--fish3d-hud-control-bg) 88%, var(--text-inverse));
}
.fish-model-composition [data-model-composition-instance]:focus-visible {
    border-color: var(--border-hover);
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
.fish-model-composition [data-model-composition-instance].is-selected {
    border-color: var(--fish3d-selection-color, #f6c453);
    background: color-mix(in srgb, var(--fish3d-hud-control-bg) 86%, var(--fish3d-selection-color, #f6c453));
    /* Выбранная строка — твёрдая рамка, как активный слот Minecraft, а не свечение.
       Она остаётся заметной рядом с оранжевым контуром меша и не добавляет тень HUD. */
    outline: 2px solid var(--fish3d-selection-color, #f6c453);
    outline-offset: -2px;
}
/* Выбор экземпляра сохраняет свою игровую поверхность и рамку.
   Клавиатурный фокус — общий нейтральный внутренний контур без свечения.
   Ref: DESIGN.md; docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. */
.fish-model-composition [data-model-composition-instance].is-selected:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
/* [2026-10-02] «Состав модели» — собственный раздел правой панели (#fish3dCompositionSection),
   а не коробка в конце Properties. Раздел есть только в 3D. Ведомость внутри — тело раздела:
   без рамки, скругления и своего фона (DESIGN.md «разделы не оборачивать в боксы»), её summary
   скрыт — раскрытием владеет заголовок раздела. Прокручивается `.sidebar-section-body`.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish-main-container:not(.fish3d-active) #fish3dCompositionSection {
    display: none;
}
#fish3dCompositionMount .fish-model-composition,
#fish3dCompositionMount .fish-model-composition[open],
#fish-main-container:not(.right-sidebar-collapsed) #fish3dCompositionMount .fish-model-composition[open] {
    position: static;
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    max-height: none;
    overflow: visible;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text-primary);
    font-size: var(--font-size-sm);
}
#fish3dCompositionMount .fish-model-composition > summary,
#fish3dCompositionMount .fish-model-composition[open] > summary {
    display: none;
}
#fish3dCompositionMount .fish-model-composition-content {
    padding: 0;
    overflow-wrap: anywhere;
}
#fish3dCompositionMount .fish-model-composition-content > p {
    margin: 0 0 var(--space-2);
}
/* [2026-10-02] Подпись таблицы стояла в столбик по букве: у таблицы `display: block`, а
   `caption` оставался `table-caption` и сжимался до ширины одной буквы.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
/* [2026-10-02] Подпись таблицы на экране не показываем: раздел уже назван заголовком, повтор
   (замечание PO: «ненужная подпись, раздел уже назван, надо удалить»). Имя таблицы для
   скринридера остаётся — подпись скрыта визуально тем же приёмом, что и строка заголовков.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition caption {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
/* [2026-10-03] СПЕЦИФИКАЦИЯ — ТАБЛИЦА В ОДНУ СТРОКУ БЕЗ ГРАНИЦ (приказ PO со снимком: «описание
   элементов надо сделать в одну строку и табличный вид без границ, как у изометрических чертежей
   или у ведомостей материалов»). Прежде каждая позиция раскладывалась столбиком «подпись: значение»
   (таблица в display:block, шапка скрыта). Теперь — настоящая таблица: видимая шапка колонок,
   одна строка на позицию, ни рамок, ни линий между строками; ряды разделяет только воздух.
   Наименование забирает остаток ширины и обрезается многоточием (полный текст — тултип ячейки),
   числа выровнены вправо табличными цифрами, значки выбора — последняя колонка. Узкая панель —
   горизонтальная прокрутка таблицы; панель теперь тянется за край (rightSidebar.js).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition-content {
    overflow-x: auto;
}
#fish3dCompositionMount .fish-model-composition table {
    width: 100%;
    margin: 0 0 var(--space-2);
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}
/* [2026-10-03] КАНОН СТИЛЯ ИСИКАВЫ (замечание PO со снимком: «не соответствует канону стиля
   исикава»; разбор навыком critique-brand-consistency против правой панели модуля и DESIGN.md):
   — ячейки: текст тела панели как у строки слоя (`.layer-name`): --font-size-sm, вес medium,
     --text-primary, обычный регистр; отступы только токенами --space-*;
   — шапка колонок: микро-подпись как заголовок раздела панели (`.sidebar-section-title`):
     --font-size-xs, semibold, прописные, разрядка 0.5px, --text-secondary;
   — название группы (цеховые/монтажные): подпись поля панели (`.form-label`): 0.8rem, medium,
     --text-secondary, обычный регистр, БЕЗ рамки — рамок-боксов у подписей в панели нет нигде.
   Прописное наименование позиций и рамка у названия раздела убраны как чужие модулю.
   Ref: DESIGN.md (типографика, токены); docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
/* [2026-10-03] ЛЁГКАЯ ТИПОГРАФИКА (замечание PO со снимком: «текст такой толстый и печатный… где
   элегантность»; разбор навыком critique-typography): было три веса (600/500/500) и все подписи
   почти белые — в тёмной теме --text-secondary (#e5e7eb) и --text-tertiary (#d1d5db) почти равны
   --text-primary, иерархии не было, таблица читалась жирной печатью. Теперь два веса и иерархия
   цветом: строки — обычный вес (--font-weight-normal) цветом текста; служебное (шапка колонок,
   номер, подпись группы) — приглушено смесью --text-primary с прозрачным, которая работает в
   обеих темах. Ref: DESIGN.md (типографика); docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition {
    --fish-bom-muted: color-mix(in srgb, var(--text-primary) 55%, transparent);
}
#fish3dCompositionMount .fish-model-composition th,
#fish3dCompositionMount .fish-model-composition td {
    padding: var(--space-1) var(--space-2) var(--space-1) 0;
    border: 0;
    color: var(--text-primary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-normal);
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
    text-align: start;
}
/* [2026-10-03] Колонки — как таблица материалов изометрии: № | НАИМЕНОВАНИЕ | РАЗМЕР | КОЛ.
   (ModelComposition + isometricBom.js; приказ PO: «чертежи найди и посмотри, как там написано»).
   Шапка — прописные мелким кеглем; № — узкий справа; наименование — прописными, забирает остаток
   ширины и обрезается многоточием (полный текст и паспорт — тултип); размер — слева; кол. —
   справа. Обе таблицы (позиции и крепёж) устроены одинаково.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition th,
#fish3dCompositionMount .fish-model-composition thead td,
#fish3dCompositionMount .fish-model-composition-fastener-table > tr:first-child > * {
    padding-bottom: var(--space-1);
    /* [2026-10-03] Шапка — приглушённая микро-подпись, вес medium (не semibold). */
    color: var(--fish-bom-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    letter-spacing: 0.5px;
    text-transform: uppercase;
}
#fish3dCompositionMount .fish-model-composition tr > :first-child {
    min-width: 2ch;
    text-align: end;
}
/* [2026-10-03] Номер позиции — служебный, приглушён. Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition tr > td:first-child {
    color: var(--fish-bom-muted);
}
#fish3dCompositionMount .fish-model-composition .fish-bom-description,
#fish3dCompositionMount .fish-model-composition tr > th:nth-child(2) {
    width: 100%;
    max-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
#fish3dCompositionMount .fish-model-composition tr > :nth-child(4) {
    text-align: end;
}
/* [2026-10-03] Группы таблицы материалов изометрии (цеховые / монтажные) — подпись группы в каноне
   `.form-label` панели, без рамки (канон Исикавы, см. выше); первая группа прижата к верху тела,
   следующие отделены воздухом --space-3. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition .fish-bom-section > tr:first-child > th {
    padding: var(--space-3) 0 var(--space-1);
    text-align: start;
}
#fish3dCompositionMount .fish-model-composition .fish-bom-section:first-of-type > tr:first-child > th {
    padding-top: 0;
}
#fish3dCompositionMount .fish-model-composition .fish-bom-section-title {
    /* [2026-10-03] Подпись группы — приглушена, вес medium, кегль --font-size-xs (лёгкая типографика). */
    color: var(--fish-bom-muted);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    letter-spacing: normal;
    text-transform: none;
}
/* [2026-10-03] Подсветка — только у строк позиций, не у названия раздела и строки колонок.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition tbody tr:has(.fish-bom-description):hover > td {
    background: var(--bg-hover);
}
#fish3dCompositionMount .fish-model-composition .fish-composition-actions {
    width: auto;
    padding-right: 0;
    text-align: end;
}
/* [2026-10-02] Выбор экземпляра в разделе — значок фокуса 34×34 у правого края строки, а не
   кнопка во всю ширину с надписью (замечание PO: «не нужна такая огромная кнопка»). Вид —
   канон иконочной кнопки панели (`.fish-sidebar-btn`): прозрачная, цвет вторичного текста;
   выбранный экземпляр — акцентный цвет и рамка. Имя действия — в aria-label и тултипе.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-model-composition .fish-composition-focus-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* [2026-10-03] float снят: значки стоят в своей колонке строки (.fish-composition-actions),
       а не обтекают имя. Chat: fish-model-composition-sidebar-section-2026-10-02. */
    vertical-align: middle;
    width: 34px;
    height: 34px;
    min-width: 34px;
    min-height: 34px;
    flex-shrink: 0;
    box-sizing: border-box;
    margin: 0 0 0 var(--space-1);
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-lg);
    background: transparent;
    color: var(--text-secondary);
}
#fish3dCompositionMount .fish-model-composition .fish-composition-focus-btn svg {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
}

#fish3dCompositionMount .fish-model-composition .fish-composition-focus-btn:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}
#fish3dCompositionMount .fish-model-composition .fish-composition-focus-btn.is-selected {
    color: var(--fish3d-selection-color, #f6c453);
    border-color: var(--fish3d-selection-color, #f6c453);
    background: transparent;
    outline: none;
}
#fish3dCompositionMount .fish-model-composition .fish-composition-focus-btn:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}

/* [2026-09-22] Поля ввода параметров расчёта в панели состава: среда, расход, допустимая
   скорость (§34 пп. 3, 6) и дата состава (§21.3). Строка «подпись — поле», как в остальных
   формах модуля; украшений нет — §22.1 их запрещает.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §34, §21.3. Chat: fish3d-implementation-2026-09-21. */
/* [2026-09-22] Круговое меню геймпада (§15.4): накладка поверх сцены, не модалка. Сцена под ним
   видна — затемнение лёгкое (§15.4 п. 4). Украшений нет: §22.1 их запрещает.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §15.4. Chat: fish3d-implementation-2026-09-21. */
/* [2026-09-22] Экран настроек управления (§14 п. 7): список СТРОК, кнопки только в подвале.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §14 п. 7. Chat: fish3d-implementation-2026-09-21. */
/* [2026-09-22] Меню `Esc` (§9.4, §22.4): игровая пауза-экран — СПИСОК СТРОК во всю ширину
   колонки по центру, крупные. Сцена под ним видна; затемнение лёгкое, украшений нет (§22.1).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §9.4, §22.4. Chat: fish3d-implementation-2026-09-21. */
.fish3d-pause {
    position: absolute;
    inset: 0;
    z-index: 9;
    display: flex;
    box-sizing: border-box;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* На невысоком холсте список из всех команд Esc выше пространства сцены. Обычное
       центрирование тогда сдвигает начало ВВЕРХ за границу холста и обрезает «Продолжить».
       `safe` сохраняет центрирование, когда места достаточно, а при переполнении начинает
       список внутри видимой области; прокрутка оставляет доступными остальные команды. */
    justify-content: safe center;
    gap: 10px;
    overflow-y: auto;
    padding: 24px 0;
    background: rgba(17, 24, 39, 0.4);
    color: var(--fish3d-hud-text);
}
.fish3d-pause.hidden {
    display: none;
}

/* The template name is entered on a game screen, with the world still visible behind it.
   Actions are full-width rows, not a document-modal footer. */
.fish3d-template-save,
.fish3d-template-apply,
.fish3d-open-unsaved {
    position: absolute;
    inset: 0;
    z-index: 12;
    display: flex;
    align-items: center;
    justify-content: safe center;
    overflow-y: auto;
    padding: 20px;
    box-sizing: border-box;
    background: rgba(17, 24, 39, 0.4);
}
.fish3d-template-save.hidden,
.fish3d-template-apply.hidden,
.fish3d-open-unsaved.hidden {
    display: none;
}
.fish3d-template-apply-name {
    margin: 0;
    padding: 10px 12px;
    overflow-wrap: anywhere;
    font-weight: 700;
    background: var(--bg-secondary);
    border-inline-start: 0;
}
.fish3d-template-apply-description {
    margin-block: 0;
}
.fish3d-template-save-panel {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: min(480px, 100%);
    padding: 20px;
    box-sizing: border-box;
    color: var(--text-primary);
    background: var(--bg-primary);
    border: 2px solid var(--fish3d-hud-border, var(--border-color));
}
.fish3d-template-save-panel h3 {
    margin: 0 0 6px;
    font-size: 18px;
}
.fish3d-template-save-panel label {
    font-weight: 600;
}
.fish3d-template-save-panel input {
    width: 100%;
    min-height: 44px;
    box-sizing: border-box;
    padding: 8px 12px;
    color: var(--text-primary);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
}
.fish3d-template-save-error {
    margin: 0;
    /* [2026-10-03] Токена `--color-danger` в themes.css нет — работал только запасной цвет, без
       тёмной темы. Канонический токен ошибки — `--color-error`.
       Chat: fish-model-composition-sidebar-section-2026-10-02. */
    color: var(--color-error-text);
}
.fish3d-template-save-error.hidden {
    display: none;
}
.fish3d-template-save-actions {
    display: grid;
    gap: 8px;
}
.fish3d-template-save-row {
    min-height: 44px;
    width: 100%;
    padding: 8px 12px;
    color: var(--text-primary);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    text-align: left;
    cursor: pointer;
}
.fish3d-template-save-row:hover,
.fish3d-template-save-row:focus-visible {
    border-color: var(--fish3d-selection-color, #f6c453);
    outline: 2px solid var(--fish3d-selection-color, #f6c453);
    outline-offset: -2px;
}
.fish3d-template-save-row:disabled {
    opacity: 0.65;
    cursor: progress;
}
/* Pause owns the current game input circuit.  The surrounding application chrome is inert while
   it is open; mute it too, so a bright Layers/Properties pane does not promise a click that the
   modal deliberately refuses.  This preserves the scene as contextual backdrop without mixing
   the active game menu with office-editor controls. */
.fish3d-pause-chrome-muted,
.fish3d-external-screen-muted {
    opacity: 0.42;
    filter: saturate(0.65);
    pointer-events: none;
}
.fish3d-pause-title {
    margin: 0;
    font-size: 18px;
}
.fish3d-pause-list,
.fish3d-pause-pane {
    width: min(560px, 90%);
}
/* [2026-09-22] Живая приёмка: развёрнутая панель была полупрозрачной, и сквозь неё просвечивали
   и сцена, и панель режимов — строки настроек читались плохо. Содержимое паузы стоит на
   НЕПРОЗРАЧНОМ фоне страницы, а лёгкая вуаль остаётся только вокруг него. */
.fish3d-pause-pane > * {
    background: var(--bg-primary);
}
/* The camera picker is rendered first in the compact scene popover and is then
   borrowed by Esc.  The generic pane rule above made the borrowed section white
   while it retained HUD-coloured (light) text, leaving the camera choices
   effectively unreadable.  It is a game-menu surface in Pause, not a document
   Properties card. */
.fish3d-pause-pane > .fish3d-view-modes {
    box-sizing: border-box;
    width: 100%;
    padding: 16px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
}
/* Pause already supplies the current pane title.  Keeping the picker's own
   title creates a visually duplicated “View modes” heading. */
.fish3d-pause-pane > .fish3d-view-modes > h3 {
    display: none;
}
.fish3d-pause-pane > .fish3d-view-modes > p {
    margin: 0 0 12px;
    color: inherit;
}
.fish3d-pause-pane > .fish3d-view-modes .fish3d-view-modes-current {
    font-weight: 700;
}
.fish3d-pause-pane > .fish3d-view-modes-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
}
.fish3d-pause-pane > .fish3d-view-modes .fish3d-view-mode-option {
    min-height: 44px;
    padding: 8px 10px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 6px;
    background: transparent;
    color: inherit;
    cursor: pointer;
}
.fish3d-pause-pane > .fish3d-view-modes .fish3d-view-mode-option[aria-checked='true'],
.fish3d-pause-pane > .fish3d-view-modes .fish3d-view-mode-option:hover,
.fish3d-pause-pane > .fish3d-view-modes .fish3d-view-mode-option:focus-visible {
    border-color: var(--fish3d-hud-accent);
    background: var(--fish3d-hud-hover);
    outline: none;
}
/* Блок настроек обычно всплывает от панели сцены и потому абсолютный. Когда меню Esc
   одалживает его в свою область, абсолютное позиционирование уводит органы под правую
   боковую панель; в паузе это обычное содержимое игрового экрана. */
.fish3d-pause-pane > .fish3d-scene-more-menu {
    position: static;
    box-sizing: border-box;
    width: 100%;
    min-width: 0;
    gap: 12px;
    padding: 14px;
    border-color: var(--fish3d-hud-border);
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
}
/* The compact scene popover is borrowed by Esc.  Its native-sized controls were only 16–21px
   tall there, which makes a full-screen game menu look like an unfinished inspector and misses
   a reliable desktop target.  Enlarge it only while it belongs to Pause; the in-scene popover
   remains compact when it is returned to the HUD. */
.fish3d-pause-pane > .fish3d-scene-more-menu .fish3d-feedback-controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}
.fish3d-pause-pane > .fish3d-scene-more-menu .fish3d-volume-control {
    grid-column: 1 / -1;
    min-height: 44px;
    gap: 12px;
    font-size: 14px;
}
.fish3d-pause-pane > .fish3d-scene-more-menu .hotbar-btn {
    width: 100%;
    min-height: 44px;
    padding: 8px 12px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: transparent;
    color: inherit;
    font-size: 14px;
    cursor: pointer;
}
.fish3d-pause-pane > .fish3d-scene-more-menu .hotbar-btn:hover,
.fish3d-pause-pane > .fish3d-scene-more-menu .hotbar-btn:focus-visible {
    border-color: var(--fish3d-hud-accent);
    background: var(--fish3d-hud-hover);
}
.fish3d-pause-pane > .fish3d-scene-more-menu .fish3d-speed-control {
    display: grid;
    grid-template-columns: auto minmax(120px, 1fr) auto;
    align-items: center;
    min-height: 44px;
    gap: 12px;
    font-size: 14px;
}
.fish3d-pause-pane > .fish3d-scene-more-menu .fish3d-speed-range,
.fish3d-pause-pane > .fish3d-scene-more-menu .fish3d-volume {
    width: 100%;
    min-height: 28px;
}
.fish3d-pause-list.hidden,
.fish3d-pause-pane.hidden {
    display: none;
}
.fish3d-pause-row {
    padding: 10px 14px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    font-size: 16px;
    cursor: pointer;
}
.fish3d-pause-row + .fish3d-pause-row {
    margin-top: 6px;
}
.fish3d-pause-pane > .fish3d-pause-back {
    display: block;
    box-sizing: border-box;
    width: 100%;
    margin-top: 12px;
    color: var(--fish3d-hud-text);
}

/* На рабочем desktop высота самого 3D-поля меньше высоты окна из-за шапки,
   панели файлов и вкладок. Одиннадцать строк Esc при прежних 16px/10px не
   помещались даже в 792px viewport: нижние «Во весь экран» и «Выйти из
   режима» оказывались за краем без подсказки, что меню прокручивается. В
   Minecraft-подобном меню все немедленные действия должны быть видны сразу;
   уплотняем только невысокий экран, сохраняя полноценный размер на высоком. */
@media (max-height: 820px) {
    .fish3d-pause {
        gap: 6px;
        padding: 12px 0;
    }

    .fish3d-pause-title {
        font-size: 16px;
    }

    .fish3d-pause-row {
        box-sizing: border-box;
        min-height: 36px;
        padding: 6px 12px;
        font-size: 14px;
    }

    .fish3d-pause-row + .fish3d-pause-row {
        margin-top: 4px;
    }
}

/* In a short desktop scene the single column still exceeds the available game area:
   its last commands require an undiscoverable scroll. Keep the DOM-ordered menu in
   two stable columns; a balanced CSS multi-column list moved rows on focus, so a
   pointerdown and pointerup could land on different commands. */
@media (max-height: 650px) and (min-width: 680px) {
    .fish3d-pause-list:not(.hidden) {
        width: min(760px, calc(100% - 32px));
        display: grid;
        grid-auto-flow: column;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        grid-template-rows: repeat(var(--fish3d-pause-grid-rows), minmax(0, auto));
        gap: 4px 8px;
    }

    .fish3d-pause-row {
        /* The second column can cross the light Properties sidebar. Keep scene visible
           around the rows, but do not let sidebar labels bleed through the commands. */
        background: var(--fish3d-hud-control-bg);
    }

    .fish3d-pause-row + .fish3d-pause-row {
        margin-top: 0;
    }
}

/* Нецветовой признак (§22.2) — жирная подпись; контур не меняет геометрию строки. */
.fish3d-pause-row.hovered,
.fish3d-pause-row:focus-visible {
    font-weight: 700;
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
.fish3d-bindings {
    position: absolute;
    top: 10%;
    left: 50%;
    transform: translateX(-50%);
    z-index: 8;
    width: min(520px, 90%);
    max-height: 70%;
    overflow-y: auto;
    padding: 12px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: var(--radius-lg);
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    font-size: 13px;
}
.fish3d-bindings.hidden {
    display: none;
}
/* Control bindings normally float above the scene.  When Esc borrows the same
   node, absolute positioning removes it from the pause layout and leaves the
   pause title visible through/behind the scroll card. */
.fish3d-pause-pane > .fish3d-bindings {
    position: static;
    box-sizing: border-box;
    width: 100%;
    max-height: min(58vh, 560px);
    margin: 0;
    transform: none;
}
/* The pause owns the pane heading; avoid announcing two near-identical titles. */
.fish3d-pause-pane > .fish3d-bindings > .fish3d-bindings-title {
    display: none;
}
.fish3d-bindings-help {
    margin: 8px 0;
    color: var(--fish3d-hud-muted, var(--fish3d-hud-text));
    line-height: 1.35;
}
.fish3d-bindings-row {
    display: flex;
    align-items: center;
    min-height: 34px;
    box-sizing: border-box;
    justify-content: space-between;
    gap: 8px;
    padding: var(--space-1) var(--space-2);
    border-bottom: 1px solid var(--fish3d-hud-border);
    cursor: pointer;
}
.fish3d-bindings-row:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
/* [2026-10-03] Строка-переключатель «Подсказки управления» перед списком привязок: та же строка,
   что у привязок, но кнопка во всю ширину; состояние справа акцентом, когда включено.
   Ref: docs/PROPOSAL_FISH_3D_CONTROL_HINTS_TOGGLE_2026-10-03.md.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish3d-bindings-option {
    display: flex;
    align-items: center;
    min-height: 34px;
    justify-content: space-between;
    gap: 8px;
    padding: var(--space-1) var(--space-2);
    cursor: pointer;
    box-sizing: border-box;
    width: 100%;
    margin: 0 0 8px;
    border: 0;
    border-bottom: 1px solid var(--fish3d-hud-border);
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
}
.fish3d-bindings-option:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
.fish3d-bindings-option-state {
    color: var(--fish3d-hud-muted, var(--fish3d-hud-text));
    font-weight: 600;
}
.fish3d-bindings-option[aria-checked='true'] .fish3d-bindings-option-state {
    color: var(--fish3d-hud-accent);
}
/* Строка в ожидании клавиши отличается не только цветом: подпись жирная и рамка толще. */
.fish3d-bindings-row.awaiting {
    font-weight: 700;
    border-bottom-width: 2px;
}
.fish3d-bindings-footer {
    position: sticky;
    bottom: -12px;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 0 0;
    border-top: 1px solid var(--fish3d-hud-border);
    background: var(--fish3d-hud-bg);
}
/* Settings commands retain the shared compact text-action target; labels may wrap. */
.fish3d-bindings-footer button {
    box-sizing: border-box;
    min-height: 34px;
    height: auto;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--fish3d-hud-border);
    border-radius: var(--radius-md);
    white-space: normal;
    overflow-wrap: anywhere;
    max-width: 100%;
    background: var(--fish3d-hud-control-bg);
    color: var(--fish3d-hud-text);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.fish3d-bindings-footer #fish3dBindingsClose {
    border-color: var(--fish3d-hud-accent);
    color: var(--fish3d-hud-accent);
}
.fish3d-bindings-footer button:hover {
    background: color-mix(in srgb, var(--fish3d-hud-control-bg) 80%, #fff);
}
.fish3d-bindings-footer button:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
.fish3d-radial {
    position: absolute;
    inset: 0;
    z-index: 7;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: rgba(17, 24, 39, 0.35);
    color: var(--fish3d-hud-text);
    pointer-events: none;
}
.fish3d-radial.hidden {
    display: none;
}
.fish3d-radial-title {
    font-size: 14px;
    font-weight: 600;
}
.fish3d-radial-wheel {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 6px;
    max-width: min(720px, 90%);
}
.fish3d-radial-sector {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    font-size: 13px;
}
/* Наведённый сектор отличается не ТОЛЬКО цветом (§22.2): рамка толще и подпись жирнее. */
.fish3d-radial-sector.hovered {
    border-width: 2px;
    font-weight: 700;
    outline: 2px solid var(--brand-primary);
}
/* Недоступное приглушено и НАЗЫВАЕТ причину, но из круга не исчезает (§15.4 п. 5). */
.fish3d-radial-sector.unavailable {
    opacity: 0.55;
}
.fish3d-radial-reason {
    opacity: 0.8;
}
.fish3d-radial-note {
    min-height: 16px;
    font-size: 12px;
}
.fish3d-radial-help {
    max-width: min(720px, 90%);
    color: var(--fish3d-hud-muted);
    font-size: 12px;
    text-align: center;
}
.fish3d-composition-params {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 6px 0;
}
.fish3d-composition-param {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.fish3d-composition-param input {
    width: 120px;
    height: var(--inspector-control-height);
    box-sizing: border-box;
    padding: 2px 4px;
    border: 1px solid var(--border-primary);
    border-radius: var(--radius-md);
    background: var(--bg-primary);
    color: var(--text-primary);
    font-size: 12.5px;
}
.fish3d-composition-param input:focus {
    outline: none;
    border-color: var(--border-hover);
    box-shadow: none;
}
/* Нарушение предела скорости (§34 п. 6) называется тем же цветом тревоги, что прочие нарушения
   модели; пометка «предварительно» (§34 п. 5) и объект вне интервала (§21.3) — приглушённым. */
.fish3d-composition-violation {
    color: var(--color-error-text);
    font-weight: 600;
}
.fish3d-composition-preliminary,
.fish3d-composition-inactive {
    color: var(--text-secondary);
}
/* Хотбар примитивов 3D (Часть II §6) — снизу по центру поверх канвы */
/* [2026-08-16] Палитра HUD вынесена в переменные блока вместо разбросанных литералов.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §C5, §C6. Chat: fish-icons-styles-audit-2026-08-16.

   [2026-09-22] Этап AP §14 п. 1: палитра переведена НА ТОКЕНЫ и ведёт себя в обеих темах.
   Прежний комментарий объяснял тёмный HUD тем, что вьюпорт three.js чистится фиксированным
   цветом и на тему не реагирует. Это перестало быть правдой: цвет сцены теперь берётся у токена
   `--bg-primary` (js/3d/Fish3D.js, `sceneBackgroundColor`), и панель обязана идти за темой
   вместе с ней. ТЗ требует этого прямо: «хардкод-цвета HUD переводятся в токены с корректным
   поведением в светлой и тёмной теме». Найдено вторым мнением (обе стороны, круг
   `fish3d-tz-final9` 2026-09-22).
   Запасные значения оставлены у каждого токена: страница без темы (тест, ранний кадр) получает
   прежний тёмный HUD, а не прозрачную панель.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §14 п. 1. Chat: fish3d-implementation-2026-09-21. */
.fish3d-hotbar {
    /* [2026-09-22] Значения берутся из СВОИХ токенов темы (styles/themes.css), объявленных один
       раз и не переопределяемых темой. Прошлая правка привязала их к общим `--bg-secondary` и
       `--text-secondary`, и в светлой теме HUD становился светлым — прямое нарушение §22.1
       («поверхности HUD остаются тёмными и в светлой теме»). Поймано вторым мнением (обе
       стороны, круг `fish3d-tz-final10` 2026-09-22): токены нужны по §14 п. 1, но общие тут не
       годятся, нужны свои. Здесь значения НЕ переопределяются: ссылка токена на самого себя
       внутри собственного объявления — цикл, и CSS такое правило отбрасывает. */
    position: absolute;
    bottom: var(--space-4);
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    display: flex;
    gap: 6px;
    padding: 6px 8px;
    border-radius: 10px;
    background: var(--fish3d-hud-bg);
    border: 1px solid var(--fish3d-hud-border);
    color: var(--fish3d-hud-text);
    /* [2026-09-22] Размытие-стекло УБРАНО. ТЗ §22.1 дословно: «ни свечений, ни размытий-стёкол,
       ни градиентных кнопок, ни декоративных частиц вне обратной связи §11» (строка 892
       документа). `backdrop-filter: blur(4px)` был ровно тем украшением, которое строка
       запрещает; поймано вторым мнением (обе стороны, круг `fish3d-tz-final11` 2026-09-22).
       Плашка остаётся сплошной — непрозрачность даёт токен `--fish3d-hud-bg`, а не размытие.
       Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. Chat: fish3d-implementation-2026-09-21. */
}
.fish3d-hotbar .hotbar-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    min-width: 52px;
    padding: 6px 8px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    color: var(--fish3d-hud-text);
    cursor: pointer;
    font-size: 11px;
}
.fish3d-hotbar .hotbar-btn:hover {
    background: var(--fish3d-hud-hover);
}
/* [2026-09-22] Этап AU §6 п. 5: кнопка режима, которая сейчас ничего не переключает (вид от
   первого лица вне Walk), ПОГАШЕНА и не отвечает на наведение — правила для `:disabled` у
   кнопок хотбара не было вовсе, и погашенная кнопка выглядела рабочей. Жалоба PO 2026-09-22:
   «между режимами конфликт и несогласованность».
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §10.6. Chat: fish3d-implementation-2026-09-21. */
.fish3d-hotbar .hotbar-btn:disabled {
    opacity: 0.4;
    cursor: default;
}
/* [2026-09-22] Этап AV: меню «Ещё» — личные настройки сеанса (звук, громкость, «уменьшить
   движение», скорость, настройки управления) больше не занимают ряд панели. Приказ PO
   2026-09-22: «это в троеточие положи, зачем это на виду». Выпадает ПОД кнопкой, внутри
   обёртки интерфейса — это накладка панели, а не модальное окно (§22.5).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §22.1. Chat: fish3d-implementation-2026-09-21. */
/* [2026-09-22] Этап AV: панель сцены — подсказка про `Esc` и статусы включённого. Кнопок в ней
   нет (приказ PO 2026-09-22), поэтому и ряд больше не переносится на вторую строку.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §9.4. */
.fish3d-hotbar .fish3d-scene-hint {
    font-size: 11px;
    letter-spacing: 0.04em;
    opacity: 0.7;
}
.fish3d-hotbar .fish3d-scene-status {
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
}
.fish3d-scene-more {
    position: relative;
}
.fish3d-scene-more-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 6;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    min-width: 220px;
    padding: 8px;
    border: 1px solid var(--fish3d-hud-border, rgba(255, 255, 255, 0.12));
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
}
.fish3d-scene-more-menu.hidden {
    display: none;
}
.fish3d-scene-more-menu .fish3d-feedback-controls,
.fish3d-scene-more-menu .fish3d-speed-control {
    justify-content: space-between;
}
.fish3d-hotbar .hotbar-btn:disabled:hover {
    background: transparent;
}
/* [2026-09-22] Этап AP: переключатель «Проектирование в воздухе» меняет подпись
   («Проектирование в воздухе» ↔ «Падение приостановлено»), и на живой приёмке ширина
   кнопки прыгала с 79 на 90 px — вся панель сцены (селектор аватара, ссылка CAD) дёргалась
   на каждое нажатие. Ширина закреплена по более длинной подписи: кнопка держит размер,
   соседи стоят на месте. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §12.14.
   Chat: fish3d-implementation-2026-09-21. */
.fish3d-hotbar #fish3dAirDesignToggle {
    width: 110px;
}
/* [2026-09-22] Этап AU §10.6: подпись кнопки вида теперь называет вид словом («3-е сзади»,
   «3-е спереди», «1-е лицо») вместо «3rd»/«1st», и на живой проверке ряд панели поехал —
   «Скорость» и «Управление» ушли во вторую строку. Ширина закреплена по самой длинной подписи
   тем же приёмом, что и у переключателя воздуха: подпись меняется, соседи стоят.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §10.6, §22.1. Chat: fish3d-implementation-2026-09-21. */
.fish3d-hotbar #fish3dViewToggle {
    width: 86px;
}
/* [2026-09-22] Этап AP: органы управления откликом (§11) — звук, громкость, «уменьшить
   движение». Прежде их не было нигде, и включить звук было нечем, хотя §11 п. 3 требует
   включения ВРУЧНУЮ. Регулятор прячется при выключенном звуке: он тогда бессмыслен.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §11 п. 3, §22.3. Chat: fish3d-implementation-2026-09-21. */
.fish3d-feedback-controls {
    display: flex;
    align-items: center;
    gap: 4px;
}
.fish3d-feedback-controls .hotbar-btn {
    width: 104px;
}
.fish3d-volume {
    width: 72px;
    accent-color: var(--fish3d-hud-accent);
}
.fish3d-volume-control {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(72px, 1fr) auto;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: var(--fish3d-hud-text);
    font-size: 11px;
}
.fish3d-volume-control.hidden {
    display: none;
}
.fish3d-volume-caption {
    min-width: 0;
    overflow-wrap: anywhere;
}
.fish3d-volume-value {
    min-width: 3ch;
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.fish3d-volume.hidden {
    display: none;
}
/* [2026-09-22] Этап AP: регулятор скорости (§10.3) — личная настройка участника рядом с
   прочими настройками сцены. Значение видно числом: «×1.4» читается без наведения.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §10.3. Chat: fish3d-implementation-2026-09-21. */
.fish3d-speed-control {
    display: flex;
    align-items: center;
    gap: 4px;
    color: var(--fish3d-hud-text);
    font-size: 11px;
}
.fish3d-speed-range {
    width: 72px;
    accent-color: var(--fish3d-hud-accent);
}
/* [2026-09-22] Этап AP §7 пп. 2, 4: статус готовности позиции и личная пометка «избранное».
   Недоступная строка приглушена и несёт причину текстом; пометка — значок состояния, а не
   кнопка: перечень остаётся строками (канон PO «списки строками, не кнопками»).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §7 пп. 2, 4. Chat: fish3d-implementation-2026-09-21. */
/* [2026-09-22] Этап AP §9.2bis «Значок проникновения в 3D — обязателен». Требование PO
   2026-09-19: «UI должен показывать в 3D, где penetration, значком». Слой лежит поверх холста
   внутри обёртки интерфейса — значит прячется по F1 вместе со всем остальным; сами значки ловят
   наведение и клик, слой — нет. Состояния различаются ФОРМОЙ (рамка) и подписью, а не только
   цветом (§9.2bis «Состояния», канон доступности §14).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §9.2bis. Chat: fish3d-implementation-2026-09-21. */
.fish3d-penetration-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.fish3d-penetration-marker {
    position: absolute;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--color-warning, #e0a020);
    border-radius: 4px;
    background: var(--fish3d-hud-bg, rgba(20, 24, 28, 0.82));
    color: var(--color-warning-text, #e0a020);
    pointer-events: auto;
    cursor: pointer;
}
.fish3d-penetration-marker.state-stale {
    border-style: dashed;
    opacity: 0.7;
}
.fish3d-penetration-marker.state-changed {
    border-width: 2px;
    border-radius: 50%;
}
.fish3d-penetration-count {
    font-size: 11px;
    line-height: 1;
}

.fish3d-inventory-row.not-ready {
    cursor: pointer;
}
.fish3d-inventory-row.not-ready[aria-disabled='true'] {
    opacity: 0.55;
    cursor: not-allowed;
}
.fish3d-inventory-status {
    font-size: 11px;
    color: var(--fish3d-inventory-error-text);
}
.fish3d-inventory-star {
    min-width: 14px;
    text-align: center;
    color: var(--color-warning-text, #e0a020);
}

/* [2026-09-22] Этап AS §7 «Состояния окна»: строка «каталог фрейма читается». Живой прогон
   2026-09-22: чтение идёт ~19 секунд, и всё это время человек видел только встроенные формы.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §7. Chat: fish3d-implementation-2026-09-21. */
.fish3d-inventory-status-line {
    margin: 0;
    padding: 2px 8px;
    font-size: 12px;
    color: var(--fish3d-inventory-warning-text);
}

.fish3d-inventory-status-line.error {
    color: var(--fish3d-inventory-error-text);
}

/* [2026-09-22] Этап AS §7 п. 4: КАРТИНКА ИЗДЕЛИЯ В СТРОКЕ КАТАЛОГА. Требование PO 2026-09-22
   дословно: «человек должен видеть картинки с названием», «в майнкрафте из каталога 3д картинок
   выбираешь элемент». Картинку рисует `3d/classThumbnail.js` той же геометрией, что и сцена;
   размер держится здесь, чтобы строка оставалась строкой перечня, а не карточкой-кнопкой (канон
   PO «списки — строками»). Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §7 п. 4.
   Chat: fish3d-implementation-2026-09-21. */
.fish3d-inventory-row {
    align-items: center;
}
.fish3d-inventory-thumb {
    width: 48px;
    height: 48px;
    flex: 0 0 48px;
    object-fit: contain;
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-bg, rgba(20, 24, 28, 0.82));
}
.fish3d-inventory-thumb.unavailable {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* [2026-10-03] `--fish3d-hud-text-muted` не объявлен нигде; приглушённый текст HUD —
       `--fish3d-hud-muted` (themes.css). Chat: fish-model-composition-sidebar-section-2026-10-02. */
    color: var(--fish3d-hud-muted);
    border: 1px dashed currentColor;
    font-size: 24px;
    line-height: 1;
}
.fish3d-inventory-title {
    flex: 1 1 auto;
}

.fish3d-speed-value {
    min-width: 30px;
    text-align: right;
}
.fish3d-hotbar #fish3dAirDesignToggle .hotbar-label {
    text-align: center;
    line-height: 1.15;
}
.fish3d-hotbar .hotbar-btn.active {
    border-color: var(--fish3d-hud-accent);
    background: var(--fish3d-hud-active-bg);
    color: var(--fish3d-hud-text-active);
}
/* [2026-08-16] Подпись внутри иконочной кнопки хотбара — правила не было вовсе.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §E. Chat: fish-icons-styles-audit-2026-08-16. */
.fish3d-hotbar .hotbar-label {
    line-height: 1;
    white-space: nowrap;
}
/* [2026-10-04] Разделитель хотбара снят как мёртвый: хотбар его не создаёт. Ref: js/__tests__/fishDeadCode.guard.test.js. */
/* Подсекция «Геометрия (3D)» в Properties (TZ §9) */
.geometry-section {
    border-top: 1px solid var(--border-primary);
    margin-top: 8px;
    padding-top: 8px;
}
.geometry-selection-title {
    color: var(--text-primary);
    font-size: 0.82rem;
    font-weight: 600;
    margin: 0 0 8px;
    overflow-wrap: anywhere;
}
.geometry-apply-status {
    margin: 8px 0 0;
    font-size: 12px;
    font-weight: 600;
}
.geometry-apply-status.error {
    color: var(--color-error-text, #d64545);
}
.geometry-apply-status.success {
    color: var(--color-success-text, #258a45);
}
.geometry-section .geom-fields {
    margin-bottom: 6px;
}
.geometry-section .geom-fields > .form-label {
    display: block;
    font-size: 0.8rem;
    margin-bottom: 2px;
    color: var(--text-secondary);
}
.geometry-section .geom-row {
    display: flex;
    gap: 4px;
}
.geometry-section .geom-row > .input {
    flex: 1;
    min-width: 0;
}
.geometry-section .geom-axis-field {
    align-items: center;
    color: var(--text-secondary);
    display: flex;
    flex: 1;
    font-size: 0.75rem;
    gap: 3px;
    min-width: 0;
}
.geometry-section .geom-axis-field > .input {
    flex: 1;
    min-width: 0;
}
.geometry-section .hidden {
    display: none;
}

/* 2D Plan — ортогональная проекция модели сверху (SVG: контуры + осевые линии) */
.fish-2d-plan {
    display: block;
    width: 100%;
    height: 100%;
}
/* зум колесом + панорама перетаскиванием */
#fish2dRoot {
    cursor: grab;
}
/* [2026-10-04] Причина отката 3D → План 2D, на месте, без окна (ТЗ §4.2).
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §4.2. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-scene-fail-notice {
    position: absolute;
    top: var(--space-2, 8px);
    left: var(--space-3, 12px);
    z-index: 6;
    max-width: min(520px, calc(100% - 24px));
    margin: 0;
    padding: var(--space-2, 8px) var(--space-3, 12px);
    border: 1px solid var(--color-warning);
    border-radius: 8px;
    background: var(--color-warning-bg);
    color: var(--text-primary);
    font-size: 12px;
    line-height: 1.35;
    pointer-events: none;
}
.fish-scene-fail-notice.hidden {
    display: none;
}
/* [2026-10-04] Строка «Фильтр WBS: … ×» над сценой (3D и План 2D), пока отбор панели WBS включён.
   Плашка-статус, как строка сбоя 3D рядом, но кликабельна: крестик снимает фильтр.
   Ref: docs/TZ_FISH_COMPONENT_WBS_TAGS_2026-10-04.md §4.4. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-wbs-filter-strip {
    position: absolute;
    top: var(--space-2, 8px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 6;
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    max-width: calc(100% - 24px);
    padding: var(--space-1, 4px) var(--space-1, 4px) var(--space-1, 4px) var(--space-3, 12px);
    border: 1px solid var(--brand-primary);
    border-radius: 8px;
    background: var(--bg-primary);
    color: var(--text-primary);
    font-size: var(--font-size-sm, 13px);
    line-height: 1.35;
}
.fish-wbs-filter-strip.hidden {
    display: none;
}
/* [2026-10-04] Контейнер сцены тянется и под правую панель: строка держится центра ВИДИМОЙ сцены
   (как хотбар .fish3dSlots). Живая приёмка: без этого строка заходила под кромку панели. */
.fish-main-container:not(.right-sidebar-collapsed) .fish-wbs-filter-strip {
    left: calc((100% - var(--fish-right-sidebar-width, 340px)) / 2);
    max-width: calc(100% - var(--fish-right-sidebar-width, 340px) - 24px);
}
.fish-wbs-filter-icon {
    color: var(--brand-primary-text);
    font-size: 18px;
}
.fish-wbs-filter-label {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
/* [2026-10-04] Строка отказа/сбоя записи меток WBS (панель WBS и поле «Теги WBS»).
   Ref: docs/TZ_FISH_COMPONENT_WBS_TAGS_2026-10-04.md §4.2, §4.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-wbs-status {
    margin: 0 0 var(--space-2, 8px);
    color: var(--color-warning-text);
    font-size: var(--font-size-xs, 12px);
    line-height: 1.35;
}
#wbs-panel .fish-wbs-status {
    padding: var(--space-2, 8px) var(--space-3, 12px) 0;
}
.fish-wbs-status.hidden,
.fish-wbs-tags-field.hidden {
    display: none;
}
/* [2026-10-04] Раскладка Спецификации по тегам WBS: выбор над таблицей и заголовок группы.
   Ref: docs/TZ_FISH_COMPONENT_WBS_TAGS_2026-10-04.md §4.5. Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dCompositionMount .fish-wbs-layout {
    margin-bottom: var(--space-2, 8px);
}
#fish3dCompositionMount .fish-model-composition .fish-bom-group > tr > th {
    padding: var(--space-4, 16px) 0 var(--space-1, 4px);
    text-align: start;
}
#fish3dCompositionMount .fish-model-composition .fish-bom-group:first-of-type > tr > th {
    padding-top: 0;
}
#fish3dCompositionMount .fish-model-composition .fish-bom-group-title {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2, 8px);
    color: var(--text-primary);
    font-size: var(--font-size-sm, 13px);
    font-weight: var(--font-weight-semibold, 600);
    /* Имя папки/тега — данные, а не шапка колонок: без прописных (живая приёмка 2026-10-04). */
    text-transform: none;
    letter-spacing: normal;
}
#fish3dCompositionMount .fish-model-composition .fish-bom-group-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: none;
    background: var(--fish-wbs-tag-color, var(--text-secondary));
}
/* [2026-10-04] Строка Спецификации, которую можно перетащить на папку панели WBS. */
#fish3dCompositionMount .fish-model-composition tr.fish-wbs-draggable {
    cursor: grab;
}
#fish2dRoot.plan-grabbing {
    cursor: grabbing;
}
.fish-2d-plan .plan-contour {
    fill: none;
    stroke-width: 1.5px;
    vector-effect: non-scaling-stroke;
}
/* осевые линии — штрих-пунктир (CAD-конвенция для осей вращения/симметрии) */
/* [2026-08-16] Токена --accent-primary в проекте НЕТ: осевые линии рисовались мёртвым
   фолбэком #e06c2f, то есть цветом вне палитры и вне темы. Взят ближайший канонический
   токен --color-warning (янтарный) — он же меняется по теме.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §B2, §C5. Chat: fish-icons-styles-audit-2026-08-16. */
.fish-2d-plan .plan-axis {
    stroke: var(--color-warning);
    stroke-width: 1px;
    stroke-dasharray: 14 4 3 4;
    vector-effect: non-scaling-stroke;
    opacity: 0.85;
}
.fish-2d-plan .plan-centermark {
    stroke: var(--color-warning);
    stroke-width: 1px;
    vector-effect: non-scaling-stroke;
    opacity: 0.85;
}
/* [2026-08-16] Убран мёртвый фолбэк #9aa0a6 — токен --text-secondary существует всегда.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §C5. Chat: fish-icons-styles-audit-2026-08-16. */
.fish-2d-plan .plan-empty {
    fill: var(--text-secondary);
    font-size: 1.05rem;
}

/* Вкладки и их непрерывный контур стыка с холстом — УНИВЕРСАЛЬНЫЙ компонент:
   styles/module-tabs-row.css + components/module-tabs-boundary.js. Локальных
   стилей вкладок здесь нет (свечение-ореол холста убрано выше — это Fish-специфично). */

/* Управление файлом-диаграммой в верхней панели кнопок (открыть/имя/переименовать/сохранить) */
/* [2026-08-16] Интервал приведён к канону группы панели Documents (`.toolbar-group { gap: 2px }`,
   modules/documents/css/pdf-toolbar.css:26-31) — было 4px, из-за чего файл-контролы стояли
   реже остальных кнопок ряда. Правило `.fish-toolbar-sep` УДАЛЕНО: разделитель в разметке
   заменён каноническим `.toolbar-divider`, класс больше не встречается ни в HTML, ни в JS.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §H. Chat: fish-icons-styles-audit-2026-08-16. */
.fish-diagram-controls {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}
/* ── Read-only (чужой файл): индикатор + гашение инструментов правки; навигация остаётся ── */
/* File access status belongs to the existing bottom path. */
.fish-readonly-banner {
    position: static;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    max-width: 100%;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--color-warning-text);
    font-size: var(--font-size-xs);
    box-shadow: none;
}
/* 3D-хотбар: гасим постановку примитивов + Physics; Walk/Fly (навигация) активны. */
.fish-readonly #fish3dHotbar .hotbar-btn[data-primitive],
.fish-readonly #fish3dPhysicsToggle {
    pointer-events: none;
    opacity: 0.4;
}
/* Верхняя панель: отключённые в read-only кнопки правки тусклые. */
/* [2026-08-16] Селекторы переведены с .btn на .toolbar-btn — панель Fish перешла на канон
   панели Documents. Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §H.
   Chat: fish-icons-styles-audit-2026-08-16. */
/* [2026-10-04] Селектор плавающей панели снят: панель ушла в Slides вместе со «Схемой».
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-readonly .module-controls-row .toolbar-btn:disabled {
    opacity: 0.4;
}

/* Поля Properties остаются читаемыми, но больше не притворяются редактируемыми. */
.geometry-section.is-readonly .input:disabled {
    cursor: not-allowed;
}

.geometry-readonly-note {
    margin: 8px 0 0;
    color: var(--color-warning-text, #e0a020);
    font-size: 12px;
}

/* [2026-10-04] Правила пикера персонажа в хотбаре сняты как мёртвые: хотбар такого выпадающего
   списка не создаёт. Ref: js/__tests__/fishDeadCode.guard.test.js. */

/* ============================================================================
   [2026-08-16] БЛОК ПРИВЕДЕНИЯ К КАНОНУ: классы, которые разметка и JS модуля уже
   использовали, но правил для них не существовало ни в одном подключённом CSS,
   плюс перенос оформления из inline-`style` и из `element.style.*` в таблицу стилей.
   Причина: аудит иконок и стилей Fish в сравнении с модулями PDF/Word.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §E1-§E9.
   Chat: fish-icons-styles-audit-2026-08-16.
   ============================================================================ */

/* [2026-10-04] §E3–§E5 сняты как мёртвые: строка «чекбокс + подпись» (полей с этим классом в окне
   больше нет — профиль кости ушёл в Slides), вкладки и строка «Новая диаграмма» прежнего окна
   «Открыть» (с 0cf63fbd7 — общий браузер Documents). Ref: js/__tests__/fishDeadCode.guard.test.js.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* §E1. Индикатор загрузки списка. Раньше нёс Tailwind-классы `text-gray-400 py-8`,
   которых в проекте нет, — текст оставался без оформления. */
.diagrams-loading {
    color: var(--text-secondary);
    text-align: center;
    padding: var(--space-8) 0;
}

/* §E6. Пустое состояние холста: раньше собиралось восемью `element.style.*` в tabs.js.
   Оформление самого блока берут общие .empty-state / .empty-state-icon / .empty-state-text
   (объявлены выше в этом же файле) — здесь только позиционирование по центру холста. */
.fish-canvas-empty {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    color: var(--text-secondary);
    font-size: var(--font-size-lg);
}

.fish-canvas-empty .empty-state-icon {
    opacity: 0.5;
}

/* §E9. Кнопка «Открыть диаграмму» в панели файла: раньше 11 присваиваний
   `openBtn.style.*` и hover двумя JS-слушателями вместо :hover. */
/* [2026-08-16] УДАЛЕНЫ правила `.fish-open-diagram-btn`: кнопка «Открыть» перешла в общую
   файловую группу панели (`.toolbar-btn.fish-file-btn`) — она единственная была 32 px против
   36 у соседей. Мёртвые правила не оставляем.
   Ref: docs/QA_FISH_OPEN_DIALOG_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16. */

/* Кнопка сохранения файла-диаграммы: «есть несохранённые правки» — состоянием-классом,
   а не присваиванием `saveBtn.style.opacity` из двух разных модулей (tabs.js, saveDiagram.js). */
.module-tab-edit.is-pristine {
    opacity: 0.5;
}

/* §F3/§F4 — пояснение к уровням наложения внутри модуля.
   Значения 5 / 50 / 60 (хотбар, плавающая панель, правая панель, её кнопка) и 1000
   (поповер кости, выпадающее меню шаблонов) намеренно ОСТАВЛЕНЫ вне шкалы --z-*:
   это внутренние слои рабочей области, и все они лежат НИЖЕ системных уровней
   (--z-modal-backdrop 1040, --z-modal 1050, --z-tooltip 1070). Подъём их до токенов
   шкалы поставил бы холст поверх выпадающих меню и модалок. Нарушения шкалы, которые
   реально перекрывали системные слои (10000 у контекстного меню, 4000 у плашки
   read-only), исправлены — см. §F1, §F2. */

/* [2026-08-16] Узкая правая половина составной кнопки «шаблон + стрелка». Раньше её ширина
   задавалась inline-стилем `padding: 8px 6px` в разметке вместе с обнулением радиусов,
   которое и без того делает канонический .btn-group (styles/components.css:222-230).
   Здесь остаётся ТОЛЬКО то, чего нет в общем компоненте, — компактный горизонтальный
   паддинг под одну иконку.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §E7. Chat: fish-icons-styles-audit-2026-08-16. */

/* [2026-10-04] Правила выпадающего меню шаблонов кости сняты: шаблон кости ушёл в Slides вместе со
   «Схемой». Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */

.material-icons.sidebar-section-icon {
    font-size: 20px;
    width: auto;
    height: auto;
}

/* [2026-08-16] Остатки inline-`style` из разметки, перенесённые в таблицу стилей.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §E8. Chat: fish-icons-styles-audit-2026-08-16. */
/* [2026-08-16] УДАЛЕНО правило `.fish-layers-add-row`: строка с заливной кнопкой «Add Layer»
   убрана из тела секции, действие переехало иконкой в заголовок (канон «Pages» в Word).
   Ref: docs/QA_FISH_TO_WORD_ICONS_2026-08-16.md §6. Chat: fish-icons-styles-audit-2026-08-16. */

/* [2026-10-04] Правила кривой профиля и поля масштаба сняты вместе с элементами «Схемы» (Slides).
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-section-placeholder {
    padding: var(--space-4);
    text-align: center;
}

/* ============================================================================
   [2026-08-16] ПАНЕЛЬ ИНСТРУМЕНТОВ FISH = ПАНЕЛЬ МОДУЛЯ DOCUMENTS (PDF/WORD).
   Причина: Fish выглядел чужим — крупные заливные кнопки `.btn btn-primary` /
   `.btn-secondary` / `.btn-danger`, тогда как PDF и Word используют плоскую панель:
   прозрачные кнопки, подсветка на hover, разделители-волоски. (Оговорка про «заливку у
   первичного и опасного действия» СНЯТА 2026-08-16: в разметке Word и PDF заливных кнопок
   панели нет вовсе, см. аннотацию у удалённых правил ниже.) Значения повторяют канон
   modules/documents/css/pdf-toolbar.css:26-82 (.toolbar-group / .toolbar-divider /
   .toolbar-btn), но берут цвета ТОКЕНАМИ, а не литералами вроде #e0e0e0 — сам
   pdf-toolbar.css держит их хардкодом, и копировать этот дефект нельзя (DESIGN.md §15.6).
   Классы объявлены здесь, а не подключением чужого CSS: тянуть 833 строки правил
   PDF-страницы в Fish — недопустимая связность между модулями.
   Ref: docs/AUDIT_FISH_ICONS_STYLES_2026-08-16.md §H.
   Chat: fish-icons-styles-audit-2026-08-16.
   ============================================================================ */

/* Сам ряд панели: канон Documents — `gap: 8px; padding: 8px 16px`
   (modules/documents/css/toolbar.css:8-17). Универсальный `.module-controls-row`
   (styles/header.css:511-521) задаёт `gap: 0.75rem; padding: 1rem 1.5rem` — из-за этого
   интервалы между группами кнопок Fish были шире канона, а сам ряд выше. Переопределяем
   ровно эти два свойства, остальное (sticky, фон, перенос) остаётся от общего компонента. */
/* [2026-08-16] Добавлена нижняя волосяная линия: у `.document-toolbar` она есть
   (modules/documents/css/toolbar.css:16 — `border-bottom: 1px solid var(--border-color)`), а
   панель Fish висела без границы и «сливалась» с холстом — одно из четырёх замеренных отличий
   по замечанию PO «не выглядит как модуль Word».
   Ref: docs/QA_FISH_TO_WORD_ICONS_2026-08-16.md §6. Chat: fish-icons-styles-audit-2026-08-16. */
.fish-toolbar {
    gap: 8px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border-primary);
}

.fish-toolbar .toolbar-group {
    display: flex;
    align-items: center;
    gap: 2px;
    position: relative;
}

.fish-toolbar .toolbar-divider {
    width: 1px;
    height: 24px;
    background: var(--border-primary);
    margin: 0 var(--space-2);
    flex-shrink: 0;
}

.fish-toolbar .toolbar-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px 10px;
    border: none;
    background: transparent;
    border-radius: var(--radius-lg);
    cursor: pointer;
    color: var(--text-primary);
    font-family: var(--font-family);
    font-size: 13px;
    line-height: 1.2;
    white-space: nowrap;
    transition:
        background-color var(--transition-fast),
        color var(--transition-fast);
}

/* Glyph-only commands keep the same target regardless of the SVG's default size. */
.fish-toolbar .toolbar-btn:has(> svg.fish-icon:only-child) {
    box-sizing: border-box;
    width: 34px;
    height: 34px;
    min-width: 34px;
    min-height: 34px;
    padding: 0;
    border-radius: var(--radius-lg);
}

.fish-toolbar .toolbar-btn > svg.fish-icon:only-child {
    width: 20px;
    height: 20px;
}

/* ============================================================================
   [2026-08-16] ОБЩЕЕ ОКНО ОТКРЫТИЯ ФАЙЛОВ — ВЫШЕ ХРОМА СТРАНИЦЫ FISH.

   Дефект пойман браузерным замером, а не на глаз: `elementFromPoint(700, 95)`
   на открытом окне возвращал `.module-controls-row.fish-toolbar`, то есть панель
   инструментов РИСОВАЛАСЬ ПОВЕРХ модалки — заголовок окна с названием и крестиком
   был закрыт кнопками страницы.

   Причина: общий оверлей объявлен с `z-index: 1000`
   (modules/documents/css/document-browser.css:3-10), а хром страницы Fish выше —
   `.module-controls-row` sticky 1019 и универсальная шапка 1030. В Word того же не
   происходит: там панель `position: static` и стекающего контекста не создаёт,
   поэтому дефект и не всплывал до переиспользования окна здесь.

   Правило живёт в fish.css, а не в общем файле: поднимать оверлей глобально —
   менять слои сразу трём модулям без их проверки. Значение берём по шкале
   DESIGN.md §9 (`--z-modal` = 1050 > 1030), а не подбираем число.
   Ref: docs/QA_FISH_OPEN_DIALOG_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16.
   ============================================================================ */
.document-browser-overlay {
    z-index: var(--z-modal);
}

/* [2026-08-16] Файловая группа панели — те же размеры, что у иконочных кнопок Word
   (`.toolbar-btn` 36×28 в замере edoc.html). Отдельный класс нужен только чтобы
   кнопка не растягивалась подписью: она иконочная и всегда одной ширины.
   Ref: docs/QA_FISH_OPEN_DIALOG_2026-08-16.md. Chat: fish-icons-styles-audit-2026-08-16. */
.fish-toolbar .fish-file-btn {
    flex-shrink: 0;
}

/* Кнопка сохранения без несохранённых правок — приглушена (состояние, не стиль из JS). */
.fish-toolbar .fish-file-btn.is-pristine {
    opacity: 0.5;
}

/* ============================================================================
   [2026-08-16] ЗНАЧОК МОДУЛЯ — контурный SVG набора js/fishIcons.js (контракт Word).

   ЗДЕСЬ НАМЕРЕННО НЕТ `color`. Значок рисуется `stroke="currentColor"` и обязан брать
   цвет КНОПКИ: `.fish-toolbar .toolbar-btn { color: var(--text-primary) }` выше,
   `.toolbar-btn.active` — `--brand-primary`, `.toolbar-btn.primary` — `--text-inverse`.
   Стоит назначить значку собственный цвет (`.fish-icon { color: var(--text-secondary) }`) —
   и панель станет бледнее словной при полностью совпавшей геометрии: на этой ошибке уже
   поймали модуль таблиц. Единственное, что нужно значку, — не сжиматься во flex-кнопке
   (ровно как `.toolbar-btn svg` в modules/documents/css/toolbar.css:90-92).

   Ref: docs/DEV_GUIDE_FISH_TO_WORD_CONTRACT_2026-08-16.md §1, §3 шаг 3, §4 (ловушка 2).
   Chat: fish-icons-styles-audit-2026-08-16.
   ============================================================================ */
.fish-icon {
    flex-shrink: 0;
}

.fish-toolbar .toolbar-btn:hover:not(:disabled) {
    background: var(--bg-hover);
}

.fish-toolbar .toolbar-btn:active:not(:disabled) {
    background: var(--bg-tertiary);
}

.fish-toolbar .toolbar-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Состояние-переключатель (напр. включённый режим вставки) — тонированная подложка,
   как `.toolbar-btn.active` в панели PDF. */
.fish-toolbar .toolbar-btn.active {
    background: rgba(var(--brand-primary-rgb), 0.12);
    color: var(--brand-primary-text);
}

/* [2026-08-16] УДАЛЕНЫ правила `.toolbar-btn.primary` и `.toolbar-btn.danger` панели Fish.
   Причина: они вводили в панель заливную синюю кнопку и красный текст «Удалить», которых в
   эталоне НЕТ. Проверено по разметке: `toolbar-btn primary` не встречается ни в `edoc.html`,
   ни в `pdf-viewer.html` (правило `css/pdf-toolbar.css:78` мёртвое), а класса
   `.toolbar-btn.danger` в модуле Documents не существует вовсе. Замер живых страниц: в панели
   Word единственный не-прозрачный фон — тонированная подложка включённого переключателя
   (rgb 227,242,253), то есть то же самое, что даёт `.toolbar-btn.active` ниже.
   Ref: docs/QA_FISH_TO_WORD_ICONS_2026-08-16.md §6. Chat: fish-icons-styles-audit-2026-08-16. */

/* [2026-10-04] Сняты правила составной кнопки шаблона кости, значка типа на схеме, меню объекта, палитры
   типов и габаритной рамки с ручками масштаба: всё это — инструменты «Схемы», ушедшей в Slides.
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
/* Catalog/class files open their own editor, without scene editing controls. */
/* [2026-10-04] Из перечня сняты кнопки «Схемы» (шаблон кости, «Разделить», «Вставить») — их в окне нет.
   Ref: docs/TZ_FISH_REMOVE_SCHEMA_TO_SLIDES_2026-10-03.md §3.3. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-engineering-file #fish-main-container,
.fish-engineering-file #deleteBoneBtn,
.fish-engineering-file #copyBoneBtn,
.fish-engineering-file #undoBtn,
.fish-engineering-file #redoBtn {
    display: none;
}

/* [2026-10-04] Правила полей и карточки прежнего окна выбора позиции класса сняты как мёртвые:
   этих узлов не создаёт ни разметка, ни код окна.
   Ref: js/__tests__/fishDeadCode.guard.test.js. Chat: fish-model-composition-sidebar-section-2026-10-02. */

/* [2026-09-21] Этапы B, C, G, K, U: слои интерфейса 3D по канону Minecraft — хотбар из девяти
   слотов, прицел с подсказкой цели, окно инвентаря строками, выбор соединения, панель состояния
   и подсказки первого входа. Стилей у них не было вовсе (замечание второго мнения 2026-09-21):
   разметка рисовалась, но на экране выглядела неоформленным текстом.
   Токены берутся из styles/themes.css — своих цветов модуль не заводит.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6, §7, §8, §13, §22.
   Chat: fish3d-implementation-2026-09-21. */

/* [2026-09-21] Этап X: панель сцены (Walk/Fly/вид/физика/аватар) уходит из нижней полосы в
   правый верхний угол. Живая приёмка 2026-09-21: она и хотбар слотов стояли в одном месте с
   одинаковым `z-index: 5` — кнопки просвечивали сквозь слоты, полоса не читалась.
   §6 п. 5 ТЗ: хотбар — только слоты, режимные кнопки живут в панели сцены.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5. Chat: fish3d-implementation-2026-09-21. */
/* Панель прижата к ВЕРХУ по центру, а не к правому краю: `#fish3dRoot` шире видимой сцены —
   его правый край уходит под боковую панель, и прижатая вправо панель обрезалась (живая
   приёмка 2026-09-21: из пяти элементов было видно три). По центру она стоит на той же
   оси, что прицел и хотбар, и ни во что не упирается. */
.fish3d-hotbar.fish3d-scene-panel {
    bottom: auto;
    top: var(--space-4, 16px);
    /* [2026-09-22] Панель ПЕРЕНОСИТ элементы, а не уезжает под боковую панель. Живая проверка
       2026-09-22 в открытом окне: ширина панели 968 px при видимой сцене 1163 px и центре на
       оси 761 — правый край панели (1245) уходил ПОД панель слоёв, и вход в настройки
       управления (§14 п. 7) на экране был недостижим мышью. Это тот же дефект, что поймала
       живая приёмка 2026-09-21 («из пяти элементов было видно три»): панель с тех пор выросла
       на отклик, скорость и управление, и центрирования перестало хватать.
       Потолок ширины — доля видимой области, а не константа: сцена шире окна, и точного числа
       у CSS нет. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §22.1. */
    flex-wrap: wrap;
    justify-content: center;
    max-width: min(700px, 62%);
}

/* [2026-09-22] Этап AP: обёртка интерфейса сцены — её и прячет `F1` (§5, критерий M15).
   Живая приёмка 2026-09-22: `F1` не прятал ничего, потому что прятать было нечего — элемента
   `#fish3dHud` в странице не существовало. Обёртка лежит поверх холста, сама кликов не ловит
   (`pointer-events: none`), а её содержимое ловит: иначе прозрачный слой во весь экран забрал
   бы у сцены и постановку, и вращение камеры.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §13, M15. Chat: fish3d-implementation-2026-09-21. */
.fish3dHud {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
}
.fish3dHud > * {
    pointer-events: auto;
}
/* [2026-09-22] Этап AS. ЖИВОЙ ДЕФЕКТ, найденный в открытом окне: мышь в сцене перестала
   работать совсем — ПКМ не ставила изделие, ЛКМ не удаляла, СКМ не брала образец, камера не
   вращалась. Причина по каскаду: слой значков проникновений — прямой ребёнок обёртки и лежит
   во весь экран (`inset: 0`), а правило выше (0,1,1) перебивало его собственное
   `pointer-events: none` (0,1,0). Прозрачный слой во весь экран забирал у сцены ВСЕ нажатия —
   ровно то, чем предостерегает комментарий к обёртке. Метки внутри слоя кликабельны своим
   правилом `.fish3d-penetration-marker`, поэтому §9.2bis не страдает.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §9.2bis, M15. Chat: fish3d-implementation-2026-09-21. */
.fish3dHud > .fish3d-penetration-layer,
.fish3dHud > .fish3d-action-markers,
.fish3dHud > .fish3dCrosshairLayer,
.fish3dHud > .fish3dHintsLayer {
    pointer-events: none;
}
.fish3dHud.hidden {
    display: none;
}
/* Pause sits above the editor sidebar. Only its own HUD layer stays visible;
   the world canvas remains visible below, without the gameplay hint, cue or
   hotbar printing through the pause title and commands. Keep these rules after
   the base HUD rules so both browser and CSS checks use the same cascade. */
.fish3dHud.fish3d-pause-open {
    z-index: 51;
}
.fish3dHud.fish3d-pause-open > :not(#fish3dPauseLayer) {
    visibility: hidden;
    pointer-events: none;
}

.fish3dSlots {
    position: absolute;
    bottom: var(--space-4, 16px);
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    justify-content: center;
    width: min(608px, calc(100% - 24px));
    gap: 4px;
    z-index: 5;
    pointer-events: auto;
}
/* The root spans the sidebar too. The hotbar belongs to the playable scene,
   not to the obscured center of the whole page. */
/* [2026-10-03] 340 → переменная ширины панели (тянется за край): хотбар держится центра
   видимой сцены при любой ширине. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-main-container:not(.right-sidebar-collapsed) .fish3dSlots {
    left: calc((100% - var(--fish-right-sidebar-width, 340px)) / 2);
    width: min(608px, calc(100% - var(--fish-right-sidebar-width, 340px) - 24px));
}

/* The equipped item stays in view when the placement ray has no ground hit.  It is a
   decorative projection of the same geometry used by the catalogue thumbnail, not a
   second interactive tool; the scene underneath must keep receiving mouse gestures. */
.fish3dHud > .fish3d-held-item {
    position: absolute;
    left: min(calc(50% + 250px), calc(100% - 172px));
    /* [2026-10-04] Рука в 1-м лице, как в Minecraft: внизу справа видимой сцены, сразу над правым
       краем хотбара (хотбар занимает почти всю ширину видимой сцены — ниже картинка легла бы на
       его слоты), а не высоко над строкой подсказок, как раньше (её поднимала высота подсказок).
       Картинка видна только в 1-м лице (Fish3DUi syncHeldItemPreview).
       Ref: docs/PROPOSAL_FISH_HELD_ITEM_MINECRAFT_2026-10-04.md §4 п. 2. Chat: fish-model-composition-sidebar-section-2026-10-02. */
    bottom: 104px;
    width: 144px;
    height: 144px;
    z-index: 4;
    pointer-events: none;
    transform: rotate(-9deg);
    filter: drop-shadow(0 8px 8px rgb(0 0 0 / 0.45));
}
/* The HUD spans the full page, but an expanded properties sidebar owns its right 340px.
   Position the equipped item against the scene edge just like the action cue below it;
   otherwise most of the item is painted behind the sidebar on desktop. */
@media (min-width: 1101px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHud > .fish3d-held-item {
        left: auto;
        /* [2026-10-03] 340 → переменная ширины панели. Chat: fish-model-composition-sidebar-section-2026-10-02. */
        right: calc(var(--fish-right-sidebar-width, 340px) + 24px);
    }
}
.fish3d-held-item[hidden] {
    display: none;
}

.fish3d-held-item > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.fish3d-held-item > img[hidden],
.fish3d-held-item-fallback[hidden] {
    display: none;
}

.fish3d-held-item-fallback {
    box-sizing: border-box;
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    padding: 12px;
    border: 1px dashed var(--fish3d-hud-border, #6b7280);
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-bg, rgb(20 24 28 / 0.82));
    color: var(--fish3d-hud-text, #e5e7eb);
    font-size: 12px;
    line-height: 1.3;
    text-align: center;
    transform: rotate(9deg);
}

@media (max-width: 1100px) {
    /* [2026-10-29] left: 24px → у правой кромки видимой сцены, как велит §4 п. 2 предложения («прижата к правой
       кромке видимой сцены… сразу над правым краем хотбара») и как уже стоит на широком экране. У левого края растёт
       столбец подсказок действий, и предмет ложился на строку «Строить: В руке…» (живой замер 780px,
       e2e/fish-narrow-320-live.cjs). Ref: docs/PROPOSAL_FISH_HELD_ITEM_MINECRAFT_2026-10-04.md §4 п. 2.
       Chat: hp-remaining-six-2026-10-28. */
    .fish3dHud > .fish3d-held-item {
        left: auto;
        right: 24px;
        /* [2026-10-04] Высота подсказок больше не задаёт положение (переменная снята) — над хотбаром.
           Ref: docs/PROPOSAL_FISH_HELD_ITEM_MINECRAFT_2026-10-04.md §4 п. 2. */
        bottom: 104px;
        width: 108px;
        height: 108px;
    }
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHud > .fish3d-held-item {
        right: calc(var(--fish-right-sidebar-width, 340px) + 24px);
    }
    /* Столбец подсказок не заходит под предмет: справа оставлена его ширина и зазор (§4 п. 2 — «миниатюра не
       перекрывает … строку подсказок»). */
    .fish3dHud:has(> .fish3d-held-item:not([hidden])) .fish3d-action-cue {
        max-width: calc(100% - 24px - 108px - 24px);
    }
}
@media (max-width: 480px) {
    .fish3dHud > .fish3d-held-item {
        width: 72px;
        height: 72px;
    }
    .fish3dHud:has(> .fish3d-held-item:not([hidden])) .fish3d-action-cue {
        max-width: calc(100% - 24px - 72px - 24px);
    }
}
/* The expanded composition disclosure occupies the lower-left scene. Keep the
   equipped item visible instead of painting it behind the interactive panel.
   Between 960–1100px it fits beside the panel and before the 340px sidebar;
   below that it uses the clear strip above the disclosure. */
@media (min-width: 960px) and (max-width: 1100px) {
    /* At this desktop width the right sidebar still occupies 340px. The generic
       left:24px rule puts the equipped item over the orientation axes; keep it
       beside the sidebar and below the top-center navigation cue instead. */
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHud > .fish3d-held-item {
        /* [2026-10-03] 340 → переменная ширины панели. Chat: fish-model-composition-sidebar-section-2026-10-02. */
        left: calc(100% - var(--fish-right-sidebar-width, 340px) - 144px);
        /* [2026-10-04] Над хотбаром без переменной высоты подсказок. Ref: docs/PROPOSAL_FISH_HELD_ITEM_MINECRAFT_2026-10-04.md §4 п. 2. */
        bottom: 104px;
        width: 96px;
        height: 96px;
    }
    #fish3dRoot:has(> #fishModelComposition[open]) .fish3dHud > .fish3d-held-item {
        left: 488px;
    }
}
@media (max-width: 959px) {
    #fish3dRoot:has(> #fishModelComposition[open]) .fish3dHud > .fish3d-held-item {
        /* [2026-10-03] 340 → переменная ширины панели. Chat: fish-model-composition-sidebar-section-2026-10-02. */
        left: clamp(36px, calc(100% - var(--fish-right-sidebar-width, 340px) - 132px), 160px);
        top: 8px;
        bottom: auto;
    }
}
@media (max-width: 500px) {
    #fish3dRoot:has(> #fishModelComposition[open]) .fish3dHud > .fish3d-held-item {
        width: 84px;
        height: 84px;
    }
}

/* Текущий предмет и применимые кнопки остаются видимыми после того, как закрылась
   стартовая памятка. Это отдельный слой над хотбаром: он не перехватывает клик и не мешает
   смене слота. */
.fish3dActionCueLayer {
    position: absolute;
    right: 0;
    /* [2026-10-29] + ряд строки действия: по решению PO 2026-10-29 над хотбаром по центру стоит
       строка действия цели (`.fish3d-crosshair-actions`, высота 36px, снизу ровно на прежней высоте
       столбца). Столбец подсказок клавиш поднят на её ряд (36px + 8px зазор) постоянно, а не по
       появлению цели — иначе он прыгал бы при каждом наведении. Строка не ложится на подсказки.
       Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. Chat: hp-remaining-six-2026-10-28. */
    bottom: calc(64px + var(--space-6, 24px) + var(--fish3d-action-bar-row, 44px));
    left: 0;
    z-index: 5;
    pointer-events: none;
}

/* [2026-10-03] ПАНЕЛЬ ПОДСКАЗОК — ВЕРТИКАЛЬНО У ЛЕВОГО КРАЯ СЦЕНЫ, БЕЗ ПЛАШКИ (приказ PO со
   снимком: «сделай панель подсказок вертикально и чтобы у неё был прозрачный фон»). Прежде —
   широкая полоса по центру над хотбаром с тёмной подложкой и рамкой, которая закрывала аватар и
   сцену. Теперь столбец: заголовок инструмента, статусы режима, ниже по одной подсказке
   «колпачок — действие» в строке; фон и рамка прозрачны, читаемость держат колпачки клавиш со
   своей подложкой. Столбец растёт вверх от хотбара (слой прижат к низу), левый край сцены не
   занят ничем, кроме знака осей наверху.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §14 п. 1.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish3d-action-cue {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    width: fit-content;
    max-width: calc(100% - 24px);
    margin: 0 0 0 var(--space-4);
    padding: 0;
    border: 0;
    background: transparent;
    /* [2026-10-03] Подложки нет — подпись стоит прямо на сцене, а фон сцены берётся у темы
       (Fish3D.js sceneBackgroundColor). Светлый текст HUD (--fish3d-hud-text рассчитан на тёмную
       плашку §22.1) на светлой сцене не читался (снимок 2026-10-03, светлая тема). Цвет подписи —
       цвет текста темы; колпачки клавиш остаются тёмными плашками HUD.
       Chat: fish-model-composition-sidebar-section-2026-10-02. */
    color: var(--text-primary);
    font-size: 13px;
    line-height: 1.3;
    text-align: start;
}
#fish3dActionCue .fish3d-kbd-sep,
#fish3dActionCue .fish3d-kbd-text {
    color: color-mix(in srgb, var(--text-primary) 60%, transparent);
}
/* Подписи действий («поставить», «инвентарь») — тоже цветом текста темы, а не светлым HUD. */
#fish3dActionCue .fish3d-key-hint-action {
    color: inherit;
}

.fish3d-action-cue-preview {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    object-fit: contain;
    border: 1px solid color-mix(in srgb, var(--fish3d-hud-border, #6b7280) 55%, transparent);
    border-radius: 3px;
    background: color-mix(in srgb, var(--fish3d-hud-bg, #111827) 75%, transparent);
}

.fish3d-action-cue-preview-status {
    max-width: 12rem;
    padding: 3px 6px;
    border: 1px dashed color-mix(in srgb, var(--fish3d-hud-text-active, #e5e7eb) 45%, transparent);
    border-radius: 3px;
    color: var(--fish3d-hud-text-active, #e5e7eb);
    font-size: 0.75rem;
    line-height: 1.2;
}

.fish3d-action-cue-title {
    font-weight: 600;
}

/* [2026-10-03] Строка заголовка общей подсказки: название инструмента и статусы режима
   («Ходьба · От третьего лица: сзади»), которые прежде стояли отдельной плашкой наверху сцены
   (замечание PO со снимком: «почему эта подсказка наверху и не вместе с общей подсказкой?»).
   Статус — приглушённым цветом HUD, через точку-разделитель после названия.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §6 п. 5.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
/* [2026-10-03] В вертикальной панели заголовок и статусы — двумя строками друг под другом,
   разделитель-точка не нужна. Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish3d-action-cue-head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    margin-bottom: var(--space-1);
}
.fish3d-action-cue-head .fish3d-scene-status {
    /* [2026-10-03] Статус на прозрачной панели — приглушённый цвет текста темы (см. .fish3d-action-cue). */
    color: color-mix(in srgb, var(--text-primary) 65%, transparent);
    font-weight: 400;
    white-space: nowrap;
}
/* Верхняя плашка сцены опустела: «Esc — меню» стоит в строке колпачков общей подсказки, статусы
   переехали в её заголовок. Узел остаётся в разметке (его ищут обработчики), но не показывается. */
.fish3d-hotbar.fish3d-scene-panel {
    display: none;
}

/* Короткий результат точной правки: центральный прицел в keyboard Edit скрыт, поэтому
 * подтверждение Q/E, сдвига или другого действия должно остаться возле выбранной детали. */
.fish3d-action-cue-status {
    flex: 0 0 100%;
    color: var(--fish3d-hud-text-active, #e5e7eb);
    font-weight: 600;
    text-align: center;
}

#fish3dActionCue .fish3d-action-cue-status {
    text-align: start;
}
.fish3d-action-cue-controls {
    opacity: 1;
}

/* [2026-10-02] Знак осей easy3D в 3D Fish (modules/easy3d/js/render/view-gizmo.js): левый верхний
   угол сцены, где стоял прежний гизмо. Только указатель — щелчки проходят к сцене.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §14 п. 1.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dRoot .easy3d-view-gizmo {
    position: absolute;
    top: var(--space-2);
    left: var(--space-2);
    z-index: 2;
    /* Размер знака easy3D (calc(--space-20 + --space-5) = 100px): при 76px буквы в кружках
       становились мельче 9px (замер в окне 2026-10-02). */
    width: calc(var(--space-20) + var(--space-5));
    height: calc(var(--space-20) + var(--space-5));
    pointer-events: none;
}
#fish3dRoot .easy3d-view-gizmo canvas {
    display: block;
    width: 100%;
    height: 100%;
}
.fish-main-container.fish3d-ui-hidden #fish3dRoot .easy3d-view-gizmo {
    display: none;
}

/* [2026-10-02] Подсказки управления — колпачками клавиш и кнопок мыши (keycaps.js), а не
   сухой строкой (замечание PO со снимком). Колпачок — HUD-токены, нижняя кромка толще, как у
   настоящей клавиши; кнопка мыши — со значком мыши. Группа «колпачки + действие» не рвётся.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §14 п. 1.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish3d-action-cue-controls,
#fish3dSceneHint {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 4px 12px;
}
.fish3d-key-hint {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
}
.fish3d-key-hint-keys {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}
/* [2026-10-03] Вертикальная панель подсказок (приказ PO): колпачки — первой колонкой, прижаты
   вправо к подписи; подписи действий — второй колонкой, ровно друг под другом (снимок 2026-10-03:
   подписи «гуляли» по ширине колпачков). Правила стоят ПОСЛЕ общих `.fish3d-action-cue-controls`
   и `.fish3d-key-hint`, чтобы перекрывать их и по весу, и по порядку.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
#fish3dActionCue .fish3d-action-cue-controls {
    display: grid;
    grid-template-columns: max-content auto;
    align-items: center;
    gap: var(--space-1) var(--space-2);
}
#fish3dActionCue .fish3d-key-hint {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: center;
}
#fish3dActionCue .fish3d-key-hint-keys {
    justify-self: end;
}
.fish3d-kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    box-sizing: border-box;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    border: 1px solid var(--fish3d-hud-border, rgba(255, 255, 255, 0.18));
    border-bottom-width: 2px;
    border-radius: 4px;
    background: var(--fish3d-hud-control-bg, #2a2f36);
    color: var(--fish3d-hud-text, #e5e7eb);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
}
.fish3d-kbd-mouse .fish-icon {
    flex-shrink: 0;
}
.fish3d-kbd-sep,
.fish3d-kbd-text {
    color: var(--fish3d-hud-muted, #cbd5e1);
    font-size: 11px;
}
.fish3d-key-hint-action {
    margin-inline-start: 3px;
    color: var(--fish3d-hud-text, #e5e7eb);
}
.fish3d-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Редкие команды Build остаются в доступном описании, но не раздувают HUD поверх сцены. */
.fish3d-action-cue-controls-full {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* В режиме правки длинная строка действий выбираемого компонента раньше центрировалась по
   ВСЕМУ #fish3dRoot (1024px), хотя правые 340px заняты свойствами. Поэтому часть текста
   оказывалась под сайдбаром и выглядела как пропавшая команда. На desktop центрируем cue в
   фактически видимой сцене; свёрнутый сайдбар возвращает всю ширину без JS-перерасчёта. */
/* [2026-10-03] 340 → переменная ширины панели (тянется за край). Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-main-container:not(.right-sidebar-collapsed) .fish3dActionCueLayer {
    right: var(--fish-right-sidebar-width, 340px);
}

@media (max-width: 720px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dActionCueLayer {
        right: var(--fish-right-sidebar-width, 340px);
    }
    .fish-main-container:not(.right-sidebar-collapsed) .fish3d-action-cue {
        max-height: 160px;
        overflow-y: auto;
        overscroll-behavior: contain;
        pointer-events: auto;
        scrollbar-width: thin;
    }
}

@media (max-width: 600px) {
    .fish3dActionCueLayer {
        /* [2026-10-29] + ряд строки действия (см. базовое правило). Chat: hp-remaining-six-2026-10-28. */
        bottom: calc(64px + var(--space-8, 32px) + var(--fish3d-action-bar-row, 44px));
    }
}

.fish3d-slot {
    width: 64px;
    height: 64px;
    flex: 1 1 0;
    min-width: 0;
    max-width: 64px;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding: 4px;
    /* [2026-09-22] §22.1 «Тёмный HUD в обеих темах»: слот берёт СВОИ токены HUD, а не общие
       `--bg-secondary`/`--text-primary`. Живая проверка 2026-09-22 в открытом окне: при светлой
       теме панель сцены осталась тёмной, а слоты хотбара стали белыми (измерено:
       rgb(248,250,252) при токене HUD rgba(20,24,28,0.82)) — ровно то расхождение с эталоном,
       которое §22.1 запрещает. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. */
    border: 2px solid var(--fish3d-hud-border);
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    cursor: pointer;
    transition:
        border-color 120ms ease,
        transform 120ms ease;
}

/* Слоты — нативные buttons ради Tab и ассистивных технологий, но не должны получить белый
   браузерный вид или системный шрифт поверх тёмного игрового HUD. */
button.fish3d-slot {
    appearance: none;
    font: inherit;
    text-align: left;
}

button.fish3d-slot:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}

.fish3d-slot.active {
    border-color: var(--primary-color, #60a5fa);
    transform: translateY(-4px);
}

.fish3d-slot.empty .fish3d-slot-title {
    opacity: 0.35;
}

.fish3d-slot-number {
    position: absolute;
    top: 3px;
    left: 4px;
    z-index: 1;
    font-size: 11px;
    opacity: 0.7;
}

/* Two identical silhouettes and NPS labels can represent different class revisions.
   Keep the revision visible at the opposite corner from the slot number in both hotbars. */
.fish3d-slot-revision,
.fish3d-inventory-slot-revision {
    position: absolute;
    top: 3px;
    right: 3px;
    z-index: 1;
    max-width: calc(100% - 22px);
    overflow: hidden;
    padding: 1px 3px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 3px;
    background: rgba(20, 24, 28, 0.96);
    color: var(--fish3d-hud-text);
    font-size: 10px;
    font-weight: 700;
    line-height: 12px;
    pointer-events: none;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* [2026-09-22] Этап AS §6 п. 5: КАРТИНКА ИЗДЕЛИЯ В СЛОТЕ. Поймано PO на экране 2026-09-22:
   слот 1 заряжен трубой и показывал одно слово «Pipe». Картинка занимает середину ячейки между
   номером и подписью; `min-height: 0` обязателен — иначе картинка в колоночном flex не даёт
   ячейке ужаться и выдавливает подпись за край.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6 п. 5, §7 п. 4. */
.fish3d-slot-thumb {
    flex: 0 0 38px;
    height: 38px;
    width: 100%;
    object-fit: contain;
}

.fish3d-slot-title {
    width: 100%;
    font-size: 11px;
    line-height: 12px;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* At a scene width below 452px, nine 44px targets no longer fit. Keep a
   readable rail inside the scene and let mouse/trackpad/keyboard reach the
   remaining slots without painting them under the properties sidebar. */
@media (max-width: 791px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dSlots {
        bottom: 8px;
        justify-content: flex-start;
        overflow-x: scroll;
        overflow-y: hidden;
        padding: 6px 0 4px;
        scrollbar-width: thin;
        scrollbar-color: var(--fish3d-hud-border) transparent;
    }
    /* [2026-10-29] 44px → настольные 64px: лента прокручивается, а в 44px подпись типоразмера обрезалась
       («Сфера», «NPS 1 1/4», «NPS 20» — живой замер e2e/fish-narrow-320-live.cjs). Ref: ТЗ
       docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6, §22. Chat: hp-remaining-six-2026-10-28. */
    .fish-main-container:not(.right-sidebar-collapsed) .fish3d-slot {
        flex: 0 0 64px;
        max-width: none;
    }
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dActionCueLayer {
        /* [2026-10-29] + ряд строки действия (см. базовое правило). Chat: hp-remaining-six-2026-10-28. */
        bottom: calc(100px + var(--fish3d-action-bar-row, 44px));
    }
}

/* [2026-10-29] Та же лента при свёрнутой панели: сцена во всю ширину окна уже 452px (телефон 320–451) не вмещает
   девять ячеек по 44px, и они сжимались до ~32px — подпись типоразмера читалась «N…», мишень была меньше 44px
   (живой прогон 9, снимок self-dark-320). Подпись слота — краткое обозначение (ТЗ §6 п. 5, таблица слота),
   поверхности HUD — «крупные читаемые подписи» (§22). Лента прокручивается, поэтому ячейка сохраняет настольные
   64px: в 44px живой замер 2026-10-29 (e2e/fish-narrow-320-live.cjs) обрезал «Сфера», «NPS 1 1/4», «NPS 20».
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §6, §22; docs/QA_UI_CANON_HP_HANDOFF_2026-10-24.md F2.
   Chat: hp-remaining-six-2026-10-28. */
@media (max-width: 451px) {
    .fish3dSlots {
        bottom: 8px;
        justify-content: flex-start;
        overflow-x: scroll;
        overflow-y: hidden;
        padding: 6px 0 4px;
        scrollbar-width: thin;
        scrollbar-color: var(--fish3d-hud-border) transparent;
    }
    .fish3d-slot {
        flex: 0 0 64px;
        max-width: none;
    }
    .fish3dActionCueLayer {
        /* [2026-10-29] + ряд строки действия (см. базовое правило). Chat: hp-remaining-six-2026-10-28. */
        bottom: calc(100px + var(--fish3d-action-bar-row, 44px));
    }
}

.fish3dCrosshairLayer {
    position: absolute;
    inset: 0;
    right: auto;
    width: var(--fish3d-playable-width, 100%);
    pointer-events: none;
    /* [2026-10-29] 4 → 5: строка действия над хотбаром стоит на высоте «предмета в руке»
       (`.fish3d-held-item`, z-index 4, создаётся позже в DOM). В узком окне они сходятся по
       горизонтали, и поле с кнопками оказывалось под картинкой руки. Как в Minecraft, HUD — над рукой.
       Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. Chat: hp-remaining-six-2026-10-28. */
    z-index: 5;
}

.fish3d-crosshair {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 14px;
    height: 14px;
    margin: -7px 0 0 -7px;
    background:
        linear-gradient(var(--text-primary, #e5e7eb), var(--text-primary, #e5e7eb)) center/2px 100% no-repeat,
        linear-gradient(var(--text-primary, #e5e7eb), var(--text-primary, #e5e7eb)) center/100% 2px no-repeat;
    opacity: 0.8;
    mix-blend-mode: difference;
}

/* §8 п. 3: цель дальше дальности руки — прицел погашен, но не исчезает. */
.fish3d-crosshair.out-of-reach {
    opacity: 0.28;
}

/* Edit с мышью использует обычный курсор. Кольцо появляется только с контроллером: A выбирает
   компонент лучом из центра камеры, поэтому игровой крест Build заменён нейтральным указателем. */
.fish3d-crosshair.controller-target {
    width: 18px;
    height: 18px;
    margin: -9px 0 0 -9px;
    border: 2px solid var(--text-primary, #e5e7eb);
    border-radius: 50%;
    background: none;
    opacity: 0.9;
}

/* [2026-10-29] Вид от третьего лица (сзади и спереди): креста нет, как F5 в Minecraft; в первом
   лице он остаётся. Гаснет только рисунок — луч цели, паспорт и строка действия работают
   (Crosshair.js setThirdPerson, класс ставит Fish3DUi.js syncCrosshairView по показанному виду).
   Слово PO «делай» 2026-10-29. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1.
   Chat: hp-remaining-six-2026-10-28. */
.fish3d-crosshair.third-person {
    display: none;
}

/* [2026-10-29] Подсказка цели больше не центрируется под прицелом, а прижимается к прицелу
   СПРАВА от столбца тела. В виде от третьего лица (вид ходьбы по умолчанию, и в него же
   переключает работа с задвижкой и лестницей) камера стоит строго за аватаром или перед ним
   без бокового сдвига (fish3dWalk.js playerCameraPose), поэтому тело всегда занимает узкий
   вертикальный столбец по центру сцены. Центрированная плашка на 50% + 18px ложилась ровно на
   торс и руки на перилах, а у участника read-only — на ноги (снимки PO 2026-10-29
   .qa-artifacts/stairs-client-planner-20261029/zh12-left-ascend.png, stairs-zh15-20261029/
   zh15-left-ascend-owner.png; замечание PO 2026-10-22 «карточка цели закрывает аватар»).
   Строка по-прежнему «под прицелом» (верх на 18px ниже креста, §22.1) и не уходит к краю
   экрана, но левая кромка отступает от оси на ширину тела: ширина аватара на экране
   пропорциональна высоте сцены (вертикальный угол камеры постоянен), отсюда отступ в vh с
   запасом. Положение одно для первого и третьего лица — плашка не прыгает по F5.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §8 п. 2, §22.1 «центр экрана свободен».
   Chat: hp-remaining-six-2026-10-28. */
/* [2026-10-29] ЗАМЕНЕНО решением PO того же дня (слово «делай» на предложение по канону Minecraft):
   под прицелом карточки нет ВООБЩЕ, ни по центру, ни сбоку от тела. Сдвиг вправо (выше) снят.
   1. Паспорт цели (что это, класс, размер, «до цели N мм», «Элемент доступа · …») — плашкой
      ВВЕРХУ ПО ЦЕНТРУ сцены, как мод Jade/WAILA: `.fish3d-crosshair-passport`.
   2. Подсказка действия, поле размера, «Изменить», «Точная правка»/«Осмотреть компонент», статусы
      действия («Подход к арматуре», «Привод в работе · ПКМ — отпустить») — СТРОКОЙ НАД ХОТБАРОМ
      по центру, как строка действия Minecraft: `.fish3d-crosshair-actions`. Высота строки
      постоянна, под неё зарезервирован ряд между хотбаром и столбцом подсказок клавиш
      (`.fish3dActionCueLayer` поднят на `--fish3d-action-bar-row`) — строка не ложится ни на
      слоты, ни на подсказки, и столбец подсказок не прыгает при появлении цели.
   3. Общий узел `.fish3d-crosshair-hint` (id, классы hidden/denied, текст для F3 и живых прогонов)
      собственной коробки не рисует (`display: contents`): обе полосы позиционируются от слоя
      прицела, а слой равен видимой сцене (`--fish3d-playable-width`) — правило 962ed732a
      «действия не под правой панелью» соблюдено, центр — центр видимой сцены.
   Центр сцены и тело аватара свободны в любом виде. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md
   §8 п. 2, §22.1 (строка «Края, а не центр», замена словом PO 2026-10-29). Chat: hp-remaining-six-2026-10-28. */
.fish3d-crosshair-hint {
    display: contents;
}
.fish3d-crosshair-passport,
.fish3d-crosshair-actions {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    box-sizing: border-box;
    width: max-content;
    /* `show()` собирает строку и отдельные интерактивные поля/кнопки. Без flex-gap браузер
       рисовал их вплотную (`…1258 ммТочная правка`), и команда выглядела частью измерения. */
    display: flex;
    align-items: center;
    gap: 6px;
    border-radius: var(--radius-sm, 4px);
    font-size: 12px;
}
/* Пустая полоса скрыта. Правило стоит ПОСЛЕ `display: flex` полос: так оно выигрывает и по
   специфичности, и по порядку (jsdom проверок видимости считает каскад порядком). */
.fish3d-crosshair-hint.hidden,
.fish3d-crosshair-passport.hidden,
.fish3d-crosshair-actions.hidden {
    display: none;
}
/* [2026-10-30] Паспорт ложился на знак осей и на открытую карточку F3 в левом верхнем углу (живой прогон
   2026-10-29, .qa-artifacts/feet-hands-card-20261029/zh12-left-ascend.png: «Элемент доступа · QA-STAIRS · Марш
   лес…» поверх F3). Плашка центрируется в СВОБОДНОМ пролёте верхней кромки, а не во всей ширине:
   - по умолчанию с каждой стороны оставлен запас знака осей — 116px = отступ `--space-2` (8px) + знак
     `--space-20` + `--space-5` (100px, `#fish3dRoot .easy3d-view-gizmo`) + зазор 8px; симметрично, плашка
     остаётся по центру сцены;
   - при открытой F3 запасы и верх задаёт Fish3DUi.js (`passportSafeArea`, debugSafeArea.js): справа от карточки,
     когда там не меньше 280px, иначе под карточкой;
   - в узком окне запас знака не оставляет места тексту — плашка встаёт под знаком осей во всю ширину (ниже).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. Chat: hp-remaining-six-2026-10-28. */
.fish3d-crosshair-passport {
    --fish3d-passport-reserve: 116px;
    --fish3d-passport-top-default: var(--space-3, 12px);
    top: var(--fish3d-passport-top, var(--fish3d-passport-top-default, 12px));
    left: calc(
        (
                100% + var(--fish3d-passport-left, var(--fish3d-passport-reserve, 116px)) -
                    var(--fish3d-passport-right, var(--fish3d-passport-reserve, 116px))
            ) /
            2
    );
    max-width: min(
        640px,
        calc(
            100% - var(--fish3d-passport-left, var(--fish3d-passport-reserve, 116px)) -
                var(--fish3d-passport-right, var(--fish3d-passport-reserve, 116px))
        )
    );
    flex-wrap: wrap;
    justify-content: center;
    white-space: normal;
    text-align: center;
    /* Паспорт — только текст: клики идут в сцену сквозь него. */
    pointer-events: none;
}
.fish3d-crosshair-actions {
    bottom: calc(64px + var(--space-6, 24px));
    height: 36px;
    /* Полуширина меньше отступа «предмета в руке» от центра (50% + 250px): строка не заходит под руку. */
    max-width: min(460px, calc(100% - 24px));
    flex-wrap: nowrap;
    white-space: nowrap;
    /* Сам слой прицела прозрачен для мыши, чтобы не закрывать сцену. Но поле точного
       размера и «Изменить» в строке действия — настоящие элементы управления: без явного
       auto они наследуют `pointer-events: none`, визуально есть, но клик человека не доходит. */
    pointer-events: auto;
}
/* Строка не растёт в высоту: длинный статус обрезается многоточием, органы управления не сжимаются. */
.fish3d-crosshair-action-text,
.fish3d-crosshair-edit-status {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fish3d-crosshair-actions > .fish3d-crosshair-size,
.fish3d-crosshair-actions > .fish3d-crosshair-edit,
.fish3d-crosshair-actions > .fish3d-crosshair-inspect {
    flex: 0 0 auto;
}

.fish3d-crosshair-hint.denied .fish3d-crosshair-action-text {
    color: var(--color-warning-text, #fbbf24);
}

/* [2026-10-02] Поле размера и кнопки подсказки цели были браузерными по умолчанию — белое поле
   и серые кнопки чужого стиля на тёмной плашке (снимок и замечание PO «не соответствует стилю
   Исикавы»). Теперь это органы HUD модуля: плашка — HUD-фон с рамкой, как подсказка действий;
   поле и кнопки — токены HUD-управления, высота 26 px, скругление `--radius-sm`; главное действие
   (применить размер) отмечено акцентом, переход к правке — вторичная кнопка. Текст отказа
   по-прежнему цветом предупреждения.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §8 п. 2, §22.1.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
/* [2026-10-29] Плашку рисуют теперь обе полосы (паспорт вверху и строка действия над хотбаром),
   а общий узел `.fish3d-crosshair-hint` коробки не имеет. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md
   §22.1. Chat: hp-remaining-six-2026-10-28. */
.fish3d-crosshair-passport,
.fish3d-crosshair-actions {
    padding: 4px 8px;
    border: 1px solid color-mix(in srgb, var(--fish3d-hud-border, #6b7280) 70%, transparent);
    background: var(--fish3d-hud-bg, rgba(20, 24, 28, 0.82));
    color: var(--fish3d-hud-text, #e5e7eb);
}
.fish3d-crosshair-size,
.fish3d-crosshair-edit,
.fish3d-crosshair-inspect {
    box-sizing: border-box;
    height: 26px;
    border: 1px solid var(--fish3d-hud-border, rgba(255, 255, 255, 0.18));
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-control-bg, #2a2f36);
    color: var(--fish3d-hud-text, #e5e7eb);
    font: inherit;
    font-size: 12px;
}
.fish3d-crosshair-size {
    width: 84px;
    padding: 0 6px;
    text-align: right;
}
.fish3d-crosshair-size:focus-visible,
.fish3d-crosshair-edit:focus-visible,
.fish3d-crosshair-inspect:focus-visible {
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}
.fish3d-crosshair-edit,
.fish3d-crosshair-inspect {
    padding: 0 10px;
    font-weight: 600;
    cursor: pointer;
}
.fish3d-crosshair-edit {
    border-color: var(--fish3d-hud-accent, #60a5fa);
    color: var(--fish3d-hud-accent, #60a5fa);
}
.fish3d-crosshair-edit:hover:not(:disabled),
.fish3d-crosshair-inspect:hover:not(:disabled) {
    background: color-mix(in srgb, var(--fish3d-hud-control-bg, #2a2f36) 80%, #fff);
}
.fish3d-crosshair-edit:disabled,
.fish3d-crosshair-size:disabled {
    opacity: 0.5;
    cursor: progress;
}

/* Правая панель перекрывает часть WebGL-холста, но прицел по-прежнему смотрит в
   геометрический центр камеры. Длинный паспорт цели раньше центрировался по всему холсту,
   поэтому его кнопка «Точная правка» оказывалась под панелью и выглядела живой, хотя клик
   получали свойства. В открытом состоянии держим ПОДСКАЗКУ (не сам прицел) в видимой рабочей
   области и разрешаем строке перенестись: все действия остаются видимы и доступны мышью. */
/* [2026-10-29] Отдельное правило открытой панели (`left: 50%` + центрирование) снято: оно
   возвращало плашку на ось прицела, то есть на тело аватара в третьем лице. Слой прицела уже
   ограничен шириной видимой сцены (`--fish3d-playable-width`), поэтому базовое правило выше
   (отступ вправо от столбца тела и `max-width` в пределах правой половины слоя) само держит
   кнопки вне панели — правило коммита 962ed732a соблюдено без отдельной ветки.
   В узком окне правой половины не хватает на поле и кнопки: плашка уходит к нижнему краю над
   подсказками действий и хотбаром (как было для открытой панели) — центр сцены и тело свободны.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §8 п. 2, §22.1. Chat: hp-remaining-six-2026-10-28. */
/* [2026-10-29] Правило узкого окна (плашка над подсказками у `--fish3d-model-composition-bottom`)
   снято вместе со сдвигом вправо — решение PO 2026-10-29 (см. `.fish3d-crosshair-actions`). Паспорт
   и в узком окне вверху по центру и переносится в пределах сцены; строка действия стоит ровно на
   той же высоте, где столбец подсказок клавиш стоял над хотбаром в каждом узком случае (хотбар
   лентой с прокруткой поднимает край до ~90px), а столбец поднят на её ряд в тех же условиях.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22.1. Chat: hp-remaining-six-2026-10-28. */
@media (max-width: 600px) {
    .fish3d-crosshair-actions {
        bottom: calc(64px + var(--space-8, 32px));
    }
    /* [2026-10-30] Сцена уже 600px: симметричный запас знака осей (2 × 116px) оставлял тексту меньше 370px.
       Плашка встаёт под знаком осей (8px + 100px + 8px) с запасом 8px по краям. Открытая F3 по-прежнему
       задаёт верх сама (`--fish3d-passport-top`). Chat: hp-remaining-six-2026-10-28. */
    .fish3d-crosshair-passport {
        --fish3d-passport-reserve: 8px;
        --fish3d-passport-top-default: 116px;
    }
}
@media (max-width: 791px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish3d-crosshair-actions {
        bottom: 100px;
    }
    /* [2026-10-30] Та же узкая сцена при открытой правой панели (видимая сцена до 451px).
       Chat: hp-remaining-six-2026-10-28. */
    .fish-main-container:not(.right-sidebar-collapsed) .fish3d-crosshair-passport {
        --fish3d-passport-reserve: 8px;
        --fish3d-passport-top-default: 116px;
    }
}
@media (max-width: 451px) {
    .fish3d-crosshair-actions {
        bottom: 100px;
    }
}

.fish3d-crosshair-line {
    min-width: 0;
}

/* Первичная памятка уже объясняет безопасный первый жест и управление. Пока она открыта,
   асинхронный статус проверки призрака попадал ровно в её середину: две разные инструкции
   читались одновременно, а предупреждение о постановке не относилось ни к одной строке.
   Не скрываем сам прицел и не останавливаем Rules — убираем только вторичную строку до
   первого действия; после закрытия памятки она снова показывается с актуальным результатом. */
.fish3dHud:has(.fish3d-first-run:not(.hidden)) .fish3d-crosshair-hint {
    display: none;
}

/* [2026-09-21] Этап AA: экран оснастки (§38) — слой поверх сцены, НЕ модальное окно: сцена под
   ним видна и живёт. Шаги, сводка и перечень неполноты — строками (канон «списки — строками»).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §38. Chat: fish3d-implementation-2026-09-21. */
.fish3d-rig-row {
    padding: 4px 8px;
    border-radius: var(--radius-sm, 4px);
    cursor: default;
}

.fish3d-rig-steps .fish3d-rig-row {
    cursor: pointer;
}

.fish3d-rig-steps .fish3d-rig-row.active {
    background: var(--bg-tertiary, rgba(96, 165, 250, 0.15));
    color: var(--brand-primary-text, #60a5fa);
}

.fish3d-rig-title {
    margin: 0;
    font-weight: 600;
}

.fish3d-rig-heading {
    display: flex;
    align-items: center;
    gap: var(--space-2, 8px);
    min-height: 56px;
}

.fish3d-rig-preview-box {
    display: grid;
    place-items: center;
    width: 56px;
    height: 56px;
    flex: 0 0 56px;
    overflow: hidden;
    border: 1px solid var(--border-color, rgba(148, 163, 184, 0.45));
    border-radius: var(--radius-sm, 4px);
    background: var(--bg-tertiary, rgba(96, 165, 250, 0.08));
}

.fish3d-rig-preview {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.fish3d-rig-preview-status {
    padding: 4px;
    text-align: center;
    font-size: 10px;
    line-height: 1.2;
    opacity: 0.75;
}

.fish3d-rig-help {
    margin: 0;
    opacity: 0.75;
    font-size: 12px;
}

.fish3d-rig-state.incomplete {
    color: var(--color-warning-text, #fbbf24);
}

.fish3d-rig-missing .fish3d-rig-row {
    color: var(--color-warning-text, #fbbf24);
}

.fish3d-rig-controls {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2, 8px);
    align-items: flex-end;
}

.fish3d-rig-field {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 12px;
}

.fish3d-rig-field input,
.fish3d-rig-field select {
    width: 120px;
}

.fish3d-rig-parts {
    flex: 1 1 100%;
}

.fish3d-rig-parts .fish3d-rig-row {
    cursor: pointer;
}

.fish3d-rig-parts .fish3d-rig-row.bound {
    opacity: 0.6;
}

.fish3d-rig-draft,
.fish3d-rig-axis-hint {
    margin: 0;
    opacity: 0.75;
    font-size: 12px;
}

.fish3d-inventory,
.fish3d-rig {
    position: absolute;
    top: 10%;
    left: 50%;
    transform: translateX(-50%);
    width: min(720px, 90%);
    max-height: 70%;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--border-color, #4b5563);
    border-radius: var(--radius-md, 8px);
    background: var(--bg-secondary, rgba(17, 24, 39, 0.94));
    color: var(--text-primary, #e5e7eb);
    z-index: 6;
}

/* Оснастка остаётся поверх живой сцены, но это всё равно экран 3D-инструмента, а не
   светлая карточка офисного редактора. В светлой теме родительские токены делали белыми
   и фон, и поля: предупреждение об ошибке читалось, а сам путь настройки — нет. Токены
   намеренно локальны: открытие оснастки не должно перекрашивать сцену или обычные формы. */
.fish3d-rig {
    --fish3d-rig-bg: rgba(17, 24, 39, 0.98);
    --fish3d-rig-field: rgba(15, 23, 42, 0.94);
    --fish3d-rig-text: #e5e7eb;
    --fish3d-rig-muted: #cbd5e1;
    --fish3d-rig-border: rgba(255, 255, 255, 0.2);
    --fish3d-rig-accent: #60a5fa;
    background: var(--fish3d-rig-bg);
    color: var(--fish3d-rig-text);
    border-color: var(--fish3d-rig-border);
    /* На рабочей высоте 900px даже стартовая сводка длиннее 70% экрана. Без собственного
       скролла нижние причины неполноты выпадали из карточки прямо на хотбар, а шаги 3–5
       теряли реальные поля. Прокручивается сам экран; колесо не уходит миру под ним. */
    box-sizing: border-box;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.fish3d-rig .fish3d-rig-help,
.fish3d-rig .fish3d-rig-draft,
.fish3d-rig .fish3d-rig-axis-hint,
.fish3d-rig .fish3d-rig-preview-status {
    color: var(--fish3d-rig-muted);
    opacity: 1;
}

.fish3d-rig .fish3d-rig-preview-box {
    border-color: var(--fish3d-rig-border);
    background: rgba(96, 165, 250, 0.12);
}

.fish3d-rig .fish3d-rig-steps .fish3d-rig-row.active,
.fish3d-rig .fish3d-rig-steps .fish3d-rig-row:hover,
.fish3d-rig .fish3d-rig-steps .fish3d-rig-row:focus-visible {
    background: rgba(96, 165, 250, 0.28);
    color: #dbeafe;
}

.fish3d-rig .fish3d-rig-field input,
.fish3d-rig .fish3d-rig-field select,
.fish3d-rig button {
    color: var(--fish3d-rig-text);
    background: var(--fish3d-rig-field);
    border-color: var(--fish3d-rig-border);
}

.fish3d-rig button:not(:disabled):hover,
.fish3d-rig button:not(:disabled):focus-visible {
    background: rgba(96, 165, 250, 0.28);
    border-color: var(--fish3d-rig-accent);
}

.fish3d-rig button:disabled {
    color: var(--fish3d-rig-muted);
    background: rgba(15, 23, 42, 0.55);
}

/* Выбор способа стыковки — продолжение подсказки прицела, а не центральная модалка.
   Он не заслоняет сцену и не выглядит отдельным «окном», пока инженер выбирает строку
   допустимого способа непосредственно у стыка (§9.2). */
.fish3d-connect {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(28px, -50%);
    width: min(360px, calc(50% - 40px));
    max-height: min(320px, calc(100% - 32px));
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px 8px;
    border: 0;
    border-left: 2px solid var(--color-accent, #60a5fa);
    border-radius: 0;
    background: color-mix(in srgb, var(--bg-secondary, #111827) 76%, transparent);
    color: var(--text-primary, #e5e7eb);
    z-index: 6;
    box-sizing: border-box;
}

.fish3d-connect-title {
    margin: 0;
    font-size: 13px;
}

.fish3d-connect-help {
    margin: 0;
    font-size: 11px;
    opacity: 0.75;
}

@media (max-width: 720px) {
    .fish3d-connect {
        top: calc(50% + 28px);
        left: 50%;
        transform: translateX(-50%);
        width: min(420px, calc(100% - 24px));
        max-height: min(280px, calc(50% - 40px));
    }
}

/* Инвентарь — игровой экран, не центральная диалоговая карточка (§7). */
.fish3d-inventory {
    top: 0;
    width: min(980px, 100%);
    /* Ширина игрового экрана включает собственные отступы: иначе на узком вьюпорте
       24px с каждой стороны выходили за край, скрывая строку каталога и паспорт выбора. */
    box-sizing: border-box;
    max-height: 100%;
    min-height: 100%;
    padding: 24px;
    border: 0;
    border-radius: 0;
    /* Каталог — самостоятельный игровой экран, а не светлая офисная карточка поверх мира.
       Наследование `--bg-secondary` делало его белым в светлой теме, тогда как потомки уже
       брали светлый HUD-текст: название и паспорт выбранного предмета теряли контраст.
       Фон намеренно НЕ непрозрачен: §7 требует оставлять живую 3D-сцену видимой за
       инвентарём. Предыдущие 0.98 делали экран фактически модальным затемнением, хотя
       ввод действительно принадлежал инвентарю. */
    --fish3d-hud-bg: rgba(20, 24, 28, 0.96);
    --fish3d-hud-text: #e5e7eb;
    --fish3d-hud-muted: #cbd5e1;
    --fish3d-hud-border: rgba(255, 255, 255, 0.18);
    --fish3d-hud-accent: #60a5fa;
    --fish3d-inventory-error-text: #ffd1ca;
    --fish3d-inventory-warning-text: #ffe9ad;
    background: rgba(17, 24, 39, 0.72);
    color: var(--fish3d-hud-text);
}

.fish3d-inventory .fish3d-inventory-slot {
    border-color: var(--fish3d-hud-border);
}

.fish3d-inventory .fish3d-inventory-category.active,
.fish3d-inventory .fish3d-inventory-category:hover,
.fish3d-inventory .fish3d-inventory-slot:not(:disabled):hover,
.fish3d-inventory .fish3d-inventory-slot:not(:disabled):focus-visible,
.fish3d-inventory .fish3d-inventory-slot.active {
    background: color-mix(in srgb, var(--fish3d-hud-accent) 24%, transparent);
}

.fish3d-inventory-navigation-hint {
    margin: 0;
    color: var(--fish3d-hud-muted);
    font-size: 13px;
}

/* Инвентарь — единственный полноэкранный экран HUD. Его локальный z-index бесполезен,
   пока вся обёртка HUD находится ниже `right-sidebar` (z-index: 50): поднимаем именно
   контекст, а не отдельную карточку. Остальные прямые HUD-слои скрываются каскадом — так
   под прозрачным фоном каталога не остаются хотбар, подсказка цели, cue или состав модели.
   Правило лежит после базового `.fish3d-inventory`, поэтому не может быть переопределено
   старой центровкой панели (`left: 50%`). */
.fish3dHud.fish3d-inventory-open {
    z-index: 51;
}

.fish3dHud.fish3d-inventory-open > *:not(#fish3dInventoryLayer) {
    visibility: hidden;
    pointer-events: none;
}

.fish3dHud.fish3d-inventory-open > #fish3dInventoryLayer {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    max-height: none;
    min-height: 100%;
    transform: none;
    z-index: 1;
}

/* Ведомость не лежит внутри `#fish3dHud`, а обычный сайдбар — вне полотна вовсе. Скрываем
   эти два оставшихся слоя тем же состоянием игрового экрана: за инвентарём не остаётся ни
   кликабельного, ни доступного «старого редактора». */
#fish3dRoot.fish3d-inventory-open > #fishModelComposition,
#fish3dRoot.fish3d-inventory-open > #fish3dTwoDimensionalOnlyNotice,
.fish-main-container.fish3d-inventory-open .right-sidebar {
    visibility: hidden;
    pointer-events: none;
}

/* F11 — это полноэкранный мир, а не только растянутый canvas. Fullscreen API выносит
   #fish3dRoot в верхний слой, однако внешние элементы оболочки (шапка, вкладки и Properties)
   оставались видимыми поверх него. В результате игрок видел одновременно мир и офисный
   редактор. HUD сцены остаётся внутри root; скрываем только внешнюю оболочку на время F11. */
body.fish3d-scene-fullscreen > header,
body.fish3d-scene-fullscreen .module-controls-row.fish-toolbar,
body.fish3d-scene-fullscreen #tabsBar,
body.fish3d-scene-fullscreen #breadcrumb-bar,
body.fish3d-scene-fullscreen .right-sidebar,
body.fish3d-scene-fullscreen #fish3dRoot #fishModelComposition {
    display: none !important;
}

/* [2026-10-03] Левая панель WBS (универсальная, из модуля активностей; разметка — fish.html,
   стили — step-by-step/wbs-panel.css) стоит слева от рабочей области: обёртка
   `.page-content-wrapper.fish-wbs-wrapper` — строка «панель WBS | #fish-main-container» под
   панелью модуля и вкладками. В чистом мире F1, полноэкранном F11 и при открытом инвентаре
   панель уходит вместе с остальной оболочкой редактора.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §5, §12.18.
   Chat: fish-model-composition-sidebar-section-2026-10-02. */
.fish-wbs-wrapper {
    min-height: 0;
}
.fish-wbs-wrapper > .fish-main-container {
    min-width: 0;
}
body.fish3d-scene-fullscreen #wbs-panel,
body.fish3d-ui-hidden #wbs-panel {
    display: none !important;
}

/* Инвентарь владеет всем рабочим экраном. Без изоляции глобальной шапки и панелей пользователь
   мог открыть настройки/файловое окно поверх каталога и потерять контекст клавиатуры. */
.fish3d-inventory-chrome-hidden {
    /* `visibility` сохраняет высоту шапки, тулбара и вкладок. Каталог при этом начинался
       на 157px ниже окна с пустой белой полосой — это уже не полноэкранный игровой экран.
       Класс добавляется только на время модального владельца и снимается вместе с inert,
       поэтому `display:none` не теряет ни исходную структуру, ни фокус после Esc. */
    display: none !important;
    pointer-events: none;
}

.fish3d-inventory-list,
.fish3d-connect-list {
    overflow-y: auto;
    min-height: 0;
}

.fish3d-inventory-families {
    display: flex;
    flex: 0 0 auto;
    gap: 6px;
    min-height: 38px;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 1px 0 3px;
    white-space: nowrap;
}

.fish3d-inventory-family {
    flex: 0 0 auto;
    min-height: 34px;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--fish3d-hud-border);
    border-radius: var(--radius-md);
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
}

.fish3d-inventory-family:hover,
.fish3d-inventory-family[aria-pressed='true'] {
    border-color: var(--fish3d-hud-accent);
    background: color-mix(in srgb, var(--fish3d-hud-accent) 24%, transparent);
    color: var(--fish3d-hud-text);
}

.fish3d-inventory-family:focus-visible {
    border-color: var(--border-hover);
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}

/* Desktop inventory is a tray of recognizable items, not a document-length table.
   The selected item keeps its full engineering passport in the adjacent panel. */
@media (min-width: 601px) {
    .fish3d-inventory-list {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
        grid-auto-rows: 146px;
        align-content: start;
        gap: 6px;
        padding: 4px;
    }

    .fish3d-inventory-list > .fish3d-inventory-row {
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        justify-content: flex-start;
        align-items: center;
        gap: 3px;
        min-width: 0;
        min-height: 0;
        padding: 5px;
        overflow: hidden;
        border: 1px solid var(--fish3d-hud-border);
        background: var(--fish3d-hud-bg);
        text-align: center;
    }

    .fish3d-inventory-list > .fish3d-inventory-row:hover,
    .fish3d-inventory-list > .fish3d-inventory-row:focus-visible {
        border-color: var(--fish3d-hud-accent);
        background: rgba(96, 165, 250, 0.16);
        color: var(--fish3d-hud-text);
    }

    .fish3d-inventory-list .fish3d-inventory-thumb {
        width: 60px;
        height: 60px;
        flex: 0 0 60px;
    }

    .fish3d-inventory-list .fish3d-inventory-row.family-focused .fish3d-inventory-thumb {
        width: 68px;
        height: 68px;
        flex-basis: 68px;
    }

    .fish3d-inventory-list .fish3d-inventory-row.family-focused .fish3d-inventory-title {
        font-size: 14px;
        font-weight: 700;
        line-height: 17px;
    }

    .fish3d-inventory-list .fish3d-inventory-title {
        display: -webkit-box;
        flex: 0 0 auto;
        width: 100%;
        overflow: hidden;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        font-size: 12px;
        line-height: 14px;
        overflow-wrap: anywhere;
    }

    .fish3d-inventory-list .fish3d-inventory-meta {
        width: 100%;
        overflow: hidden;
        color: var(--fish3d-hud-muted);
        font-size: 11px;
        line-height: 13px;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .fish3d-inventory-list .fish3d-inventory-status {
        display: -webkit-box;
        overflow: hidden;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-height: 12px;
    }

    .fish3d-inventory-list > .fish3d-inventory-empty {
        grid-column: 1 / -1;
    }
}

.fish3d-inventory-content {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(180px, 0.45fr);
    gap: 8px;
    min-height: 0;
    /* Keep the world visible around the inventory, but not through item names and
       passport values: the screen's 0.72-alpha backdrop alone lets scene meshes
       compete with the catalogue text. */
    background: #14181c;
}

.fish3d-inventory-details {
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    overflow-wrap: anywhere;
    padding: 8px;
    border-left: 1px solid var(--border-color, #4b5563);
    color: var(--fish3d-hud-text, var(--text-primary, #e5e7eb));
    font-size: 12px;
    line-height: 1.4;
}

/* Выбор не должен быть только тонкой рамкой строки: карточка показывает тот же 3D-силуэт,
   который попадёт в слот и под прицел. Пока WebGL-миниатюра строится либо недоступна,
   текстовая замена остаётся видимой — пустого «выбранного» предмета не бывает. */
.fish3d-inventory-preview {
    position: relative;
    display: grid;
    place-items: center;
    min-height: 132px;
    margin: 0 0 8px;
    overflow: hidden;
    border: 1px solid var(--border-color, #4b5563);
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-bg, rgba(20, 24, 28, 0.82));
}

.fish3d-inventory-preview-image {
    display: none;
    width: min(100%, 220px);
    height: 132px;
    object-fit: contain;
}

.fish3d-inventory-preview.ready .fish3d-inventory-preview-image {
    display: block;
}

.fish3d-inventory-preview-fallback {
    padding: 12px;
    color: var(--fish3d-hud-muted, #cbd5e1);
    text-align: center;
}

.fish3d-inventory-preview.ready .fish3d-inventory-preview-fallback {
    display: none;
}

.fish3d-inventory-preview.unavailable .fish3d-inventory-preview-fallback::before {
    display: block;
    margin-bottom: 6px;
    color: var(--fish3d-hud-accent, #60a5fa);
    content: '◇';
    font-size: 32px;
    line-height: 1;
}

.fish3d-inventory-passport,
.fish3d-inventory-next-step {
    margin: 0;
}

.fish3d-inventory-specs {
    display: grid;
    grid-template-columns: minmax(76px, 0.35fr) minmax(0, 1fr);
    gap: 4px 8px;
    margin: 8px 0;
    padding: 8px 0;
    border-top: 1px solid var(--fish3d-hud-border);
    border-bottom: 1px solid var(--fish3d-hud-border);
}

.fish3d-inventory-specs dt {
    color: var(--fish3d-hud-muted);
}

.fish3d-inventory-specs dd {
    min-width: 0;
    margin: 0;
}

/* Нижний ряд не заимствует скрытый HUD-хотбар: это настоящий, видимый адрес назначения
   выбранной позиции внутри полноэкранного инвентаря. */
.fish3d-inventory-slots {
    display: grid;
    grid-template-columns: repeat(9, 64px);
    justify-content: center;
    gap: 4px;
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid var(--border-color, #4b5563);
}

.fish3d-inventory-feedback:not([hidden]) {
    margin: 8px 0 0;
    padding: 6px 10px;
    border: 1px solid var(--fish3d-inventory-warning-text);
    border-radius: var(--radius-sm, 4px);
    background: rgba(75, 45, 5, 0.88);
    color: var(--fish3d-inventory-warning-text);
    font-size: 13px;
    line-height: 1.35;
}

.fish3d-inventory-slot {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    min-width: 0;
    height: 64px;
    padding: 4px;
    border: 1px solid var(--border-color, #4b5563);
    border-radius: var(--radius-sm, 4px);
    background: var(--fish3d-hud-bg, rgba(20, 24, 28, 0.82));
    color: inherit;
    cursor: pointer;
}

.fish3d-inventory-slot:not(:disabled):hover,
.fish3d-inventory-slot:not(:disabled):focus-visible,
.fish3d-inventory-slot.active {
    border-color: var(--primary-color, #60a5fa);
    background: var(--bg-hover, rgba(96, 165, 250, 0.16));
}

.fish3d-inventory-slot:disabled {
    cursor: default;
    /* Assignment may be unavailable while the saved item itself remains valid. */
    opacity: 1;
}

/* Во время перетаскивания событие получает полоса слотов, включая пустые disabled-ячейки. */
.fish3d-inventory-slots.dragging .fish3d-inventory-slot {
    pointer-events: none;
}

.fish3d-inventory .fish3d-inventory-slot.drop-target {
    outline: 2px solid var(--fish3d-hud-accent, #60a5fa);
    outline-offset: -2px;
    background: rgb(96 165 250 / 34%);
}

.fish3d-inventory-slot-number {
    position: absolute;
    top: 3px;
    left: 4px;
    z-index: 1;
    color: var(--fish3d-hud-accent, #60a5fa);
    font-weight: 700;
}

.fish3d-inventory-slot-thumb {
    width: 100%;
    height: 38px;
    flex: 0 0 38px;
    object-fit: contain;
}

.fish3d-inventory-slot-label {
    width: 100%;
    overflow: hidden;
    color: var(--fish3d-hud-muted, #cbd5e1);
    font-size: 11px;
    line-height: 12px;
    text-align: center;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.fish3d-inventory-next-step {
    margin-top: 8px;
    color: var(--fish3d-hud-muted, #cbd5e1);
    font-size: 13px;
    font-weight: 600;
}

.fish3d-inventory-row,
.fish3d-connect-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 8px;
    border-radius: var(--radius-sm, 4px);
    cursor: pointer;
}

.fish3d-inventory-row:hover,
.fish3d-connect-row:hover,
.fish3d-inventory-row:focus-visible,
.fish3d-connect-row:focus-visible {
    background: var(--bg-hover, rgba(96, 165, 250, 0.16));
}

.fish3d-inventory-row.selected {
    outline: 1px solid var(--primary-color, #60a5fa);
    background: var(--bg-hover, rgba(96, 165, 250, 0.16));
}

/* Выбранная строка живёт на тёмном игровом каталоге. Офисный `--bg-hover` светлый и вместе
   с HUD-текстом делал название выбранного изделия белым на белом — превью оставалось, а
   предмет визуально «исчезал». */
.fish3d-inventory .fish3d-inventory-row.selected {
    background: rgba(96, 165, 250, 0.28);
}

@media (max-width: 600px) {
    .fish3d-inventory-content {
        grid-template-columns: minmax(0, 1fr);
    }

    .fish3d-inventory-details {
        border-top: 1px solid var(--border-color, #4b5563);
        border-left: 0;
    }

    .fish3d-inventory-slots {
        grid-template-columns: repeat(9, minmax(44px, 1fr));
        justify-content: start;
        overflow-x: auto;
        flex-shrink: 0;
    }
}

.fish3d-inventory-meta {
    /* Size, material and standard distinguish near-identical catalog rows. Muting this
       12px text over the translucent scene made it unreadable on a bright grid. */
    font-size: 13px;
}

.fish3d-connect-note {
    opacity: 0.7;
    font-size: 12px;
}

.fish3d-connect-row.denied {
    opacity: 0.6;
    cursor: not-allowed;
}

.fish3d-connect-row.review .fish3d-connect-note {
    color: var(--color-warning-text, #fbbf24);
}

.fish3d-inventory-categories {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}

.fish3d-inventory-heading {
    margin: 0;
    color: var(--fish3d-hud-text, var(--text-primary, #e5e7eb));
    font-size: 18px;
    line-height: 1.25;
}

.fish3d-inventory-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.fish3d-inventory-close {
    flex: 0 0 auto;
    min-height: 40px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--fish3d-hud-border);
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--fish3d-hud-text);
    font-size: 14px;
    cursor: pointer;
}

.fish3d-inventory-close:hover {
    background: var(--fish3d-hud-control-bg);
}

.fish3d-inventory-close:focus-visible {
    border-color: var(--border-hover);
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}

.fish3d-inventory-category {
    min-height: 40px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--fish3d-hud-border);
    border-radius: var(--radius-md);
    background: transparent;
    color: inherit;
    font-size: 14px;
    cursor: pointer;
}

.fish3d-inventory-category:focus-visible {
    border-color: var(--border-hover);
    outline: 1px solid var(--border-hover);
    outline-offset: -1px;
    box-shadow: none;
}

/* Search and discipline tabs are the first decisions in the full-screen catalogue.  They used
   native 21px controls despite every catalogue row being 60px; give them the same desktop
   game-menu reach without turning catalogue entries themselves into buttons. */
.fish3d-inventory-search {
    box-sizing: border-box;
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    color: var(--fish3d-hud-text);
    font-size: 14px;
}
.fish3d-inventory-search:focus-visible {
    border-color: var(--border-hover);
    outline: none;
}

/* [2026-10-29] Слой памятки — по видимой сцене, как слой прицела (`--fish3d-playable-width`, Fish3D.js onResize):
   при пристыкованной панели «Свойства» (780px, живой замер e2e/fish-narrow-320-live.cjs) карточка центрировалась по
   всему корню и уходила правой половиной под панель. Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §22;
   docs/QA_UI_CANON_HP_HANDOFF_2026-10-24.md F2. Chat: hp-remaining-six-2026-10-28. */
.fish3dHintsLayer {
    position: absolute;
    inset: 0;
    right: auto;
    width: var(--fish3d-playable-width, 100%);
    pointer-events: none;
    /* Одноразовая памятка — временный учебный экран. Постоянный HUD полезен после неё,
       но не вправе закрывать строки обучения в момент первого входа. */
    z-index: 6;
}

.fish3d-first-run,
.fish3d-debug {
    position: absolute;
    padding: 8px 12px;
    border: 1px solid color-mix(in srgb, var(--fish3d-hud-border, #6b7280) 70%, transparent);
    border-radius: var(--radius-md, 8px);
    /* Игровые карточки не наследуют белый фон офисной оболочки в светлой теме:
       первый вход и F3 относятся к сцене так же, как хотбар и Action cue. */
    background: color-mix(in srgb, var(--fish3d-hud-bg, #111827) 92%, transparent);
    color: var(--fish3d-hud-text, #e5e7eb);
    font-size: 12px;
    line-height: 1.6;
}

.fish3d-first-run {
    left: 50%;
    top: 50%;
    /* Раньше памятка прижималась к низу и пересекалась с Action cue/хотбаром: последняя
       строка управления оказывалась под тёмной плашкой. Центр сцены сохраняет оба края
       для постоянного HUD и показывает весь список до первого действия. */
    transform: translate(-50%, -50%);
    text-align: center;
    /* [2026-10-29] Ширина — по строкам, в пределах сцены. При left: 50% ширина «по содержимому» считалась от
       половины слоя: в сцене 440px (780px с панелью) карточка сжималась до 220px и вырастала до 547px, ложась на
       строку «Строить» и хотбар (живой замер e2e/fish-narrow-320-live.cjs). Chat: hp-remaining-six-2026-10-28. */
    box-sizing: border-box;
    width: max-content;
    max-width: calc(100% - 2 * var(--space-2, 8px));
}
/* [2026-10-29] Пристыкованная панель «Свойства» на экране до 1100px оставляет сцене 429–760px: по центру
   тринадцать строк памятки доходят до подсказок действий. Как на телефоне — у верхнего края сцены, снизу запас под
   постоянный HUD. Ref: docs/QA_UI_CANON_HP_HANDOFF_2026-10-24.md F2. Chat: hp-remaining-six-2026-10-28. */
@media (max-width: 1100px) {
    /* Запас снизу — предмет в руке (bottom 104px + 108px, с поворотом ~124px) и подсказки действий; строки — в
       компактном наборе телефонной памятки, чтобы весь текст вошёл без обрезки. */
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHintsLayer > .fish3d-first-run {
        top: var(--space-2, 8px);
        transform: translateX(-50%);
        max-height: calc(100% - 240px);
        overflow: hidden;
        padding: 6px 8px;
        font-size: 11px;
        line-height: 1.35;
    }
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHintsLayer > .fish3d-first-run .fish3d-first-run-line {
        margin: 0 0 2px;
    }
}
/* [2026-10-29] Низкое окно: запас 240px под предмет в руке оставлял памятке ~60px при сцене 300px, и `overflow:
   hidden` срезал команды (ревью Codex 2026-10-29 №4). Строки обучения важнее: памятка временная и уходит с первой
   командой, поэтому на низком окне она берёт высоту сцены, а не обрезается. Chat: hp-remaining-six-2026-10-28. */
@media (max-width: 1100px) and (max-height: 760px) {
    .fish-main-container:not(.right-sidebar-collapsed) .fish3dHintsLayer > .fish3d-first-run {
        max-height: calc(100% - 2 * var(--space-2, 8px));
    }
}

/* In Esc the same DOM is a reference pane, not first-run onboarding.  Keeping its world-card
   absolute made the pane height zero, so it could float over the pause title and had no layout
   presence.  Scope the normal-flow layout to the borrowed card only. */
.fish3d-pause-pane > .fish3d-first-run {
    position: static;
    box-sizing: border-box;
    width: 100%;
    max-height: min(58vh, 560px);
    margin: 0;
    overflow-y: auto;
    transform: none;
}

.fish3d-first-run-dismiss {
    margin: 8px 0 0;
    opacity: 0.78;
    font-size: 11px;
}

/* [2026-10-25] Узкий экран: центрированная памятка переносила каждую строку на две-три, тянулась на всю высоту сцены
   и ложилась на строку «Строить» и хотбар (живой прогон двух пользователей 2026-10-25, снимки 320 px). Здесь она
   прижата к верху во всю ширину сцены, строки компактнее, а снизу оставлен запас под постоянный HUD. Граница
   ширины — та же, что у остальной мобильной раскладки Fish (mobile-ribbon.css). Esc-справка (.fish3d-pause-pane)
   этим правилом не затрагивается. Ref: docs/QA_UI_CANON_HP_HANDOFF_2026-10-24.md F2.
   Chat: перенос-чата-на-HP-2026-10-24. */
@media (width <= 480px) {
    .fish3dHintsLayer > .fish3d-first-run {
        top: var(--space-2, 8px);
        transform: translateX(-50%);
        box-sizing: border-box;
        width: calc(100% - 2 * var(--space-2, 8px));
        max-height: calc(100% - 160px);
        overflow: hidden;
        padding: 6px 8px;
        font-size: 11px;
        line-height: 1.35;
    }

    .fish3dHintsLayer > .fish3d-first-run .fish3d-first-run-line {
        margin: 0 0 2px;
    }
}

.fish3d-debug {
    top: var(--space-4, 16px);
    left: var(--space-4, 16px);
    font-family: var(--font-family-mono, monospace);
}

/* [2026-09-22] Метки отклика §11: маркер в точке стыковки и контур на месте удалённого тела.
   Отклик транзиентный и ввод не блокирует — слой не принимает указатель.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §11, M42. Chat: fish3d-implementation-2026-09-21. */
.fish3d-action-markers {
    position: absolute;
    inset: 0;
    z-index: 6;
    pointer-events: none;
}
.fish3d-action-marker {
    position: absolute;
    pointer-events: none;
}
.fish3d-action-marker.place {
    width: 14px;
    height: 14px;
    margin: -7px 0 0 -7px;
    border: 2px solid var(--brand-primary);
    border-radius: 50%;
}
.fish3d-action-marker.removed {
    border: 2px dashed var(--color-error);
    border-radius: 4px;
}
.fish3d-action-marker.selection {
    border: 2px solid #ffb000;
    border-radius: 4px;
}

/* Feedback.applyAppearance задаёт animation-duration по §22.3; CSS задаёт
   только кадры и резервную длительность для метки без вызова JS. */
.fish3d-appear {
    animation: fish3dAppear 180ms ease-out;
}

.fish3d-appear.reduce-motion {
    animation-name: fish3dFadeIn;
}

/* §11 «удаление — кратковременный контур»: контур гаснет тем же законом, что появление, но в
   обратную сторону. При «уменьшить движение» перемещения нет — остаётся прозрачность. */
.fish3d-disappear {
    animation: fish3dDisappear 100ms ease-out;
}

@keyframes fish3dFadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

@keyframes fish3dDisappear {
    from {
        opacity: 1;
    }
    to {
        opacity: 0.2;
    }
}

@keyframes fish3dAppear {
    from {
        opacity: 0;
        transform: translateY(4px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

/* [2026-09-22] Этап AR §21.5 п. 2: ПЛЕЕР «ИСТОРИЯ 3D» — ПОЛОСА ПО НИЖНЕМУ КРАЮ СЦЕНЫ, а не окно.
   ТЗ дословно: «Модель занимает весь экран, её ничто не перекрывает: смотреть прогон и есть смысл
   этого режима». Поэтому полоса прижата к низу, тянется по ширине и НЕ накрывает сцену собой;
   надпись «Просмотр истории» идёт над ней — §21.5 п. 1 требует явного признака, что живой режим
   приостановлен.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §21.5, §22.1. Chat: fish3d-implementation-2026-09-21. */
.fish3d-history {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 12px;
    color: var(--fish3d-hud-text);
}
.fish3d-history.hidden {
    display: none;
}
.fish3d-history-banner {
    align-self: center;
    padding: 4px 10px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: var(--fish3d-hud-bg);
    font-size: 13px;
}
.fish3d-history-help {
    align-self: center;
    margin: 0;
    font-size: 12px;
    opacity: 0.75;
}
.fish3d-history-origin {
    align-self: center;
    margin: 0;
    padding: 3px 8px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 6px;
    background: var(--fish3d-hud-bg);
    font-size: 12px;
}
.fish3d-history-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 10px;
    background: var(--fish3d-hud-bg);
}
.fish3d-history-scale {
    flex: 1 1 240px;
    min-width: 160px;
}
.fish3d-history-label {
    flex: 0 1 auto;
    font-size: 13px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fish3d-history-filter {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
}

/* [2026-09-22] Живая приёмка этапа AR в открытом окне (playwright-2, файл 51). Поймано на экране:
   полоса прогона легла ПОВЕРХ хотбара и накладки подсказок — «Просмотр истории» перекрыла слоты,
   строка управления села на подписи изделий, а список участников уехал за правый край.
   §21.5 п. 2: «Модель занимает весь экран, её ничто не перекрывает». В прогоне ставить и убирать
   нечем — живой режим приостановлен, — поэтому его органы на это время убираются, полоса получает
   свою подложку и не вылезает за ширину сцены.
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §21.5. Chat: fish3d-implementation-2026-09-21. */
body.fish3d-history-open #fish3dSlots,
body.fish3d-history-open #fish3dHeldItem,
body.fish3d-history-open #fish3dHintsLayer,
body.fish3d-history-open #fish3dCrosshairLayer,
/* Прогон приостанавливает живое редактирование. Оставленная подсказка «Редактировать»
   выглядела как доступный инструмент над записью истории, хотя ни один такой жест в этом
   состоянии не выполняется. Скрываем весь живой action-слой вместе с хотбаром и прицелом. */
body.fish3d-history-open #fish3dActionCueLayer,
body.fish3d-history-open #fish3d-action-markers,
body.fish3d-history-open #fish3dPenetrationLayer {
    display: none;
}
/* [2026-09-26] Действие аватара с арматурой: легенда клавиш и хотбар закрывали нижнюю треть
   сцены, и кран у ног аватара на колене не был виден (QA valve-ops, дефект 10). На время
   действия клавиши не работают по легенде — движение прерывает действие, ПКМ отпускает привод,
   это называет подпись у прицела. Заголовок и строка статуса легенды остаются.
   Ref: docs/QA_VALVE_OPS_2026-09-26.md §4. Chat: valve-ops-avatar-2026-09-25. */
body.fish3d-valve-action #fish3dSlots,
body.fish3d-valve-action #fish3dHeldItem,
body.fish3d-valve-action #fish3dActionCueLayer .fish3d-action-cue-controls {
    display: none;
}
.fish3d-history {
    box-sizing: border-box;
    max-width: 100%;
}
.fish3d-history-strip {
    box-sizing: border-box;
    max-width: 100%;
    overflow: hidden;
}
.fish3d-history-author,
.fish3d-history-category,
.fish3d-history-speed {
    max-width: 180px;
}

/* [2026-09-22] Второй круг живой приёмки этапа AR: полоса прогона стояла БЕЗ подложки — кнопка и
   подпись висели прямо на сцене, «убрано — …» ложилось на линию сетки и читалось плохо, а правый
   край с кнопкой «В живой режим» срезался. Подложка и перенос строк возвращают полосе вид панели
   интерфейса, как у остальных элементов HUD (§22.1: интерфейс живёт по краям и читается).
   Ref: docs/TZ_FISH_3D_MINECRAFT_UX_2026-09-18.md §21.5 п. 2, §22.1. Chat: fish3d-implementation-2026-09-21. */
.fish3d-history-strip {
    flex-wrap: wrap;
    overflow: visible;
    row-gap: 6px;
    background: var(--fish3d-hud-bg);
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 10px;
}
.fish3d-history-label {
    flex: 1 1 200px;
    white-space: normal;
}
.fish3d-history-scale {
    flex: 1 1 200px;
}
/* History is a persistent in-scene control strip, not an HTML form left at browser defaults.
   Its play/return controls previously measured only 21px high (the checkbox 13px), which made
   the visual language diverge from every other desktop game control and made them hard to hit. */
.fish3d-history-strip .hotbar-btn {
    min-height: 40px;
    padding: 8px 12px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: transparent;
    color: var(--fish3d-hud-text);
    font-size: 14px;
    cursor: pointer;
}
.fish3d-history-strip .hotbar-btn:hover,
.fish3d-history-strip .hotbar-btn:focus-visible {
    border-color: var(--fish3d-hud-accent);
    background: var(--fish3d-hud-hover);
}
.fish3d-history-speed,
.fish3d-history-author,
.fish3d-history-category {
    min-height: 40px;
    padding: 0 10px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
    background: transparent;
    color: var(--fish3d-hud-text);
    font-size: 14px;
}
.fish3d-history-scale {
    min-height: 28px;
    accent-color: var(--fish3d-hud-accent);
}
.fish3d-history-filter {
    min-height: 40px;
    padding: 0 8px;
    border: 1px solid var(--fish3d-hud-border);
    border-radius: 8px;
}
.fish3d-history-filter input[type='checkbox'] {
    inline-size: 18px;
    block-size: 18px;
    accent-color: var(--fish3d-hud-accent);
}
