/* =========================================================================
   Modul3D — UI Shell v2
   Дизайн-система: две темы (Studio Light / Pro Dark) на одних токенах.
   Всё оформление живёт здесь; логика (app.js, engine.js) не менялась.
   ========================================================================= */

/* ---------- 1. ТОКЕНЫ ---------------------------------------------------- */

:root {
  /* типографика */
  --ff: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --ff-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  --fs-xs: 11px;
  --fs-sm: 12px;
  --fs-md: 13px;
  --fs-lg: 15px;

  /* геометрия */
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;

  /* движение */
  --ease: cubic-bezier(.22, .61, .36, 1);
  --dur: .28s;
  --dur-slow: .42s;

  /* размеры оболочки */
  --topbar-h: 52px;
  --rail-w: 52px;
  --drawer-w: 340px;
  --sheet-h: 40px;
}

/* --- Studio Light (по умолчанию) --- */
:root,
[data-theme='light'] {
  --bg: #eef2f7;
  --bg-2: #f8fafc;
  --stage: radial-gradient(circle at 50% 40%, #ffffff 0%, #e8eef5 100%);
  --grid-line: rgba(148, 163, 184, .14);

  --surface: rgba(255, 255, 255, .88);
  --surface-solid: #ffffff;
  --surface-2: #f1f5f9;
  --surface-3: #e9eef5;

  --border: #e2e8f0;
  --border-strong: #cbd5e1;

  --text: #0f172a;
  --text-2: #475569;
  --muted: #64748b;

  --accent: #0284c7;
  --accent-2: #0369a1;
  --accent-ink: #ffffff;
  --accent-soft: rgba(2, 132, 199, .10);
  --accent-glow: rgba(2, 132, 199, .28);

  --danger: #dc2626;
  --danger-soft: rgba(220, 38, 38, .10);
  --ok: #059669;
  --warn: #d97706;

  --shadow-1: 0 1px 2px rgba(15, 23, 42, .06);
  --shadow-2: 0 8px 24px -8px rgba(15, 23, 42, .16), 0 2px 6px rgba(15, 23, 42, .05);
  --shadow-3: 0 24px 60px -20px rgba(15, 23, 42, .28), 0 4px 12px rgba(15, 23, 42, .06);
  --blur: blur(16px) saturate(140%);
}

/* --- Pro Dark --- */
[data-theme='dark'] {
  --bg: #101317;
  --bg-2: #16191e;
  --stage: radial-gradient(circle at 50% 40%, #262b33 0%, #101317 100%);
  --grid-line: rgba(255, 255, 255, .045);

  --surface: rgba(30, 34, 41, .84);
  --surface-solid: #1b1f25;
  --surface-2: #21262e;
  --surface-3: #272d36;

  --border: rgba(255, 255, 255, .09);
  --border-strong: rgba(255, 255, 255, .18);

  --text: #eef3f8;
  --text-2: #bcccdc;
  --muted: #8b9bad;

  --accent: #00c2ff;
  --accent-2: #38d4ff;
  --accent-ink: #06131a;
  --accent-soft: rgba(0, 194, 255, .14);
  --accent-glow: rgba(0, 194, 255, .40);

  --danger: #f87171;
  --danger-soft: rgba(248, 113, 113, .14);
  --ok: #34d399;
  --warn: #fbbf24;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-2: 0 10px 30px rgba(0, 0, 0, .45);
  --shadow-3: 0 28px 70px rgba(0, 0, 0, .6);
  --blur: blur(18px) saturate(130%);
}

/* ---------- 2. БАЗА ------------------------------------------------------ */

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

body {
  font-family: var(--ff);
  font-size: var(--fs-md);
  color: var(--text);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}

::selection { background: var(--accent-soft); }

/* тонкие скроллбары в тон теме */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 9px; height: 9px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 6px; border: 2px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: content-box; }

/* ---------- 3. ШАПКА ----------------------------------------------------- */

.topbar {
  position: relative;
  z-index: 40;
  flex: none;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: 0 var(--sp-4);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  transition: opacity var(--dur-slow) var(--ease), background var(--dur) var(--ease);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-weight: 700;
  font-size: var(--fs-lg);
  letter-spacing: -.01em;
  color: var(--text);
}
.brand-mark { width: 26px; height: 26px; flex: none; display: block; }
.brand-mark .bm-wire { fill: none; stroke: var(--accent); stroke-width: 3; stroke-linejoin: round; }
.brand-mark .bm-fill { fill: var(--accent); opacity: .18; }
.brand-name { font-weight: 800; letter-spacing: -.02em; }
.brand-name b { color: var(--accent); font-weight: 800; }
.brand .ver {
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
}
.brand-sub {
  font-weight: 400;
  font-size: var(--fs-sm);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-actions { display: flex; align-items: center; gap: var(--sp-2); }

/* ---------- 4. КНОПКИ ---------------------------------------------------- */

.btn,
.btn-header,
.add-section-btn,
.lib-cat,
.mod-tab,
.mod-add,
.sec-tab,
.sec-add,
.view-btn {
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.2;
  color: var(--text-2);
  background: var(--surface-solid);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 7px 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform .12s var(--ease);
}
.btn:hover,
.btn-header:hover,
.add-section-btn:hover,
.lib-cat:hover,
.mod-tab:hover,
.mod-add:hover,
.sec-tab:hover,
.sec-add:hover,
.view-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.materials-link-btn {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; margin-top: var(--sp-2);
  font-weight: 600; color: var(--accent);
  background: var(--accent-soft); border-color: var(--accent);
}
.materials-link-btn:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.materials-link-btn .arrow { font-weight: 700; }
/* Кнопка/select рядом со СВОИМ полем-счётчиком в .field-row (карточка секции,
   renderSectionsList): «Ящики, шт» + «Редактировать →», «Полки, шт» + режим
   распределения. У поля есть label над input, у кнопки/select своей подписи
   нет — без сброса margin-top кнопка/select уезжали бы ниже input соседней
   колонки. См. .field-row-action ниже — там же невидимая label-заглушка,
   которая ставит кнопку/select на ту же высоту, что и input. */
.field-row-btn { width: 100%; margin-top: 0; }
/* Кнопка «назад» (стрелка слева) переиспользует .materials-link-btn, но
   стрелка+текст должны идти одной группой у левого края, а не разъезжаться
   по краям, как у кнопки «вперёд» (space-between в базовом классе). */
.back-link-btn { justify-content: flex-start; gap: 8px; margin-bottom: var(--sp-3); }
.btn:active, .btn-header:active, .add-section-btn:active { transform: translateY(1px); }

.btn:focus-visible,
.btn-header:focus-visible,
.icon-btn:focus-visible,
.rail-btn:focus-visible,
.view-btn:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* акцентная (главная) кнопка */
.btn-primary,
.btn.primary,
.add-section-btn {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-ink);
  font-weight: 600;
}
.btn-primary:hover,
.btn.primary:hover,
.add-section-btn:hover {
  background: var(--accent-2);
  color: var(--accent-ink);
  border-color: transparent;
  box-shadow: 0 4px 14px -4px var(--accent-glow);
}

/* состояние «включено» */
.btn-header.active,
.btn.active,
.mod-tab.active,
.sec-tab.active,
.view-btn.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}

.mod-add { padding: 7px 11px; font-weight: 700; color: var(--accent); border-style: dashed; border-color: var(--border-strong); flex: 0 0 auto; }
.mod-add:hover { border-color: var(--accent); color: var(--accent); }
.sec-add { padding: 6px 10px; font-weight: 700; color: var(--accent); border-style: dashed; border-color: var(--border-strong); flex: 0 0 auto; }
.sec-add:hover { border-color: var(--accent); color: var(--accent); }

.link-btn {
  border: none; background: none; padding: 0;
  color: var(--accent); font-size: var(--fs-xs); font-family: inherit;
  cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
/* «+ Добавить материал»/«Удалить материал» под Материал корпуса/Материал
   фасада/Задняя стенка в «Параметрах проекта» (см. app.js:
   materialPickActionsHtml) — та же пара ссылок, что и в «Библиотеке», в ряд
   под своим <select>. */
.lib-pick-actions { display: flex; gap: var(--sp-3); margin-top: 5px; }
/* иконочная кнопка */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: 1px solid var(--border);
  background: var(--surface-solid);
  color: var(--text-2);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); }
.icon-btn svg { width: 17px; height: 17px; }
.icon-btn.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* сегментированный переключатель видов */
.view-btns {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.view-btn {
  border: none; background: transparent; padding: 6px 12px; border-radius: 7px;
  font-size: var(--fs-sm);
}
.view-btn:hover { background: var(--surface-3); }
.view-btn.active {
  background: var(--surface-solid);
  color: var(--accent);
  border: none;
  box-shadow: var(--shadow-1);
}
[data-theme='dark'] .view-btn.active { background: var(--accent-soft); }

.project-btns { display: flex; gap: var(--sp-1); }

/* ---------- 5. СЦЕНА (3D во весь экран) ---------------------------------- */

.stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  /* clip, а не hidden: спрятанные за экран панели не должны делать сцену
     прокручиваемой — иначе scrollIntoView внутри вкладок «уводит» 3D вбок */
  overflow: hidden;
  overflow: clip;
  background: var(--stage);
}
.stage::before {
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 44px 44px;
  pointer-events: none;
  opacity: .9;
}
/* touch-action: none — иначе на тач-устройствах браузер перехватывает жест
   пальцем как прокрутку/зум страницы раньше, чем до него доберётся наш
   pointermove-обработчик в SimpleOrbitControl (viewer.js), и вращать/двигать
   сцену пальцем не получается вообще. */
#viewer3d { position: absolute; inset: 0; z-index: 1; touch-action: none; }
#viewer3d canvas { display: block; touch-action: none; }

.view-overlay { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.ov-svg { display: block; width: 100%; height: 100%; }
.ov-dim { stroke: var(--accent); stroke-width: 1.1; }
.ov-ext { stroke: var(--accent); stroke-width: .7; stroke-dasharray: 3 2; }
.ov-t {
  font: 600 11px var(--ff); fill: var(--accent); text-anchor: middle;
  paint-order: stroke; stroke: var(--bg-2); stroke-width: 3px; stroke-linejoin: round;
}
.ov-inner { font-size: 10px; }

/* предупреждения — плавающая плашка снизу по центру. bottom/z-index
   подняты над панелью видов .stage-dock (bottom: var(--sp-4), z-index: 28)
   тем же значением, что и у .access-gate ниже — иначе многострочное
   предупреждение перекрывается кнопками «Спереди/Сбоку/Сверху/3D». */
.warnings {
  position: absolute; left: 50%; bottom: 78px; transform: translateX(-50%);
  z-index: 29; max-width: min(680px, 82vw);
  font-size: var(--fs-sm); line-height: 1.45; color: var(--danger);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--danger); border-left-width: 3px;
  border-radius: var(--r-md);
  padding: 8px 14px;
  box-shadow: var(--shadow-2);
  transition: opacity var(--dur-slow) var(--ease);
}
.warnings:empty { display: none; }

/* гейт доступа (401/402 при экспорте, "нужна подписка") — плашка того же
   типа, что и .warnings выше, но акцентная, а не «опасная»: это призыв к
   действию (войти/оплатить), а не ошибка геометрии проекта. Тот же bottom/
   z-index, что и у .warnings — обе подняты над нижней плавающей панелью
   видов .stage-dock (bottom: var(--sp-4), z-index: 28), там как раз лежит
   кликабельная кнопка действия, её нельзя перекрывать. */
.access-gate {
  position: absolute; left: 50%; bottom: 78px; transform: translateX(-50%);
  z-index: 29; max-width: min(680px, 82vw);
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-sm); line-height: 1.45; color: var(--text);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--accent); border-left-width: 3px;
  border-radius: var(--r-md);
  padding: 8px 10px 8px 14px;
  box-shadow: var(--shadow-2);
}
.access-gate-actions { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }

/* ---------- 6. РЕЙКА ТРИГГЕРОВ ------------------------------------------- */

.rail {
  position: absolute;
  left: var(--sp-3);
  top: 50%;
  transform: translateY(-50%);
  /* Выше открытой панели (.drawer, z-index 36) — иначе рейка сама видна
     нормально (панель её визуально не перекрывает), но всплывающая
     подсказка кнопки (.tip::after, z-index 60) рисуется ВНУТРИ
     собственного стекового контекста .rail и не может оказаться поверх
     соседней панели с более высоким z-index, даже имея больший z-index
     сама по себе — подсказка пропадала под открытой панелью параметров. */
  z-index: 38;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px;
  border-radius: var(--r-xl);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2);
  opacity: .72;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.rail:hover { opacity: 1; }

.rail-btn {
  position: relative;
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-md);
  background: transparent; color: var(--text-2);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.rail-btn svg { width: 20px; height: 20px; }
.rail-btn:hover { background: var(--surface-2); color: var(--text); }
.rail-btn.active { background: var(--accent-soft); color: var(--accent); }
.rail-btn.active::before {
  content: ''; position: absolute; left: -6px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 20px; border-radius: 2px; background: var(--accent);
}
.rail-sep { height: 1px; margin: 2px 8px; background: var(--border); }

/* подсказка по наведению */
.tip { position: relative; }
.tip::after {
  content: attr(data-tip);
  position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%) scale(.96);
  padding: 5px 9px; border-radius: var(--r-sm);
  background: var(--surface); color: var(--text);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--border); box-shadow: var(--shadow-2);
  font-size: var(--fs-xs); font-weight: 500;
  /* Перенос по словам + ограничение ширины — иначе длинная подсказка
     (например, у вкладки модуля или у миниатюры пресета, где в data-tip
     склеены название и примечание) рисуется одной строкой без предела
     ширины и вылезает за край узкой панели, обрезаясь контейнером с
     overflow. С переносом строк подсказка остаётся в разумных пределах
     независимо от длины текста и позиции элемента внутри панели. */
  white-space: normal; max-width: 220px; text-align: left;
  opacity: 0; pointer-events: none;
  transition: opacity .18s var(--ease), transform .18s var(--ease);
  z-index: 60;
}
.tip:hover::after { opacity: 1; transform: translateY(-50%) scale(1); transition-delay: 2s; }
.tip.tip-down::after { left: 50%; top: calc(100% + 8px); transform: translateX(-50%) scale(.96); }
.tip.tip-down:hover::after { transform: translateX(-50%) scale(1); }

/* подсказка из нескольких пар «клавиша — действие» (например, кнопка
   горячих клавиш) — каждая пара на своей строке по литеральному переносу
   в data-tip, без обрезания и без разрыва пары посередине. Модификатор
   отдельный от .tip::after, чтобы не задеть остальные (однострочные)
   подсказки в проекте.
   width: max-content нужен из-за того, что containing block у ::after —
   сама кнопка (узкая, ~36px): без явного width браузер считает
   shrink-to-fit от доступного места СПРАВА от кнопки внутри неё же, а не
   от текста, и сжимает подсказку до ширины одного слова, разрывая пары
   "клавиша — действие" на две строки. */
.tip.tip-lines::after {
  white-space: pre-line; width: max-content; max-width: 260px;
  font-size: 12px; line-height: 1.5;
}

/* нижняя плавающая панель видов */
.stage-dock {
  position: absolute; left: 50%; bottom: var(--sp-4); transform: translateX(-50%);
  z-index: 28;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 6px;
  border-radius: var(--r-xl);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-2);
  transition: opacity var(--dur-slow) var(--ease);
}
.stage-dock .view-btns { background: transparent; border: none; padding: 0; }

/* ---------- 7. ВЫДВИЖНЫЕ ПАНЕЛИ (off-canvas) ----------------------------- */

.scrim {
  display: none;                 /* на десктопе панели не блокируют холст */
  position: absolute; inset: 0; z-index: 34;
  background: rgba(8, 12, 20, .28);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
body.has-modal-drawer .scrim { opacity: 1; pointer-events: auto; }

.drawer {
  position: absolute;
  z-index: 36;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-3);
  opacity: 0;
  visibility: hidden;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              visibility 0s linear var(--dur);
}
.drawer.open { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }

.drawer-left {
  left: 0; top: var(--sp-3); bottom: var(--sp-3);
  width: var(--drawer-w);
  margin-left: calc(var(--rail-w) + var(--sp-3));
  border-radius: var(--r-lg);
  transform: translateX(calc(-100% - var(--rail-w) - var(--sp-4)));
}
.drawer-right {
  right: var(--sp-3); top: var(--sp-3); bottom: var(--sp-3);
  width: 300px;
  border-radius: var(--r-lg);
  transform: translateX(calc(100% + var(--sp-4)));
}

/* Библиотека: на вкладках «Материалы»/«Фурнитура» (класс .lib-wide,
   переключается в app.js renderLibraryPanel()) панель шире, чем «База
   модулей» — под таблицы каталога с колонками цены/образца/фильтров. Ширина
   ФИКСИРОВАННАЯ (не max-content — раньше панель подстраивалась под самую
   широкую таблицу, из-за чего разные разделы визуально «плавали» разной
   шириной, см. .lib-table ниже: теперь все таблицы сами разложены под одну
   и ту же ширину колонок через table-layout:fixed). max-width — только
   подстраховка на узких экранах, не основной механизм. Тот же переход, что
   и у .drawer, плюс width, чтобы смена ширины при переключении вкладок
   анимировалась. */
#drawer-library {
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              visibility 0s linear var(--dur), width var(--dur) var(--ease);
}
#drawer-library.lib-wide { width: 640px; max-width: 92vw; }
.drawer-bottom {
  /* левый край — за рейкой триггеров, чтобы она оставалась доступной */
  left: calc(var(--rail-w) + var(--sp-3)); right: var(--sp-3); bottom: var(--sp-3);
  height: min(62vh, 560px);
  border-radius: var(--r-lg);
  transform: translateY(calc(100% + var(--sp-4)));
}

.drawer-head {
  flex: none;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 12px var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.drawer-title {
  margin: 0; flex: 1;
  font-size: var(--fs-sm); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted);
}
.drawer-close {
  width: 28px; height: 28px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--muted); cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.drawer-close:hover { background: var(--surface-2); color: var(--text); }
.drawer-close svg { width: 15px; height: 15px; }

.drawer-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: var(--sp-4); }
.drawer-bottom .drawer-body { padding: 0; display: flex; flex-direction: column; }

/* поиск в панели */
.drawer-search { position: relative; margin-bottom: var(--sp-3); }
.drawer-search input {
  width: 100%; padding: 8px 10px 8px 32px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text);
  font-family: inherit; font-size: var(--fs-sm);
}
.drawer-search svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: var(--muted); pointer-events: none;
}
.dim-out { display: none !important; }

/* заголовок раздела внутри панели «Студия» */
.drawer-section {
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted);
}
.drawer-section:first-child { margin-top: 0; }
.studio-list { display: flex; flex-direction: column; gap: 6px; }
.studio-list .btn { width: 100%; text-align: left; padding: 9px 12px; font-size: var(--fs-md); }

/* ---------- 7.1 ПОЛНОЭКРАННЫЙ РЕДАКТОР ВЫРЕЗОВ ДЕТАЛИ --------------------- */
/* Отдельный полноэкранный режим (не .drawer) поверх всего интерфейса — вход
   с экрана «Деталь» (partBlock, кнопка «Открыть визуальный редактор вырезов»),
   выход красным крестиком возвращает в режим фокуса на модуле. Этап 1: только
   контейнер и статичный вид детали, без интерактива (см. src/app.js). */
.part-editor-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;              /* выше шапки (40), рейки (38), панелей (36), HUD (32), ctx-menu/поповеров (60) */
  display: flex;
  flex-direction: column;
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  opacity: 0;
  visibility: hidden;
  transform: scale(.98);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
              visibility 0s linear var(--dur);
}
.part-editor-overlay.open {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

.part-editor-head {
  flex: none;
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-1);
}
.part-editor-title {
  margin: 0; flex: 1;
  font-size: var(--fs-lg); font-weight: 700;
  color: var(--text);
}
.part-editor-close { width: 34px; height: 34px; flex: none; }

.part-editor-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
  overflow: auto;
}
.part-editor-canvas {
  max-width: 100%;
  max-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.part-editor-canvas .hint { max-width: 420px; text-align: center; }

/* ---------- 8. СОДЕРЖИМОЕ ПАНЕЛИ ПАРАМЕТРОВ ------------------------------ */

.panel h3 {
  margin: var(--sp-5) 0 var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--muted);
}
.panel h3:first-child { margin-top: 0; }
.panel h3.screen-title { color: var(--accent); }
.panel h4.mat-sub {
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
}

.field { margin-bottom: var(--sp-3); }
.field > label {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-bottom: 5px;
  font-weight: 500;
}
.field input,
.field select,
.mini-row input,
.sub input,
.sub select,
input[type='number'],
input[type='text'] {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--surface-solid);
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
input[type='number'] { font-family: var(--ff-mono); }
.field select, select {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--surface-solid);
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-md);
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 26px;
  /* Подстраховка на случай тесной колонки (см. .field-row-wide-action ниже
     по файлу):
     если текст опции всё же не влезает, обрезаем его многоточием, а не
     серединой слова. В Firefox на закрытом <select> может не сработать —
     тогда просто вернётся к обычной обрезке, не хуже, чем было. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.field input:focus, .field select:focus, select:focus, input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.field input[type='checkbox'] { width: auto; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2); }
/* Строки «Ящики, шт» и «Полки, шт» (renderSectionsList): числовому полю
   хватает 1-2 цифр, а соседняя кнопка/select с текстом («Редактировать
   ящики →», «Равномерно»/«Вручную») читается тесно на ровно половине узкой
   боковой панели — перекашиваем колонки в их пользу. Один и тот же
   модификатор у обеих строк, чтобы кнопка ящиков и select полок были одной
   ширины друг с другом. */
.field-row-wide-action { grid-template-columns: 0.5fr 1.5fr; }
.field-row3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.field-row3 .field input { padding: 7px 6px; text-align: center; }
/* Свесы столешницы (панель «Столешница»): 4 узких числовых поля в один ряд —
   тот же приём, что и .field-row3 выше, только на 4 колонки. */
.field-row4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.field-row4 .field input { padding: 7px 4px; text-align: center; }
/* Вторая колонка .field-row, где вместо своего поля стоит кнопка/select без
   подписи (см. .field-row-btn выше, «Ящики, шт»/«Полки, шт» в карточке
   секции) — label остаётся в разметке (&nbsp;) только чтобы занять ту же
   высоту, что и подпись соседнего поля, сам текст не нужен и не читается
   скринридером. */
.field-row-action > label { visibility: hidden; }

.checkbox-field label,
.checkbox-inline {
  display: flex !important; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-2); cursor: pointer;
  user-select: none;
}
.checkbox-inline input,
.checkbox-field input { width: auto !important; margin: 0; accent-color: var(--accent); }

.hint { font-size: var(--fs-xs); line-height: 1.45; color: var(--muted); margin: 4px 0 var(--sp-2); }
.hint a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.dim { color: var(--muted); font-weight: 400; }
.mt6 { margin-top: 6px; display: block; font-size: var(--fs-sm); color: var(--text-2); }
.mini-row { display: flex; gap: 6px; margin-top: 4px; }
.sub { margin-top: var(--sp-2); padding-left: var(--sp-2); border-left: 2px solid var(--border); }
.sub label { font-size: var(--fs-sm); color: var(--text-2); }

/* Ряд вкладок модулей проекта (moduleTabsBlock() в app.js) — не переносится
   на вторую строку: при 50+ модулях перенос заполнил бы всю панель. Вместо
   этого ряд скроллится по горизонтали (nowrap + overflow-x, колесо мыши —
   см. bindPanelEvents), та же визуальная логика, что и у .sec-tabs ниже.
   «+» (.mod-add) — вне этого ряда, в .mod-tabs-row, чтобы не уезжать за
   край при прокрутке. */
.mod-tabs-row { display: flex; align-items: flex-start; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.mod-tabs {
  display: flex; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; gap: var(--sp-1);
  flex: 1 1 auto; min-width: 0; padding-bottom: 2px;
}
.mod-tab {
  display: flex; align-items: center; flex: 0 0 auto;
  padding: 6px 10px; font-size: var(--fs-sm); border-radius: var(--r-sm); white-space: nowrap;
}
.mod-search { margin-bottom: var(--sp-2); }

/* Вкладки секций внутри модуля (renderSectionsList() в app.js) — та же
   визуальная логика, что и у .mod-tabs/.mod-tab выше (те же переменные,
   радиусы, отступы), но с ДВУМЯ осознанными отличиями: ряд не переносится
   на вторую строку, а скроллится по горизонтали (nowrap + overflow-x —
   секций внутри модуля может быть 5-6+, вторая строка тут менее уместна,
   чем горизонтальная прокрутка), и крестик-удаление есть только у активной
   (раскрытой) вкладки — на свёрнутых вкладках его нет. «+» (.sec-add) — вне
   скроллящегося ряда, в .sec-tabs-row, по тому же принципу, что и у
   .mod-tabs-row выше. */
.sec-tabs-row { display: flex; align-items: flex-start; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.sec-tabs {
  display: flex; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; gap: var(--sp-1);
  flex: 1 1 auto; min-width: 0; padding-bottom: 2px;
}
.sec-tab {
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 6px 10px; font-size: var(--fs-sm); border-radius: var(--r-sm); white-space: nowrap;
}
.sec-tab-remove {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; flex: 0 0 auto;
  font-size: 10px; line-height: 1; color: var(--muted);
  transition: all var(--dur) var(--ease);
}
.sec-tab-remove:hover { color: var(--danger); background: var(--danger-soft); }

.section-card {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  margin-bottom: var(--sp-2);
  background: var(--surface-2);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.section-card:hover { border-color: var(--border-strong); }
.section-card-title {
  display: flex; justify-content: space-between; align-items: center;
  font-weight: 600; font-size: var(--fs-md); color: var(--text);
  margin-bottom: var(--sp-2);
}
.remove-section {
  border: none; background: none; cursor: pointer;
  color: var(--muted); font-size: var(--fs-sm); padding: 2px 6px; border-radius: 4px;
  transition: all var(--dur) var(--ease);
}
.remove-section:hover { color: var(--danger); background: var(--danger-soft); }

.add-section-btn { width: 100%; margin-top: var(--sp-2); padding: 9px 12px; }

/* Экран «Деталь» → крыша из планок, переключатель «на ребро» (partBlock() в
   app.js). Цвет вкл/выкл — обычный .btn/.active, здесь только раскладка. */
.part-top-edge-btn { display: block; width: 100%; margin: var(--sp-2) 0 var(--sp-3); text-align: center; }

/* Экран «Деталь» → список ручных доп. отверстий (см. partBlock() в app.js) */
.extra-hole-row { margin-bottom: var(--sp-2); padding-bottom: var(--sp-2); border-bottom: 1px dashed var(--border); }
.extra-hole-row:last-child { border-bottom: none; }
.extra-hole-row .remove-section { display: block; margin-top: 2px; padding: 2px 0; }
/* Цвета осей совпадают буквально с подсветкой рёбер детали в 3D (viewer.js: 0xe03131/0x2f9e44) */
.axis-label-x { color: #e03131; }
.axis-label-y { color: #2f9e44; }

.lib-row { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
/* Уже уменьшенный горизонтальный отступ (было 12px, как у обычных .btn) —
   чтобы все три категории («Шкаф», «Тумба», «Кухонный модуль») помещались
   в один ряд на стандартной ширине панели «Библиотека» (340px). */
.lib-cat { padding-left: 8px; padding-right: 8px; font-weight: 600; color: var(--accent); border-color: var(--border-strong); }
.lib-cat:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.lib-cat.on { background: var(--accent-soft); border-color: var(--accent); }

/* Сетка миниатюр открытой категории «Базы модулей» — рендерится прямо в
   панели под рядом кнопок-категорий (см. libraryGridBlock() в app.js). */
.lib-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 8px; }
/* Заголовок группы плиток по `tier` (например, «Нижние модули» / «Верхние
   модули» для кухонных модулей) — на всю ширину сетки, см. libraryGridBlock().
   Показывается и перед самой первой группой, не только между группами. */
.lib-grid-heading {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
  padding-bottom: 4px;
  margin-top: 4px;
  border-bottom: 1px solid var(--border);
}
/* У самой первой плитки в сетке заголовок не должен создавать лишний
   отступ сверху (он и так margin-top:8px у .lib-grid) — компенсируем. */
.lib-grid-heading:first-child { margin-top: 0; }
/* Подсказка «Модули появятся позже» под пустой tier-группой (см.
   libraryGridBlock() в app.js) — растягиваем на всю ширину сетки, само
   оформление текста даёт класс .hint. */
.lib-grid-empty { grid-column: 1 / -1; margin: 0 0 var(--sp-2); }
.lib-item {
  padding: 0; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface-2);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease);
}
.lib-item:hover { border-color: var(--accent); }
/* Скругление — на самой картинке, не на .lib-item: этот элемент несёт
   класс .tip (всплывающая подсказка с названием пресета), а overflow:hidden
   на нём самом обрезал бы подсказку (она — тоже дочерний элемент .lib-item,
   как псевдоэлемент ::after) вместе с картинкой. */
.lib-thumb {
  display: block; width: 100%; aspect-ratio: 1 / 1; object-fit: contain;
  border-radius: var(--r-sm);
}

.passport-ok { font-size: var(--fs-xs); color: var(--ok); margin-top: 6px; }
.passport-warn { font-size: var(--fs-xs); color: var(--warn); margin-top: 6px; }

/* ---------- 9. ДОКУМЕНТЫ (чертежи / деталировка / спецификация) ---------- */

.results { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }

.tabs {
  flex: none;
  display: flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.tab-btn {
  border: none; background: none;
  padding: 7px 13px; border-radius: var(--r-sm);
  font-family: inherit; font-size: var(--fs-md); font-weight: 500;
  color: var(--muted); cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.tab-btn:hover { background: var(--surface-2); color: var(--text); }
.tab-btn.active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.spacer { flex: 1; }

/* панели документов видимы, когда открыта соответствующая вкладка */
.tab-panel { display: none; }
.tab-panel.active { display: block; flex: 1 1 auto; overflow: auto; padding: var(--sp-3) var(--sp-4); min-height: 0; }

table { border-collapse: collapse; width: 100%; font-size: var(--fs-sm); color: var(--text); }
th, td {
  border: 1px solid var(--border);
  padding: 6px 9px; text-align: left; white-space: nowrap;
}
th {
  background: var(--surface-2); color: var(--text-2);
  position: sticky; top: 0; z-index: 2;
  font-weight: 600; font-size: var(--fs-xs);
  text-transform: uppercase; letter-spacing: .04em;
}
tbody tr:hover td { background: var(--surface-2); }
tfoot td { font-weight: 700; background: var(--surface-2); }
h4.spec-title { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-md); font-weight: 700; color: var(--text); }
.total-line {
  margin-top: var(--sp-4); padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-lg); font-weight: 700; text-align: right;
  color: var(--accent); background: var(--accent-soft); border-radius: var(--r-md);
}

/* чертежи */
.dw-head { font-size: var(--fs-sm); color: var(--muted); margin-bottom: var(--sp-3); padding-bottom: var(--sp-2); border-bottom: 1px solid var(--border); }
.dw-h { margin: var(--sp-5) 0 var(--sp-3); font-size: var(--fs-md); font-weight: 700; color: var(--text); text-transform: uppercase; letter-spacing: .06em; }
.dw-grid { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: flex-start; }
.dw-block { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3); background: var(--surface-solid); }
.dw-title { font-size: var(--fs-sm); font-weight: 600; margin-bottom: 6px; color: var(--text-2); }
.dw-note { font-size: 10.5px; color: var(--muted); margin-top: 4px; }
.dw-svg { display: block; max-width: none; overflow: visible; }
.dw-secrow { display: flex; gap: var(--sp-3); align-items: flex-start; flex-wrap: wrap; }
.dw-empty { font-size: var(--fs-sm); color: var(--muted); }
.dw-wide { width: 100%; }
.dw-wire { fill: none; stroke: var(--text); stroke-width: 1; }
.dw-wire-back { fill: none; stroke: var(--muted); stroke-width: .5; stroke-dasharray: 5 3; }
.dw-part { fill: var(--surface-2); stroke: var(--text); stroke-width: 1; }
.dw-back { fill: var(--surface-2); stroke: var(--muted); stroke-width: .5; stroke-dasharray: 4 2; }
.dw-drawer { fill: var(--surface-2); stroke: var(--text); stroke-width: .7; }
.dw-facade { fill: var(--surface-2); stroke: var(--accent); stroke-width: 1.2; }
.dw-open { fill: none; stroke: var(--accent); stroke-width: 1.4; }
.dw-dim { stroke: var(--accent); stroke-width: .5; }
.dw-ext { stroke: var(--muted); stroke-width: .35; }
.dw-axis { stroke: var(--accent); stroke-width: .35; stroke-dasharray: 12 3 2 3; }
.dw-arrow { fill: var(--accent); }
.dw-thin { stroke: var(--muted); stroke-width: .5; }
.dw-handle { fill: none; stroke: var(--text); stroke-width: 1; }
.dw-dt { font: 10px var(--ff); fill: var(--accent); }
.dw-t { font: 10px var(--ff); fill: var(--text); }
.dw-sec { font: 600 10px var(--ff); fill: var(--text); }
.dw-vname { font: 600 10px var(--ff); fill: var(--accent); letter-spacing: .06em; }
.dw-hole { fill: var(--surface-solid); stroke: var(--accent); stroke-width: .8; }
.dw-pos { fill: var(--surface-solid); stroke: var(--text); stroke-width: .7; }
.dw-post { font: 600 8px var(--ff); fill: var(--text); }
.dw-legend { border-collapse: collapse; font-size: var(--fs-xs); width: auto; color: var(--text); }
.dw-legend th, .dw-legend td { border: 1px solid var(--border); padding: 3px 7px; white-space: nowrap; }
.dw-legend th { background: var(--surface-2); }

/* ---------- 10. HUD — меню прямо на модели -------------------------------- */

.hud {
  position: absolute; z-index: 32;
  width: 262px;
  padding: var(--sp-3);
  border-radius: var(--r-md);
  background: var(--surface);
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-3);
  opacity: 0; visibility: hidden; transform: scale(.94) translateY(4px);
  transform-origin: top left;
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility 0s linear .2s;
}
.hud.open { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
.hud-title {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  font-size: var(--fs-md); font-weight: 700; color: var(--text);
  margin-bottom: var(--sp-2);
}
.hud-title .hud-close {
  border: none; background: none; color: var(--muted); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 2px 4px; border-radius: 4px;
}
.hud-title .hud-close:hover { color: var(--text); background: var(--surface-2); }
.hud-dims { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-bottom: var(--sp-2); }
.hud-dim { display: flex; flex-direction: column; gap: 3px; }
.hud-dim span { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.hud-dim input {
  width: 100%; padding: 5px 6px; text-align: center;
  font-family: var(--ff-mono); font-size: var(--fs-sm);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-solid); color: var(--text);
}
.hud-meta { font-size: var(--fs-xs); color: var(--muted); margin-bottom: var(--sp-2); line-height: 1.45; overflow-wrap: anywhere; }
.hud-group { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin-bottom: 4px; }
.hud-actions { display: flex; gap: 6px; }
.hud-actions .btn { flex: 1; padding: 6px 8px; font-size: var(--fs-xs); text-align: center; }
.hud-full { display: block; width: 100%; margin-top: 6px; text-align: center; }
.hud-numrow { display: flex; gap: 6px; margin-top: 6px; align-items: center; }
.hud-numrow input[type="number"] {
  width: 56px; box-sizing: border-box; font-family: inherit; font-size: var(--fs-sm);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text); padding: 5px 6px;
}
.hud-numrow .btn { flex: 1; }

/* ---------- 11. КОНТЕКСТНОЕ МЕНЮ (переименование модуля, меню фокуса) ----- */

.ctx-menu {
  position: fixed; z-index: 60; min-width: 214px; padding: 6px;
  background: var(--surface-solid);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
}
.ctx-title { font-size: var(--fs-sm); font-weight: 700; padding: 5px 9px 7px; color: var(--text); }
.ctx-title-input {
  display: block; width: 100%; box-sizing: border-box;
  margin-bottom: 2px; font-family: inherit;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent;
}
.ctx-title-input:hover { background: var(--surface-2); }
.ctx-title-input:focus { background: var(--surface-2); border-color: var(--accent); outline: none; }
.ctx-group { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: 5px 9px 3px; }
.ctx-item {
  display: block; width: 100%; text-align: left; border: none; background: none;
  padding: 7px 9px; border-radius: var(--r-sm);
  font-family: inherit; font-size: var(--fs-sm); color: var(--text); cursor: pointer;
  transition: background var(--dur) var(--ease);
}
.ctx-item:hover { background: var(--surface-2); }
.ctx-item.on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.ctx-item.danger { color: var(--danger); }
.ctx-item.danger:hover { background: var(--danger-soft); }
.ctx-sep { height: 1px; margin: 5px 4px; background: var(--border); }
/* Составной пункт меню: число + кнопка в одной строке (например «Разделить
   на секции по вертикали» у фасада в режиме фокуса, см. showFocusMenu). */
.ctx-numrow { display: flex; gap: 6px; padding: 2px 9px 7px; align-items: center; }
.ctx-numrow input[type="number"] {
  width: 56px; box-sizing: border-box; font-family: inherit; font-size: var(--fs-sm);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text); padding: 5px 6px;
}
.ctx-numrow .ctx-item { width: auto; flex: 1; text-align: center; background: var(--surface-2); }
.ctx-numrow .ctx-item:hover { background: var(--accent-soft); color: var(--accent); }

/* ---------- 12. ПОПОВЕРЫ (эскиз ИИ, API-ключ) ----------------------------- */

.popover {
  background: var(--surface-solid);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  padding: var(--sp-3);
}
/* внутри выдвижной панели поповер встроен в поток, а не висит абсолютно */
.drawer .popover { position: static; width: auto; margin-top: var(--sp-2); }
.drawer .popover label { display: block; font-size: var(--fs-sm); color: var(--text-2); margin-bottom: 6px; }
.sketch-preview {
  width: 100%; max-height: 170px; object-fit: contain;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  margin-bottom: var(--sp-2); background: var(--surface-2);
}
.sketch-status { font-size: var(--fs-sm); margin-top: var(--sp-2); color: var(--muted); white-space: pre-wrap; line-height: 1.45; }
.sketch-status.error { color: var(--danger); }
.sketch-status.ok { color: var(--ok); }

/* ---------- 13. ЛЕГЕНДА ПРИСАДКИ ----------------------------------------- */

.drill-legend-inline {
  font-size: var(--fs-xs); line-height: 1.5; color: var(--text);
}
.drill-legend-inline:empty { display: none; }
.drill-legend-inline b { display: block; margin: var(--sp-3) 0 6px; font-size: var(--fs-sm); color: var(--text); }
.drill-legend-inline .dl-row {
  display: flex; align-items: flex-start; gap: 7px;
  padding: 4px 6px; margin: 0 -6px; border-radius: var(--r-sm);
  cursor: pointer;
  transition: background var(--dur) var(--ease);
}
.drill-legend-inline .dl-row:hover { background: var(--surface-2); }
.drill-legend-inline .dl-row.on { background: var(--accent-soft); font-weight: 600; }
.drill-legend-inline i { width: 10px; height: 10px; border-radius: 3px; flex: none; margin-top: 4px; }
.drill-legend-inline span { flex: 1; }
.drill-legend-inline small { display: block; color: var(--muted); font-size: 10.5px; }
.drill-legend-inline .dl-hint { margin-top: 6px; color: var(--muted); font-size: 10.5px; }

/* ---------- 14. БИБЛИОТЕКА (база модулей / материалы / фурнитура) -------- */

.lib-tabs { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-3); flex-wrap: wrap; }
.lib-tab-btn {
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2);
  padding: 7px 12px; border-radius: var(--r-sm);
  font-family: inherit; font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.lib-tab-btn:hover { border-color: var(--accent); color: var(--text); }
.lib-tab-btn.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* Вкладка «Материалы» (app.js: libTopCategoryHtml/libNodeHtml/
   libTreeRowHtml) — дерево категорий ПРОИЗВОЛЬНОЙ глубины: одна строка на
   узел (не ряд кнопок-«таблеток», как раньше), отступ слева пропорционален
   глубине (инлайн style в libTreeRowHtml — 16px/уровень), клик — по всей
   строке. Верхнеуровневая категория («Листовые материалы» и т.п., depth 0)
   — жирный акцентный текст покрупнее, не сворачивается сама целиком (см.
   .lib-tree-top ниже — только раскрывает/прячет своих детей); остальные
   уровни — обычный текст, без различий между собой, кроме отступа. */
.lib-category { margin-bottom: var(--sp-3); }
.lib-tree-row {
  display: flex; align-items: center; gap: 6px;
  padding-top: 6px; padding-bottom: 6px; padding-right: 6px;
  cursor: pointer; border-radius: var(--r-sm);
  transition: background var(--dur) var(--ease);
}
.lib-tree-row:hover { background: var(--accent-soft); }
.lib-tree-arrow { flex: 0 0 auto; width: 10px; font-size: 10px; color: var(--muted); }
.lib-tree-name { flex: 1 1 auto; font-size: var(--fs-sm); color: var(--text); }
.lib-tree-top .lib-tree-name { font-size: var(--fs-md); font-weight: 700; color: var(--accent); }
/* ✎/+/× узла — обычный текст без рамки/фона (не кнопки), курсор pointer,
   видны по наведению на СТРОКУ (не только на сам значок), лёгкая акцентная
   подсветка при наведении на сам значок. */
.lib-tree-actions { flex: 0 0 auto; display: flex; gap: 8px; opacity: 0; transition: opacity var(--dur) var(--ease); }
.lib-tree-row:hover .lib-tree-actions { opacity: 1; }
.lib-tree-ic { color: var(--muted); font-size: var(--fs-sm); line-height: 1; cursor: pointer; }
.lib-tree-ic:hover { color: var(--accent); }
/* Инлайн-переименование узла (см. startTreeRename в app.js) — тот же
   компактный инпут, что и у ячеек таблицы (.lib-table td.lib-edit-cell
   input ниже), но без обёртки в <td>. */
.lib-tree-name input {
  width: 100%; border: 1px solid var(--accent); border-radius: var(--r-sm);
  padding: 3px 5px; font-family: inherit; font-size: inherit; color: var(--text);
  background: var(--surface-solid);
}
/* Скрытие свёрнутого узла дерева — свой класс, не .dim-out (тот занят
   поиском applyLibrarySearch) и не .lib-filtered-out (тот занят фильтрами
   листа, см. ниже) — все три должны мирно сосуществовать на одной и той же
   таблице/строке одновременно. */
.lib-collapsed { display: none !important; }
/* Таблица позиций одного листа (app.js: libLeafTableHtml) — под строкой
   узла, без своего отступа: содержимое (фильтры/таблица/кнопка «+») уже не
   часть навигации по дереву, поэтому не наследует отступ глубины узла. */
.lib-leaf-body { margin: 2px 0 var(--sp-3); }

/* Фильтры внутри листа (app.js: libFiltersHtml) — компактные select рядом,
   а не на всю ширину поля, как обычный .field select. */
.lib-filters { display: flex; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.lib-filter-select { width: auto; min-width: 120px; padding: 5px 24px 5px 8px; font-size: var(--fs-xs); }
/* Строка, не подходящая под выбранные фильтры — скрыта. Отдельный от
   .dim-out класс: тот управляется поиском независимо и должен продолжать
   работать на той же строке одновременно, без конфликта. */
.lib-filtered-out { display: none !important; }

/* Редактируемые таблицы каталога (Материалы/Фурнитура) — клик по ячейке
   превращает её в инпут (см. app.js: startCellEdit). Ширина колонок — ОДНА
   и та же во всех листьях/категориях (см. #drawer-library.lib-wide выше:
   панель теперь фиксированной ширины, а не «под самую широкую таблицу»);
   фиксирует её сама таблица через table-layout:fixed (инлайн, только у
   таблиц материалов — см. libLeafTableHtml) + <colgroup> с явными шириной
   служебных колонок, «Наименование» без ширины забирает остаток. Длинное
   название переносится по словам (см. :first-child ниже), а не расширяет
   таблицу. */
.lib-table {
  margin-bottom: var(--sp-2);
  width: 100%;
  max-width: 100%;
  overflow-x: auto;   /* резервный вариант на случай нехватки места */
}
/* Узкие служебные колонки (26/50/62px в libColgroup) с обычным padding
   (9px, см. общий th,td выше) обрезали заголовок «ОБРАЗЕЦ» — виден только
   «ОБРАЗЕ». Более тесный padding именно у этих таблиц освобождает нужные
   ~6px без пересчёта самих ширин колонок. */
.lib-table th, .lib-table td { padding: 6px 5px; }
.lib-table td:first-child, .lib-table th:first-child { white-space: normal; word-break: break-word; }
.lib-table td.lib-edit-cell { cursor: text; }
.lib-table td.lib-edit-cell:hover { background: var(--accent-soft); }
.lib-table td.lib-edit-cell input {
  width: 100%; border: 1px solid var(--accent); border-radius: var(--r-sm);
  padding: 3px 5px; font-family: inherit; font-size: var(--fs-sm);
  background: var(--surface-solid); color: var(--text);
}
/* Единица измерения (field === 'unit', см. app.js: startCellEdit) — та же
   компактная посадка в ячейке таблицы, что и у input выше, только select. */
.lib-table td.lib-edit-cell select {
  width: 100%; border: 1px solid var(--accent); border-radius: var(--r-sm);
  padding: 3px 20px 3px 5px; font-family: inherit; font-size: var(--fs-sm);
  background-color: var(--surface-solid); color: var(--text);
}
.lib-add { display: inline-block; margin: 0 0 var(--sp-4); }
/* «+ Добавить материал»/«− Удалить материал» под таблицей листа (app.js:
   libLeafTableHtml) — в ряд, как .lib-pick-actions выше; собственный нижний
   отступ несёт сам .lib-leaf-actions, у кнопок внутри него он обнулён —
   иначе рассинхронились бы по вертикали между собой (у «+ Добавить позицию»
   фурнитуры вне этой обёртки .lib-add остаётся как был). */
.lib-leaf-actions { display: flex; gap: var(--sp-3); align-items: center; margin: 0 0 var(--sp-4); }
.lib-leaf-actions .lib-add, .lib-leaf-actions .lib-row-del { margin: 0; }
/* Ссылка-кнопка в неактивном состоянии (например «− Удалить материал», пока
   строка не выбрана, см. app.js: libLeafTableHtml/state.libSelectedRow) —
   без явного правила disabled-кнопка унаследовала бы обычный цвет ссылки. */
.link-btn:disabled { opacity: .45; cursor: default; text-decoration: none; }

/* Заголовок-тумблер «± характеристики» (app.js: libTableHead) — над
   колонками Длина/Ширина/Толщина, клик сворачивает/разворачивает их. */
.lib-chars-toggle { cursor: pointer; text-align: center; color: var(--muted); }
.lib-chars-toggle:hover { color: var(--accent); }
/* Свёрнутые характеристики (.chars-collapsed на самой <table>, см.
   libLeafTableHtml/state.libCharsCollapsed) — прячем и заголовки, и ячейки
   Длина/Ширина/Толщина одним правилом, без пересборки colspan остальных
   ячеек. display:none на <col> тоже работает — браузер просто не учитывает
   эту колонку в раскладке оставшихся ячеек. */
.lib-table.chars-collapsed .lib-char-col { display: none; }

/* Выбранная кликом строка таблицы (app.js: state.libSelectedRow) — под
   «− Удалить материал» ниже таблицы. Инлайн-редактируемые ячейки внутри
   такой строки сохраняют свой курсор (text/pointer) — правило ниже их не
   переопределяет, они уже описаны выше (.lib-edit-cell/.lib-swatch). */
.lib-table tbody tr.lib-row-selected { background: var(--accent-soft); }
.lib-table tbody tr[data-row-key] { cursor: pointer; }

/* Переключатель единицы цены в шапке (app.js: libPriceUnitHeaderHtml) — той
   же компактной посадки, что и .lib-filter-select. */
.lib-table th select.lib-price-unit-select {
  width: 100%; border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 3px 18px 3px 5px; font-family: inherit; font-size: var(--fs-xs);
  font-weight: 400; background-color: var(--surface-solid); color: var(--text);
}

/* Компактная ссылка-иконка на карточку товара у поставщика (item.sourceUrl,
   см. catalog.js) — отдельная узкая колонка рядом с «Наименование», не
   часть .lib-edit-cell (см. app.js: libSourceLinkCell) */
.lib-source-cell { width: 1%; padding-left: 2px; padding-right: 2px; text-align: center; }
.lib-source-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: var(--r-sm);
  color: var(--muted); text-decoration: none; font-size: 13px; line-height: 1;
  transition: all var(--dur) var(--ease);
}
.lib-source-link:hover { color: var(--accent); background: var(--accent-soft); }

/* Карточка цвета/образца материала — клик открывает загрузку файла */
.lib-swatch {
  display: block; width: 36px; height: 24px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background-color: var(--surface-2);
  background-size: cover; background-position: center; cursor: pointer;
}
.lib-swatch:hover { border-color: var(--accent); }
.lib-swatch.empty { display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 15px; }
.lib-swatch.empty::after { content: '+'; }

/* ---------- 15. ВАЛЮТА ПРОЕКТА -------------------------------------------- */

.currency-wrap { position: relative; display: inline-flex; }
.currency-wrap .popover { position: absolute; right: 0; top: calc(100% + 8px); width: 230px; z-index: 55; }
.currency-options { display: flex; flex-direction: column; gap: 5px; margin-bottom: var(--sp-3); }
.currency-opt { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); color: var(--text); cursor: pointer; }
.currency-opt input { width: auto; }

/* ---------- 15б. АККАУНТ (вход/регистрация, токены, подписка) ------------ */

.account-wrap { position: relative; display: inline-flex; }
.account-wrap .popover { position: absolute; right: 0; top: calc(100% + 8px); width: 280px; z-index: 55; }
.account-btns { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.account-btns .btn { flex: 1; }
.account-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-2); padding: 4px 0;
}
.account-row b { color: var(--text); font-weight: 600; }
#accountInfo #authLogoutBtn { width: 100%; margin-top: var(--sp-2); }
#accountInfo #accountUpgradeBtn { width: 100%; margin-top: var(--sp-2); }

/* Глазик показа/скрытия пароля (см. index.html: .password-field,
   app.js: initAccountPanel) */
.password-field { position: relative; }
.password-field input { padding-right: 32px; }
.password-toggle-btn {
  position: absolute; right: 3px; top: 50%; transform: translateY(-50%);
  width: 26px; height: 26px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; border-radius: var(--r-sm);
  background: transparent; color: var(--muted);
  cursor: pointer; transition: all var(--dur) var(--ease);
}
.password-toggle-btn:hover { background: var(--surface-2); color: var(--text); }
.password-toggle-btn svg { width: 16px; height: 16px; }

/* «Забыли пароль?» — ссылка-кнопка под полем пароля (см. app.js:
   initAccountPanel, обработчик #authForgotBtn, POST /auth/forgot-password). */
#authForgotBtn { display: inline-block; margin-top: 6px; }

/* Чекбокс согласия с условиями использования — та же ссылка-паттерн, что и
   остальные inline-чекбоксы в панели параметров, но с переносом на 2 строки
   (align-items: flex-start, а не center) и запасом сверху/снизу. */
.auth-terms {
  align-items: flex-start !important;
  margin: 2px 0 var(--sp-3);
  line-height: 1.4;
}
.auth-terms input { margin-top: 2px !important; }
.auth-terms a { color: var(--accent); }

/* Превью аватарки — при регистрации (#authAvatarPreview, до отправки формы,
   см. app.js: initAccountPanel) и в карточке аккаунта (#accountAvatarPreview,
   после GET /auth/me). Круглая рамка фиксированного размера, картинка через
   background — без "битой" иконки при пустом значении. */
.avatar-preview {
  width: 48px; height: 48px; flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--surface-2) center/cover no-repeat;
}
.avatar-upload-row { display: flex; align-items: center; gap: var(--sp-2); }
.avatar-upload-row input[type='file'] {
  flex: 1 1 auto; width: auto; padding: 6px 0;
  font-size: var(--fs-xs); color: var(--text-2);
}

/* Шапка карточки аккаунта — аватарка слева, строки «Аккаунт»/«Никнейм»
   справа (см. index.html: #accountInfo .account-header). */
.account-header { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-1); }
.account-header .avatar-preview { width: 44px; height: 44px; }
.account-header-rows { flex: 1 1 auto; min-width: 0; }
.account-header-rows .account-row { padding: 2px 0; }

/* Отзыв о приложении (#accountInfo .review-block, см. app.js:
   initAccountPanel — обработчик #reviewSubmitBtn, POST /reviews). */
.review-block {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}
.review-block label {
  display: block; font-size: var(--fs-sm); color: var(--text-2);
  margin-bottom: 5px; font-weight: 500;
}
.review-block textarea {
  width: 100%; min-height: 72px; resize: vertical;
  padding: 7px 10px;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-solid); color: var(--text);
  font-family: inherit; font-size: var(--fs-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.review-block textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.review-block .btn { width: 100%; margin-top: var(--sp-2); }

/* Панель сравнения тарифов — после регистрации и по клику «Оформить
   подписку» в карточке аккаунта (см. index.html: #plansPanel, app.js:
   showPlansPanel). Попап «Аккаунт» узкий (280px), поэтому карточки идут
   вертикально одна под другой, а не колонками. */
.account-wrap #plansPanel { width: 100%; }
.plan-card {
  border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--sp-3); margin-bottom: var(--sp-3);
  background: var(--surface-2);
}
.plan-card:last-child { margin-bottom: 0; }
.plan-card h4 { margin: 0 0 var(--sp-2); font-size: var(--fs-md); color: var(--text); }
.plan-card ul { margin: 0 0 var(--sp-3); padding-left: 18px; }
.plan-card li { font-size: var(--fs-sm); color: var(--text-2); margin-bottom: 4px; line-height: 1.4; }
.plan-card li:last-child { margin-bottom: 0; }
.plan-card .btn { width: 100%; }
.plan-card-paid { background: var(--accent-soft); border-color: var(--accent); }

/* Отменить/Вернуть/Удалить в шапке — иконки-глифы вместо svg */
.icon-btn-text { font-size: 15px; font-weight: 700; font-family: inherit; }
.icon-btn.danger { color: var(--danger); }
.icon-btn.danger:hover { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.icon-btn:disabled { opacity: .4; cursor: default; pointer-events: none; }
.btn:disabled { opacity: .5; cursor: default; pointer-events: none; }

/* ---------- 16. FOCUS MODE ------------------------------------------------ */
/* при вращении / зуме / перетаскивании интерфейс растворяется до 0 */

body.is-focus .topbar,
body.is-focus .rail,
body.is-focus .stage-dock,
body.is-focus .drawer,
body.is-focus .hud,
body.is-focus .warnings,
body.is-focus .mobile-sheet-bar {
  opacity: 0 !important;
  pointer-events: none !important;
}
body.is-focus .scrim { opacity: 0 !important; }

/* ---------- 17. МОБИЛЬНАЯ РАСКЛАДКА -------------------------------------- */

.mobile-sheet-bar { display: none; }

@media (max-width: 820px) {
  :root { --topbar-h: 48px; --drawer-w: 100%; }

  /* мобильная раскладка и так занимает всю доступную ширину шторки —
     подстройку под содержимое таблиц (см. #drawer-library.lib-wide выше)
     здесь отключаем, чтобы не отличаться от остальных панелей */
  #drawer-library.lib-wide { width: 100%; max-width: 100%; }

  .brand-sub, .brand .ver { display: none; }
  /* Скрываем только Сохранить/Открыть (текстовые кнопки, не помещаются) —
     #historyBtns (Отменить/Вернуть/Удалить, компактные icon-btn) остаются
     видимыми, иначе на мобильном пропадает доступ к undo/redo/удалению. */
  .header-actions #projectBtns { display: none; }

  .rail { display: none; }
  .scrim { display: block; }
  .stage-dock { bottom: calc(var(--sheet-h) + 10px); padding: 4px; }
  .stage-dock .view-btn { padding: 6px 10px; }

  /* нижняя шторка 40 px — открывается свайпом вверх или тапом */
  .mobile-sheet-bar {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 30;
    height: var(--sheet-h);
    display: flex; align-items: center; justify-content: space-around;
    padding: 0 var(--sp-2);
    background: var(--surface);
    -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
    border-top: 1px solid var(--border);
    box-shadow: 0 -6px 24px -12px rgba(0, 0, 0, .35);
    touch-action: none;
    transition: opacity var(--dur-slow) var(--ease);
  }
  .mobile-sheet-bar::before {
    content: ''; position: absolute; left: 50%; top: 5px; transform: translateX(-50%);
    width: 38px; height: 4px; border-radius: 2px; background: var(--border-strong);
  }
  .mobile-sheet-bar .rail-btn { width: 44px; height: 32px; margin-top: 5px; }
  .mobile-sheet-bar .rail-btn svg { width: 18px; height: 18px; }
  .mobile-sheet-bar .rail-btn.active::before { display: none; }
  .mobile-sheet-bar .tip::after { display: none; }

  /* все панели превращаются в нижние листы */
  .drawer,
  .drawer-left,
  .drawer-right,
  .drawer-bottom {
    left: 0; right: 0; bottom: 0; top: auto;
    width: auto; margin: 0;
    height: 80vh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-left: none; border-right: none; border-bottom: none;
    transform: translateY(100%);
  }
  .drawer::before {
    content: ''; position: absolute; left: 50%; top: 7px; transform: translateX(-50%);
    width: 40px; height: 4px; border-radius: 2px; background: var(--border-strong);
  }
  .drawer-head { padding-top: 18px; }
  .warnings { bottom: calc(var(--sheet-h) + 56px); max-width: 92vw; }
  .access-gate { bottom: calc(var(--sheet-h) + 116px); max-width: 92vw; flex-wrap: wrap; }
  .hud { width: 232px; }
}

@media (max-width: 480px) {
  .topbar { padding: 0 var(--sp-3); }
  .tabs { padding: var(--sp-2); }
  .tab-btn { padding: 6px 9px; font-size: var(--fs-sm); }
  .tabs .btn { font-size: var(--fs-xs); padding: 6px 9px; }
}

/* ---------- 16. ДОСТУПНОСТЬ / ПЕЧАТЬ ------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

@media print {
  .topbar, .rail, .stage-dock, .drawer-head, .tabs, .scrim, .mobile-sheet-bar, .hud, .part-editor-overlay { display: none !important; }
  .stage { overflow: visible; }
  body { overflow: visible; }
}

/* ---------- 18. АВТОФИЛЬТР ДЕТАЛИРОВКИ (вкладка «Деталировка») ----------- */
/* Треугольник-фильтр в заголовке таблицы деталировки (renderDetailingTable
   в app.js) — по образцу .ctx-menu (контекстное меню модуля/фокуса), тот же
   визуальный язык поповеров проекта. */

#tab-detailing th { position: relative; padding-right: 22px; }
.dth-filter-btn {
  position: absolute; right: 3px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; padding: 0; border: none; background: none;
  color: var(--muted); font-size: 11px; line-height: 1; cursor: pointer;
  border-radius: var(--r-sm);
}
.dth-filter-btn:hover { background: var(--surface-solid); color: var(--text); }
.dth-filter-btn.active { color: var(--accent); font-weight: 700; }

.detail-filter-menu { max-width: 260px; }
.detail-filter-menu .df-values-list { overflow-y: auto; max-height: 220px; padding: 2px 0; }
.df-check-row {
  display: flex !important; align-items: center; gap: 7px;
  padding: 5px 9px; border-radius: var(--r-sm);
  font-size: var(--fs-sm); color: var(--text); cursor: pointer; user-select: none;
}
.df-check-row:hover { background: var(--surface-2); }
.df-check-row input { width: auto !important; margin: 0; accent-color: var(--accent); flex: none; }
.df-check-row span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.df-check-all { font-weight: 600; border-bottom: 1px solid var(--border); margin-bottom: 2px; padding-bottom: 7px; }
.df-empty { padding: 7px 9px; font-size: var(--fs-xs); color: var(--muted); }

.detail-reset-filters {
  display: block; margin-bottom: var(--sp-2); font-size: var(--fs-xs); color: var(--accent);
  background: none; border: none; cursor: pointer; padding: 0; text-decoration: underline;
}
.detail-empty-row td { text-align: center; color: var(--muted); padding: 14px 9px; white-space: normal; }

/* ---------- 19. СТОЛЕШНИЦА (панель списка тумб проекта) ------------------ */
/* Список модулей проекта в панели «Столешница» (countertopPanelBlock в
   app.js) — по образцу .df-check-row выше (та же логика: checkbox + текст в
   один ряд), но не в поповере, а прямо в теле панели, поэтому своя, чуть
   просторнее набранная разновидность. */
.ctop-mod-list { margin-bottom: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.ctop-mod-row {
  display: flex !important; align-items: center; gap: var(--sp-2);
  padding: 8px 10px; font-size: var(--fs-sm); color: var(--text); cursor: pointer; user-select: none;
}
.ctop-mod-row + .ctop-mod-row { border-top: 1px solid var(--border); }
.ctop-mod-row:hover { background: var(--surface-2); }
.ctop-mod-row input { width: auto !important; margin: 0; accent-color: var(--accent); flex: none; }
/* Навесной модуль (не тумба) — виден в списке, но неактивен: приглушённый и
   без hover/курсора-указателя, чтобы не выглядел кликабельным. */
.ctop-mod-row.disabled { color: var(--muted); opacity: .6; cursor: default; }
.ctop-mod-row.disabled:hover { background: none; }
/* Тумба, чьи материал/свесы сейчас показывает панель ниже (клик по строке,
   см. bindCountertopEvents: data-ctop-select) — та же подсветка, что и у
   активной вкладки модуля (.mod-tab.active). */
.ctop-mod-row.active { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--accent); }

/* Текущий материал «своего материала» столешницы — просто текст (не select,
   выбор только через Библиотеку, см. countertopPanelBlock), тот же стиль
   поля, что у select/input рядом. Кнопка «Изменить» (.link-btn) стоит рядом
   в одну строку — .ctop-decor-current-row, текст занимает всё оставшееся
   место, кнопка не сжимается. */
.ctop-decor-current-row { display: flex; align-items: center; gap: var(--sp-3); }
.ctop-decor-current { flex: 1; min-width: 0; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: var(--r-sm); font-size: var(--fs-sm); background: var(--surface-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctop-decor-current-row .link-btn { flex: none; }
/* Толщина текущего материала — читается только из каталога (dec.thickness),
   поле больше не редактируется на этой панели (2026-09-06: чтобы задать
   нестандартную толщину, материал заводится отдельной позицией в Библиотеке
   материалов, см. комментарий у ctopMaterial change в bindCountertopEvents). */
.ctop-decor-thickness { margin-top: 6px; font-size: var(--fs-xs); color: var(--muted); }
