/* ЧАСТЬ 2А: НАЧАЛО — Базовые стили, переменные, Toolbar, Workspace */

/* ===== CSS-переменные (Дизайн-система КАРТ РЕГИОН) ===== */
:root {
  /* Основные цвета (Dark Mode — премиальная холодная палитра) */
  --bg-primary: #131419;
  --bg-secondary: #1a1c22;
  --bg-tertiary: #232730;
  --bg-hover: #2c313b;
  --bg-active: #363c48;

  /* Акцент (фирменный КАРТ РЕГИОН) */
  --accent: #6ab8ee;
  /* ТЕКСТ НА АКЦЕНТНОЙ ПОДЛОЖКЕ — ОТДЕЛЬНЫЙ ТОКЕН (приёмка меню 2026-08-22).
     Акцент у тем РАЗНЫЙ по светлоте: тут светло-голубой, в нуаре перивинкль, в светлой —
     печатный navy. Значит и текст на нём не может быть одним зашитым цветом: белое «1 мин»
     на голубой пилюле дало 2.16:1 — надпись почти не читалась. Один факт «чем писать поверх
     акцента» — один владелец, по одному значению на тему. */
  --on-accent: #0e1c26;
  --accent-hover: #8ccbf6;
  --accent-dim: rgba(106, 184, 238, 0.14);
  --accent-grad: linear-gradient(135deg, #6ab8ee 0%, #8a7df0 100%);

  /* Текст */
  --text-primary: #eef1f6;
  --text-secondary: #9aa4b4;
  /* Подсветлён до AA-контраста (~4.95:1 на bg-secondary): был #626a79 ≈ 3.2:1 */
  --text-muted: #828c9c;

  /* Границы */
  --border: #2a2e38;
  --border-light: #3a3f4b;

  /* Состояния */
  --warning: #f5b041;
  --error: #e74c3c;
  --success: #2ecc71;

  /* Геометрия */
  --radius-sm: 6px;
  --radius-md: 9px;
  --radius-lg: 14px;
  --radius-pill: 999px; /* полностью скруглённые чипы (E3) */

  /* Тени (мягкие, диффузные) */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.55);

  /* ═══ МЯГКИЙ РЕЛЬЕФ (редизайн 2026-08-18, пример заказчика — неоморфизм) ═══
     Пластика с картинки: плашка не обведена линией, а ВЫДАВЛЕНА из поверхности парой теней —
     светлая сверху-слева, тёмная снизу-справа. Нажатое состояние вдавлено внутрь (inset).

     ПОЧЕМУ НЕ ЧИСТЫЙ НЕОМОРФИЗМ. Он строит различимость на рельефе и потому живёт только в
     светлом монохроме: в тёмной теме светлая тень превращается в грязь, а текст тон-в-тон
     проваливает контраст. У нас тёмная тема — ДЕФОЛТ (препресс: цвет оттиска оценивают на
     нейтральном тёмном фоне), и на панели стоит контраст-гвард ≥4.5:1 — он появился из жалобы
     «левое меню почти не читается». Поэтому берём пластику, но контраст держим текстовый.

     Тени задаются ТОКЕНАМИ, а не литералами: светлая тема переопределяет их у себя, иначе
     подложка с тёмной темы уехала бы в светлую (правило проекта про хардкод цвета). */
  --nm-radius: 12px;
  --nm-radius-lg: 16px;
  /* Сила рельефа подобрана ГЛАЗАМИ по кадрам, а не на слух: при бликe 0.055 и тенях 3 px
     эффект в тёмной теме не читался вовсе — плашка выглядела как прежний прямоугольник. */
  --nm-hi: rgba(255, 255, 255, 0.1); /* блик — сверху-слева */
  --nm-lo: rgba(0, 0, 0, 0.62); /* тень — снизу-справа */
  --nm-out: -4px -4px 10px var(--nm-hi), 5px 5px 12px var(--nm-lo);
  --nm-out-sm: -2px -2px 6px var(--nm-hi), 3px 3px 7px var(--nm-lo);
  --nm-in: inset -2px -2px 6px var(--nm-hi), inset 3px 3px 8px var(--nm-lo);
  /* Мелкий калибр (волна 2): органы ниже ~24 px. Полная пара на них даёт «пузырь» и размывает
     форму — та же причина, по которой у кнопки тулбара взят --nm-out-sm. */
  --nm-in-sm: inset -1px -1px 3px var(--nm-hi), inset 2px 2px 5px var(--nm-lo);
  --nm-lo-strong: var(--nm-lo); /* светлая тема делает тень мелких органов плотнее общей */
  --nm-out-xs: -1px -1px 3px var(--nm-hi), 2px 2px 4px var(--nm-lo-strong);
  --nm-knob: #f2f4f8; /* ручка тумблера: не чистый белый — иначе в светлой теме сливается с канавкой */
  /* КАНАВКА — поверхность, в которой лежат плотные сетки чипов и ездит ручка тумблера. В
     тёмной теме совпадает с утопленной поверхностью, в светлой заметно темнее её: там
     `--nm-surface-in` СВЕТЛЕЕ панели, и углубление читалось как белая пластина поверх. */
  --nm-groove: var(--nm-surface-in);
  --nm-surface: linear-gradient(145deg, var(--bg-hover), var(--bg-secondary));
  --nm-surface-in: linear-gradient(145deg, var(--bg-primary), var(--bg-tertiary));
  --nm-ease: 220ms cubic-bezier(0.4, 0, 0.2, 1);
  --busy-scrim: rgba(8, 10, 15, 0.6); /* скрим заставки: 40–60 % по правилу, темы переопределяют */

  /* Размеры панелей */
  --toolbar-height: 54px;
  --panel-left-width: 264px;
  --panel-right-width: 300px;

  /* Типографика — шкала размеров (единый источник; см. UX-аудит P1-10).
     E-309: ШКАЛА ПОДНЯТА НА ДВЕ СТУПЕНИ. Живой прогон намерил: 69 из 135 видимых текстов были
     мельче 11 px, из них 61 — ровно 9 px, а самый крупный текст в продукте — 13 px. Для
     десктопного веба основной текст 14–16 px, то есть интерфейс был набран примерно вдвое
     мельче нормы; отсюда же и ощущение плотности (46 кнопок на первом экране).
     Правим ТОЛЬКО токены — 197 мест их уже используют, и шкала остаётся единым источником.
     Крупные ступени (xl и выше) не трогаем: заголовки и так читаются, а их рост распирал бы
     шапки панелей. Прежние значения оставлены в комментариях — чтобы откат был очевиден. */
  --fs-3xs: 11px; /* было 9 */
  --fs-2xs: 12px; /* было 10 */
  --fs-xs: 13px; /* было 11 — самый частый мелкий текст */
  --fs-sm: 14px; /* было 12 */
  --fs-base: 15px; /* было 13 — базовый body */
  --fs-md: 16px; /* было 14 */
  --fs-lg: 17px; /* было 15 */
  --fs-xl: 19px; /* было 17 */
  --fs-2xl: 20px; /* было 18 */
  --fs-3xl: 22px;
  --fs-4xl: 34px;
  /* Полустепы — точечные значения, кандидаты на консолидацию позже. Подняты вместе со шкалой:
     иначе они провалились бы НИЖЕ соседних ступеней и «полустеп» перестал бы быть полустепом. */
  --fs-9-5: 11.5px; /* было 9.5 */
  --fs-10-5: 12.5px; /* было 10.5 */
  --fs-11-5: 13.5px; /* было 11.5 */
  --fs-12-5: 14.5px; /* было 12.5 */
  --fs-13-5: 15.5px; /* было 13.5 */

  /* Отступы — шкала (4px-сетка + точечные полушаги) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;

  /* Начертания */
  --fw-light: 300;
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* Высота строки */
  --lh-tight: 1.2;
  --lh-normal: 1.5;
  --lh-loose: 1.7;
  /* Высота ленты миниатюр в виде «карта крупно» (js/19). На :root, потому что о ней должны
     знать и элементы вне #canvas-area — например, тосты в <body>. */
  --focus-strip-h: 168px;
}

/* ===== СБРОС И БАЗА ===== */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  overflow: hidden;
  font-family:
    'Inter',
    -apple-system,
    BlinkMacSystemFont,
    sans-serif;
  font-size: var(--fs-base);
  background: var(--bg-primary);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  user-select: none;
}

button {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  outline: none;
}

button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.hidden {
  display: none !important;
}

/* ===== ВЕРХНЯЯ ПАНЕЛЬ (TOOLBAR) ===== */
#toolbar {
  height: var(--toolbar-height);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  position: relative;
  z-index: 100;
}

.toolbar-left,
.toolbar-center,
.toolbar-right {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* Тулбар на честном flex: боковые секции равны (flex:1), центр по центру и
   не накладывается на логотип/«Скачать» при средних ширинах. */
.toolbar-left {
  flex: 1 1 0;
  min-width: 0;
}
.toolbar-right {
  flex: 1 1 0;
  min-width: 0;
  justify-content: flex-end;
}
.toolbar-center {
  flex: 0 1 auto;
  min-width: 0;
  justify-content: center;
}

/* Логотип */
.logo {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-right: var(--sp-4);
  flex-shrink: 0;
}
/* Логотип — кнопка меню «Моя колода» (24.09.2026): вид прежний, отклик как у кнопок шапки */
button.logo {
  font: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  border-radius: 10px;
  padding: 4px var(--sp-3) 4px 6px;
  margin-right: var(--sp-2);
  cursor: pointer;
  transition:
    background 0.2s ease,
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
button.logo:hover,
button.logo:focus-visible,
button.logo[aria-expanded='true'] {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  outline: none;
}
button.logo:active {
  transform: translateY(1px);
}
.logo-caret {
  color: var(--text-secondary);
  margin-left: -2px;
}
/* Меню «Моя колода» — fixed-слой под логотипом, образец меню «Написать нам» */
.deck-menu {
  position: fixed;
  z-index: 10050;
  width: 320px;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  padding: 6px;
  border-radius: var(--nm-radius, 12px);
  background: var(--nm-surface, var(--bg-secondary));
  border: 1px solid var(--border);
  box-shadow: var(--nm-out-sm, 0 10px 30px rgba(0, 0, 0, 0.35));
  animation: write-us-in 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.deck-menu-head {
  padding: 8px 12px 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.deck-name {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 2px 12px 8px;
}
.deck-name-input {
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-primary, var(--bg-secondary));
  color: var(--text-primary);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
}
.deck-name-input::placeholder {
  color: var(--text-muted);
  font-weight: 400;
}
.deck-name-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.deck-name small {
  font-size: 11px;
  color: var(--text-muted);
}
.deck-save-status {
  margin: 2px 12px 4px;
  font-size: 11.5px;
  color: var(--text-secondary);
}
.deck-save-status.is-bad {
  color: var(--error);
  font-weight: 600;
}
.deck-menu-version {
  margin: 8px 12px 4px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 11px;
  color: var(--text-muted);
}
/* ВНИМАНИЕ НА ЛОГОТИПЕ (24.09.2026): вышла новая версия · оператор ответил в чате при закрытом окне.
   Язык движения проекта: только transform/opacity, cubic-bezier(.16,1,.3,1), не короче 0,3 с,
   без появления из точки и без пружин; редкий медленный блик (цикл 9 с, как у логотипа
   funlovegift). Цвет причины — токен: обновление — акцент, чат — «успех» (ждёт живой человек). */
button.logo {
  position: relative;
  --attn-c: var(--accent);
}
button.logo.attn-chat {
  --attn-c: var(--success);
}
.logo-attn {
  position: absolute;
  top: 3px;
  left: 22px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--attn-c);
  box-shadow: 0 0 0 2px var(--bg-secondary, #16181d);
  pointer-events: none;
  animation: logo-attn-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.logo-attn::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--attn-c);
  opacity: 0;
  animation: logo-attn-ring 2.8s cubic-bezier(0.16, 1, 0.3, 1) 0.7s infinite;
}
.logo-attn-sheen {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
}
.logo-attn-sheen::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 60%;
  background: linear-gradient(
    105deg,
    transparent 0%,
    color-mix(in srgb, var(--attn-c) 26%, transparent) 50%,
    transparent 100%
  );
  transform: translateX(-120%);
  animation: logo-attn-sheen 9s cubic-bezier(0.16, 1, 0.3, 1) 1.2s infinite;
}
.logo-attn-pill {
  position: absolute;
  top: calc(100% + 9px);
  left: 4px;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 12px 6px 10px;
  border-radius: 999px;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-primary);
  background: var(--nm-surface, var(--bg-secondary));
  border: 1px solid color-mix(in srgb, var(--attn-c) 45%, var(--border));
  box-shadow:
    0 10px 28px -8px color-mix(in srgb, var(--attn-c) 40%, rgba(0, 0, 0, 0.5)),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  pointer-events: none;
  z-index: 10040;
  opacity: 0;
  animation: logo-attn-pill 12s cubic-bezier(0.16, 1, 0.3, 1) 0.9s infinite;
}
.logo-attn-pill::before {
  content: '';
  position: absolute;
  top: -5px;
  left: 16px;
  width: 8px;
  height: 8px;
  background: inherit;
  border-left: inherit;
  border-top: inherit;
  transform: rotate(45deg);
}
.logo-attn-pill svg {
  color: var(--attn-c);
  flex-shrink: 0;
}
button.logo[aria-expanded='true'] .logo-attn-pill {
  display: none;
}
@keyframes logo-attn-in {
  from {
    opacity: 0;
    transform: translateY(-3px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes logo-attn-ring {
  0% {
    opacity: 0.7;
    transform: scale(1);
  }
  70%,
  100% {
    opacity: 0;
    transform: scale(2.8);
  }
}
@keyframes logo-attn-sheen {
  0% {
    transform: translateX(-120%);
  }
  16%,
  100% {
    transform: translateX(260%);
  }
}
@keyframes logo-attn-pill {
  0% {
    opacity: 0;
    transform: translateY(-8px);
  }
  6%,
  32% {
    opacity: 1;
    transform: none;
  }
  40%,
  100% {
    opacity: 0;
    transform: translateY(-4px);
  }
}
/* Карточки в меню: причина словами + одно действие */
.deck-attn {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 2px 10px 10px;
}
.deck-attn-card {
  --attn-c: var(--accent);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 10px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--attn-c) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--attn-c) 34%, transparent);
  animation: deck-attn-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.deck-attn-card + .deck-attn-card {
  animation-delay: 0.11s;
}
.deck-attn-card[data-attn='чат-ответ'] {
  --attn-c: var(--success);
}
.deck-attn-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  color: var(--attn-c);
  background: color-mix(in srgb, var(--attn-c) 16%, transparent);
}
.deck-attn-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.deck-attn-text b {
  font-size: 13px;
  color: var(--text-primary);
}
.deck-attn-text small {
  font-size: 11.5px;
  color: var(--text-secondary);
}
.deck-attn-btn {
  grid-column: 1 / -1;
  justify-self: stretch;
  margin-top: 6px;
  padding: 7px 12px;
  border: 0;
  border-radius: var(--nm-radius, 10px);
  cursor: pointer;
  background: var(--attn-c);
  color: var(--bg-primary, #0d1117);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.2;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.deck-attn-btn:hover,
.deck-attn-btn:focus-visible {
  transform: translateY(-2px);
  outline: none;
}
@keyframes deck-attn-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .logo-attn,
  .logo-attn::after,
  .logo-attn-sheen::before,
  .deck-attn-card {
    animation: none;
  }
  .logo-attn-pill {
    display: none;
  }
}
.deck-menu-sep {
  margin: 6px 12px 2px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.deck-menu-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.deck-menu-item svg {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--accent);
}
.deck-menu-item span {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.deck-menu-item b {
  font-weight: 600;
  font-size: 13px;
}
.deck-menu-item small {
  font-size: 11.5px;
  color: var(--text-muted);
}
.deck-menu-item:hover,
.deck-menu-item:focus-visible {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  outline: none;
}
.deck-menu-item[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  .deck-menu {
    animation: none;
  }
  button.logo {
    transition: none;
  }
}

.logo-icon {
  font-size: var(--fs-3xl);
  color: var(--accent);
  line-height: 1;
}

.logo-text {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 1.5px;
  color: var(--text-primary);
  white-space: nowrap;
}

.logo-text em {
  font-style: normal;
  font-weight: 400;
  color: var(--text-secondary);
}

/* Кнопки тулбара */
/* ═══ ТУЛБАР В НЕОМОРФИЗМЕ ═══════════════════════════════════════════════════════════════
   Кнопка — не плоское пятно, а ВЫДАВЛЕННАЯ из фона плашка; нажатая — ВДАВЛЕННАЯ. Рельеф
   берётся ТОКЕНАМИ (--nm-*), а не литералами: у каждой темы свои блик и тень, и хардкод увёл
   бы тёмную подложку в светлую тему (правило проекта).
   Малый вариант (--nm-out-sm) выбран намеренно: полный рельеф на кнопке 34 px даёт «пузырь»,
   на панели из полутора десятков кнопок это рябит. */
.tool-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 34px;
  padding: 0 12px;
  border-radius: var(--nm-radius);
  color: var(--text-secondary);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color 0.15s ease,
    background 0.15s ease;
}

.tool-btn:hover {
  background: var(--nm-surface);
  color: var(--text-primary);
  box-shadow: var(--nm-out);
}

/* НАЖАТА — ВДАВЛЕНА. В неоморфизме это главный (и единственный честный) способ показать
   состояние: цветом акцента пользуются и наведение, и фокус, а рельеф занят только им. */
.tool-btn:active {
  box-shadow: var(--nm-in);
}

.tool-btn.active {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  color: var(--accent);
}

.tool-btn .btn-label {
  font-size: var(--fs-sm);
  font-weight: 500;
}

.tool-btn svg {
  flex-shrink: 0;
}

/* Главная кнопка "Скачать" */
.tool-btn.btn-primary {
  background: var(--accent);
  color: #1a1a1a;
  font-weight: 600;
}

.tool-btn.btn-primary:hover {
  background: var(--accent-hover);
  color: #1a1a1a;
}

.toolbar-divider {
  width: 1px;
  height: 24px;
  background: var(--border);
  margin: 0 4px;
}

/* Выпадающее меню "Скачать" */
.dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 16px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  min-width: 320px;
  overflow: hidden;
  z-index: 200;
  animation: dropdownIn 0.2s ease;
}

@keyframes dropdownIn {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.dropdown-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  width: 100%;
  padding: 14px 16px;
  text-align: left;
  transition: background 0.15s;
  border-bottom: 1px solid var(--border);
}

.dropdown-item:last-child {
  border-bottom: none;
}

.dropdown-item:hover {
  background: var(--bg-hover);
}

.dropdown-sep {
  height: 1px;
  margin: 4px 10px;
  background: var(--border);
}

/* ============================================================
   TOPBAR 2.0 — логические группы, иконки-первые с раскрытием
   подписи по наведению на группу, сегмент ресурсов, timeline-
   поповер истории в кнопках Отменить/Вернуть. Всё на токенах.
   ============================================================ */

/* Контейнер логической группы инструментов */
.tb-group {
  display: flex;
  align-items: center;
  gap: 1px;
  flex-shrink: 0;
}

/* Иконка-первая кнопка: подпись свёрнута, разворачивается «вправо»
   при наведении/фокусе на группу (а также если кнопка активна). */
.tool-btn.tb-icon {
  position: relative;
  gap: 0;
  padding: 0 9px;
}
/* Подпись иконки — плавающая подсказка ПОД иконкой (абсолютно, вне потока), поэтому
   раскладка НЕ смещается и иконки не «убегают» при наведении (быстрый выбор). */
.tb-icon .btn-label {
  position: absolute;
  left: 50%;
  top: calc(100% + 6px);
  transform: translateX(-50%) translateY(-4px);
  white-space: nowrap;
  padding: 4px 9px;
  border-radius: 7px;
  background: var(--bg-active);
  border: 1px solid var(--border-light);
  color: var(--text-primary);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-xs);
  font-weight: 600;
  opacity: 0;
  pointer-events: none;
  z-index: 120;
  transition:
    opacity 0.15s ease,
    transform 0.15s ease;
}
.tb-icon:hover .btn-label,
.tb-icon:focus-visible .btn-label {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* ПОДПИСЬ ГАСНЕТ, ПОКА ОТКРЫТО ОКНО ЭТОЙ КНОПКИ (просьба заказчика 2026-09-18: «когда большое
   меню разворачивается, маленький ховер с подписью закрывался»). Меню встаёт ровно туда, где
   стоит подпись (top: 100% + 6px у обеих), а мышь после клика остаётся над кнопкой — подпись
   продолжала висеть под меню и выглядывать из-под его края. Признак один — aria-expanded, его
   ставят все кнопки с окнами (Вид, Настройки, Советы, ресурсы); модальные (Версии, Поиск) гасят
   подпись сами — теряется наведение. Правило стоит ПОСЛЕ hover-правила при равной
   специфичности — порядок и есть приоритет. Страж — test/topbar-hover-label-hides.js. */
.tb-icon[aria-expanded='true'] .btn-label {
  opacity: 0;
  transform: translateX(-50%) translateY(-4px);
  pointer-events: none;
}

/* Каретка выпадающих меню (Вид / Создать) */
.tb-caret {
  margin-left: 3px;
  opacity: 0.5;
  transition: transform 0.2s ease;
}
.tool-btn--menu[aria-expanded='true'] .tb-caret {
  transform: rotate(180deg);
}
.tool-btn--muted {
  color: var(--text-muted);
}

/* Сегмент ресурсов — единый «пилюльный» блок (Стили/Библиотека/Файлы/Палитра) */
.tb-segment {
  gap: 0;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 2px;
}
.tb-segment .tb-res {
  height: 30px;
  border-radius: 7px;
}
.tb-segment .tb-res.active {
  background: var(--accent-dim);
  color: var(--accent);
}
.tb-res svg {
  width: 18px;
  height: 18px;
}

/* Выпадающее, привязанное под свой триггер (Создать) — не к правому краю */
.dropdown--anchored {
  right: auto;
  min-width: 300px;
}

/* ===== Timeline-поповер истории (раскрывается из Отменить/Вернуть) ===== */
.hist-pop {
  position: fixed;
  z-index: 400;
  width: 304px;
  max-height: 62vh;
  overflow-y: auto;
  padding: 8px;
  /* Материал выпадающего меню (волна 4): пикер иконок — такое же всплывающее окно. */
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out), var(--shadow-lg);
  animation: dropdownIn 0.18s ease;
}
.hist-pop-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 3px 8px 9px;
}
.hist-pop-title {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.hist-pop-hint {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .tb-icon .btn-label,
  .tb-caret {
    transition: none;
  }
  .hist-pop {
    animation: none;
  }
}

/* Вкладки ресурсов переехали в верхнее меню (сегмент .tb-segment) — дублирующий
   ряд в левой панели скрыт. Контент (#tab-*) остаётся и управляется сверху. */
.panel-tabs.resource-tabs {
  display: none;
}

/* ===== «Лицо ▾» — сплит-вкладка с кареткой быстрого выбора карты ===== */
.card-tab--split {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.card-tab-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: 4px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
  opacity: 0.9;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    opacity 0.14s ease;
}
.card-tab-caret:hover {
  opacity: 1;
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.card-tab-caret svg {
  width: 12px;
  height: 12px;
}

/* Отдельная кнопка «Вся колода» в переключателе сторон */
.card-tab--deck {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 10px;
  position: relative;
}
.card-tab--deck::before {
  content: '';
  position: absolute;
  left: -6px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 20px;
  background: var(--border);
}
.card-tab--deck svg {
  flex: 0 0 auto;
}

/* Попап быстрого выбора карты лица */
.face-quick-menu {
  min-width: 268px;
  padding: 8px;
}
.face-quick-groups {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0 2px 4px;
}
.face-quick-grp {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.face-quick-grp:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.face-quick-grp.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
/* ИКОНКА СТРОКИ — SVG В КРУГЛОЙ ПОДЛОЖКЕ (2026-08-13, просьба заказчика «сделать меню
   дизайнерским»). Прежде здесь стояли эмодзи 16 px: их рисует шрифт системы, поэтому стиль,
   вес и цвет плясали от машины к машине, а «🅰️» приезжал синим квадратом мимо темы.
   SVG наследует currentColor — строка целиком меняет цвет на наведении и при выборе. */
.face-quick-grp .fq-ic {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 8px;
  background: var(--bg-tertiary, rgba(255, 255, 255, 0.05));
  border: 1px solid var(--border);
  color: inherit;
  transition:
    background 0.14s ease,
    border-color 0.14s ease;
}
.face-quick-grp .fq-ic svg {
  width: 16px;
  height: 16px;
  display: block;
}
.face-quick-grp:hover .fq-ic {
  background: var(--bg-hover);
}
.face-quick-grp.active .fq-ic {
  background: var(--accent-dim);
  border-color: var(--accent);
}
/* Особые карты (джокер) — тот же ряд, но отделён от групп показа: это не «что показать
   из колоды», а конкретная сторона. */
.face-quick-special {
  padding-bottom: 6px;
}
.face-quick-grp .fq-lb {
  flex: 1;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: left;
}
.face-quick-grp .fq-hint {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  letter-spacing: 0.06em;
}
.face-quick-ranks {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  padding: 0 2px 6px;
}
.face-quick-suits {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
  padding: 0 2px 2px;
}
.fq-chip {
  height: 30px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    color 0.12s ease;
}
.fq-chip:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.fq-chip.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.fq-suit {
  font-size: 16px;
}
.fq-heart,
.fq-diamond {
  color: #e0556a;
}
.fq-heart.active,
.fq-diamond.active {
  color: #ff6b81;
}

/* ===== Флайаут ресурсов (Стили/Библиотека/Файлы/Палитра) — холст остаётся виден ===== */
.resource-flyout {
  position: fixed;
  z-index: 350;
  width: 380px;
  max-height: 74vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: dropdownIn 0.18s ease;
}
.resource-flyout.hidden {
  display: none;
}
/* ВИТРИНА СТИЛЕЙ: у каталога из 38 карточек своя ширина. В форточке 380 px он вставал в две
   колонки — 7,5 экранов прокрутки на каждый заход, самый дорогой сценарий продукта. Ширина
   ограничена и величиной окна (92vw), иначе на ноутбуке витрина выехала бы за край. */
.resource-flyout.wide {
  width: min(920px, 92vw);
}
.resource-flyout.wide .styles-grid {
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
}
.styles-compare-btn {
  display: block;
  width: 100%;
  min-height: 38px;
  margin-top: 10px;
  padding: 0 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--accent);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.styles-compare-btn:hover {
  background: var(--bg-hover, var(--bg-tertiary));
}
/* РЕЛЬЕФ ЕЙ НЕ НУЖЕН — решение волны 2, а не забытое место. Пунктирная рамка сама говорит о
   роли: это не готовая ячейка, а приглашение создать. Ровно так же оставлен вход «Добавить
   слой» (.layers-shelf-add) в волне 1; выдавить их значило бы обещать существующую вещь. */
.styles-blank-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 40px;
  padding: 0 12px;
  margin-top: 6px;
  background: var(--bg-secondary);
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.styles-blank-row:hover {
  border-color: var(--accent);
  color: var(--text-primary);
}
.styles-blank-plus {
  font-size: 16px;
  line-height: 1;
  color: var(--text-muted);
}
.styles-family-lab {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--text-secondary);
  margin: 14px 0 6px;
}
.styles-family-count {
  font-weight: 400;
  color: var(--text-muted);
  font-size: var(--fs-xs);
}
.resource-flyout-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.resource-flyout-title {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.resource-flyout-close {
  display: inline-flex;
  padding: 4px;
  border-radius: 6px;
  color: var(--text-muted);
  cursor: pointer;
}
/* ЗАКРЫВАШКА — ВРЕЗАННОЕ ГНЕЗДО, а не второй выступ: шапка флайаута уже поднята над панелью,
   и выступ на выступе при одном источнике света читается как грязь (правило волны 1 для
   значков строки слоя). Наведение поднимает значок вровень с шапкой, нажатие утапливает. */
.resource-flyout-close {
  border: 1px solid transparent;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.resource-flyout-close:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
  box-shadow: var(--nm-out-xs);
}
.resource-flyout-close:active {
  box-shadow: var(--nm-in-sm);
}
.resource-flyout #panel-resource-region {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 10px 12px;
}
/* ═══ ВТОРАЯ МЁРТВАЯ КОПИЯ (609 строк), СНЯТАЯ В ВОЛНЕ 3 ══════════════════════════════════
   Тот же случай, что и снятый в волне 2 регион в 1654 строки: участок файла присутствовал
   ДВАЖДЫ, и первая копия не влияла ни на пиксель — при равной силе побеждает правило ПОЗЖЕ.
   Найдена не глазами: правка окна диалога не применилась, а Edit отказался работать, увидев
   ДВА одинаковых определения .ux-modal-box. После этого файл проверен на дубли целиком —
   сканом одинаковых участков длиной от 40 строк. Больше таких в файле нет.

   ЖИВОЙ НАБОР ПРАВИЛ ИДЁТ НИЖЕ. Границы среза брать по балансу скобок: совпадение строк
   началось ВНУТРИ правила, и наивный срез оставил бы висящую закрывающую. */
/* Чипы категорий библиотеки описаны НИЖЕ, одним набором правил. Здесь стоял его
   полный дубль — байт в байт, и потому мёртвый: при равной силе побеждает позднее правило.
   Волна 1 уже споткнулась об это у .region-header (правку внесли в недействующую копию и
   не увидели эффекта), поэтому копия снята, а не одета второй раз. */
/* ═══ ЗДЕСЬ ЛЕЖАЛА ПОЛНАЯ КОПИЯ РЕГИОНА (1654 строки), СНЯТАЯ В ВОЛНЕ 2 ═══════════════════
   Тот же кусок файла — от .mgr-count до конца блока перед заголовком региона — присутствовал
   ДВАЖДЫ, строка в строку. При равной силе побеждает правило, стоящее ПОЗЖЕ, поэтому первая
   копия не влияла ни на один пиксель, но исправно принимала правки: пишешь в неё — на экране
   ничего. Волна 1 уже потеряла здесь время на .region-header, волна 2 — на чипах библиотеки.

   ЖИВОЙ НАБОР ПРАВИЛ ИДЁТ НИЖЕ.

   РАВЕНСТВО ДО И ПОСЛЕ СНЯТИЯ ДОКАЗАНО НЕ КАРТИНКАМИ. Сверка снимков экрана для этого
   негодна: контрольный опыт дал 17 расхождений из 18 на ОДНОМ И ТОМ ЖЕ коде (превью узоров
   случайны, идут анимации) — она объявила бы поломкой что угодно. Сверялись ВЫЧИСЛЕННЫЕ
   СТИЛИ всех видимых узлов в 24 сценах (инспектор, три флайаута, четыре меню × три темы):
   расхождений 0. Метод проверен встречным опытом — заведомая правка отступа у чипа
   библиотеки в живой копии видна сразу в трёх сценах.

   ГРАНИЦУ СРЕЗА БРАТЬ ПО ЗАКРЫВАЮЩЕЙ СКОБКЕ, а не по концу совпадения: первая попытка
   обрезала внутри правила и оставила висящую закрывающую скобку — ловится счётом за секунду. */
.region-header {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
  padding: 10px 12px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
  /* ЗАГОЛОВОК РЕГИОНА — ВЫРЕЗАН В ФОНЕ, а не наклеен поверх. В неоморфизме у надписи-шапки
     это естественная роль: она не действие, нажимать её нечего, и выдавливать её значило бы
     обещать кнопку (а заголовок «Слои» перестал быть кнопкой 19 августа по просьбе
     заказчика). Вдавленность даёт ту же границу региона, что прежняя линия снизу, но одним
     языком с остальной панелью. */
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  border-bottom: none;
}
.region-header svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  color: var(--accent);
}
.panel-layers {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-2);
}
/* Правила .layer-group-title удалены 2026-08-19 вместе с подписями ролей (решение заказчика:
   «опять появилось разбивание по базовым / композиционным / вспомогательным»). Мёртвый селектор
   оставлять нельзя — он обещал бы, что вещь ещё такая. Владелец решения — комментарий в js/06. */
#panel-resource-region {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 8px 10px 12px;
}
@media (prefers-reduced-motion: reduce) {
  .resource-flyout {
    animation: none;
  }
}

/* ── Меню «Вид»: блок «Формат карты» ── */
.view-format-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
  padding: 0 8px 6px;
}
.view-format-pill {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 7px 10px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  text-align: left;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.view-format-pill:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.view-format-pill.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.view-format-pill strong {
  font-size: var(--fs-sm);
  font-weight: 700;
}
.view-format-pill small {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
}
.view-format-pill.active small {
  color: var(--accent);
  opacity: 0.85;
}
.view-format-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 8px 8px;
}
.view-format-act {
  padding: 8px 12px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-sm);
  text-align: left;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.view-format-act:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.view-format-act.active {
  border-color: var(--accent);
  color: var(--accent);
}

/* Формат карты переехал в меню «Вид» — левопанельный регион скрыт. */
#panel-cardsize-region {
  display: none;
}

/* ===== Чип наследования слоя 🔗/✎ (Фаза 1 «Мастер колоды + оверрайды») ===== */
.layer-scope {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex: 0 0 auto;
  margin: 0 6px;
  padding: 2px 7px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  /* E-309: было --text-muted. На собственном фоне чипа (--bg-tertiary, светлее панели) это
     давало 4.40 в тёмной теме и 4.20 в светлой — ниже нормы 4.5. Та же причина, что у
     .scope-head-lab: не токен виноват, а светлая подложка. */
  color: var(--text-secondary);
  font-size: var(--fs-3xs); /* E-309: было 10px мимо шкалы */
  font-weight: 600;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.layer-scope:hover {
  border-color: var(--accent);
  color: var(--text-secondary);
}
.layer-scope.is-own {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
/* Нейтральная метка «Общий» для глобальных слоёв лица (не локализуемых). Приглушённая,
   некликабельная — отличает их от слоёв с чипом охвата 🔗/✎. */
/* E-309 повторно (жалоба 2026-08-13 «левое меню почти не читается»): приглушать метку
   ПРОЗРАЧНОСТЬЮ нельзя — 0.7 давала «Общий» 3.58:1 в тёмной теме и 3.30:1 в светлой, ниже
   нормы 4.5, причём на ВКЛЮЧЁННЫХ строках. От кликабельных чипов метку отличают пунктирная
   рамка, отсутствие курсора-указателя и ховера — этого достаточно, и это не стоит читаемости. */
.layer-scope.is-global {
  cursor: default;
  border-style: dashed;
}
.layer-scope.is-global:hover {
  border-color: var(--border);
  color: var(--text-muted);
}
/* «Различаются» — слой выглядит по-разному у карт выбранного набора. Это ИНДИКАТОР,
   а не кнопка: без курсора-указателя и без ховера. Цвета — только через токены,
   иначе метка выпадет из светлой темы. */
.layer-scope.is-mixed {
  cursor: default;
  border-style: dashed;
  border-color: var(--warn, var(--border));
  color: var(--warn, var(--text-secondary));
}
.layer-scope .ls-ic {
  font-size: 11px;
  line-height: 1;
}
.layer-scope .ls-txt {
  letter-spacing: 0.2px;
}
.layer-scope .ls-reset {
  font-size: 12px;
  line-height: 1;
  opacity: 0.85;
}
/* Галка «на всю колоду» (охват слоя в режиме мастера). */
.layer-scope.layer-deckwide.is-own {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  border-color: var(--accent);
  color: var(--accent);
}
.layer-scope.layer-deckwide:not(.is-own) {
  border-style: dashed;
}
/* Индикатор «немой правки» в охвате «Вся колода»: слой переопределён локально
   у N карт — мастер-правка их не изменит. */
.layer-scope.layer-ov-count {
  cursor: help;
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
  border-color: color-mix(in srgb, var(--warning) 45%, transparent);
}
/* На узких панелях прячем подпись, оставляем иконку. */
@media (max-width: 1120px) {
  .layer-scope .ls-txt {
    display: none;
  }
}
/* Провенанс в сноске (js/37): 🔗 от колоды / ✎ своё */
.tc-scope {
  font-size: 10px;
  opacity: 0.75;
  margin-left: 1px;
}
.tc-scope.is-own {
  opacity: 1;
}
/* Кнопка распространения слоя ⇢ (Фаза 2) + меню охвата */
.layer-scope-prop {
  flex: 0 0 auto;
  margin-right: 4px;
  padding: 2px 6px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--accent);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease;
}
.layer-scope-prop:hover {
  background: var(--accent-dim);
  border-color: var(--accent);
}
.prop-menu {
  min-width: 224px;
  padding: 6px;
}

/* ===== Мини-меню выбора темы (на токенах — адаптируется под каждую тему) ===== */
.theme-menu {
  position: fixed;
  z-index: 400;
  min-width: 234px;
  padding: 6px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: dropdownIn 0.18s ease;
}
.theme-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: none;
  border-radius: 9px;
  background: none;
  text-align: left;
  cursor: pointer;
  color: var(--text-secondary);
  transition:
    background 0.14s ease,
    color 0.14s ease;
}
.theme-menu-item:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.theme-menu-item.active {
  background: var(--accent-dim);
}
.theme-swatch {
  width: 34px;
  height: 24px;
  flex: 0 0 auto;
  border-radius: 6px;
  border: 1px solid var(--border-light);
}
.theme-menu-text {
  flex: 1;
  min-width: 0;
}
.theme-menu-item strong {
  display: block;
  font-size: var(--fs-12-5);
  color: var(--text-primary);
}
.theme-menu-item.active strong {
  color: var(--accent);
}
.theme-menu-item small {
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  line-height: 1.35;
}

/* ===== UX: модалки, командная палитра, версии, онбординг ===== */
.ux-modal {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}
.ux-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
}
/* ОКНО ДИАЛОГА — та же поверхность, что у выпадающих меню (волна 3). Прежде коробка была
   обведена линией в пиксель и лежала под тяжёлой чёрной тенью-литералом: на фоне меню и
   панелей, одетых в мягкий рельеф, диалог выглядел пришельцем из прежнего продукта — а видит
   его каждый, кому продукт задаёт вопрос.
   ДВА СЛОЯ ТЕНИ ОТВЕЧАЮТ НА РАЗНЫЕ ВОПРОСЫ и потому оба нужны: рельеф говорит «из чего окно
   сделано», отброшенная тень — «оно поверх всего». Обе берутся токенами, светлая тема
   переопределяет их у себя. */
.ux-modal-box {
  position: relative;
  width: 92%;
  max-width: 620px;
  max-height: 72vh;
  display: flex;
  flex-direction: column;
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out), var(--shadow-lg);
  overflow: hidden;
  animation: uxIn 0.16s ease;
}
@keyframes uxIn {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.98);
  }
}
/* Строка ввода палитры команд — НИША во всю ширину окна, как всякое поле для набора текста.
   Линию снизу оставляем: она делит ввод и список, а рельеф говорит «сюда пишут». */
.cmd-input {
  width: 100%;
  padding: 16px 18px;
  border: none;
  border-bottom: 1px solid var(--border);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in);
  color: var(--text-primary);
  font-size: var(--fs-lg);
  outline: none;
}
.cmd-list {
  overflow-y: auto;
  padding: 6px;
}
.cmd-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  cursor: pointer;
}
/* Строка списка команд: в покое плоская, под курсором и у выбранной — рельеф. Список длинный,
   и полсотни выпуклых строк подряд дали бы стиральную доску (тот же довод, что у строк слоёв
   и раскрывашек). Акцентная подложка у выбранной остаётся: по списку ходят с клавиатуры, и
   различать текущую строку одним рельефом нельзя. */
.cmd-row {
  border: 1px solid transparent;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
.cmd-row:hover {
  box-shadow: var(--nm-out-xs);
}
.cmd-row.active {
  background: var(--accent-dim);
  box-shadow: var(--nm-in-sm);
}
.cmd-group {
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--text-muted);
  min-width: 92px;
  flex: 0 0 auto;
}
.cmd-label {
  flex: 1;
  font-size: var(--fs-base);
  color: var(--text-primary);
}
.cmd-row.active .cmd-label {
  color: var(--accent);
}
.cmd-hint {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  background: var(--bg-active);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
}

.ux-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.ux-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--text-primary);
}
.ux-btn {
  padding: 7px 12px;
  border-radius: var(--nm-radius);
  /* Кнопка окна — выдавлена, как её родня в панелях. Габарит держит прозрачная рамка. */
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.ux-btn:hover {
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.ux-btn:active {
  box-shadow: var(--nm-in-sm);
}
.ux-primary {
  background: var(--accent-grad, var(--accent));
  color: #10141c;
  border: none;
  margin: 16px 18px 18px;
  padding: 10px;
  font-size: var(--fs-base);
}
.ux-empty {
  color: var(--text-muted);
  font-size: var(--fs-base);
  padding: 24px 8px;
  text-align: center;
  line-height: 1.5;
}

/* ===== Развилка действия (uxChoice, js/13) =====
   Варианты равноправны, поэтому карточки одинакового веса — ни один не выделен как
   «правильный». Заголовок отвечает «что это», подпись — «что произойдёт с картинкой»:
   цена выбора должна быть видна ДО файлового диалога, а не после. */
.ux-choice-lead {
  padding: 14px 18px 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-secondary);
}
.ux-choice-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-3);
  padding: 14px 18px 4px;
}
@media (max-width: 640px) {
  .ux-choice-grid {
    grid-template-columns: 1fr;
  }
}
/* КАРТОЧКА ВЫБОРА — крупная выдавленная плашка: это главный орган окна, им и отвечают на
   вопрос. Нажатие утапливает — обратное движение читается как «принято». */
.ux-choice-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 16px;
  text-align: left;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    transform var(--nm-ease);
}
.ux-choice-card:hover {
  border-color: transparent;
  background: var(--bg-hover);
  transform: translateY(-1px);
  box-shadow:
    var(--nm-out),
    0 0 0 1px var(--accent-dim);
}
.ux-choice-card:active {
  transform: none;
  box-shadow: var(--nm-in);
}
.ux-choice-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.ux-choice-card .uc-ico {
  display: inline-flex;
  width: 34px;
  height: 34px;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}
.ux-choice-card .uc-ico svg {
  width: 20px;
  height: 20px;
}
.ux-choice-card .uc-name {
  font-size: var(--fs-base);
  font-weight: 700;
}
.ux-choice-card .uc-hint {
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-secondary);
}
/* «Было → стало»: показать нагляднее, чем описать. Тонкая графика, не иллюстрация ради
   иллюстрации — она отвечает на единственный вопрос «что случится с моим файлом». */
.ux-choice-card .uc-preview {
  display: block;
  width: 100%;
  margin-top: 2px;
  color: var(--text-muted);
}
.ux-choice-card .uc-preview svg {
  width: 118px;
  max-width: 100%;
  height: auto;
}
.ux-choice-foot {
  display: flex;
  justify-content: flex-end;
  padding: 10px 18px 18px;
}
@media (prefers-reduced-motion: reduce) {
  .ux-choice-card {
    transition: none;
  }
  .ux-choice-card:hover {
    transform: none;
  }
}
.versions-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-3);
  padding: 14px 18px 18px;
  overflow-y: auto;
}
.version-card {
  position: relative;
  cursor: pointer;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-tertiary);
  transition:
    transform 0.15s ease,
    border-color 0.15s ease;
}
.version-card:hover {
  transform: translateY(-3px);
  border-color: var(--accent);
}
.version-card img,
.version-noimg {
  width: 100%;
  aspect-ratio: 63/88;
  object-fit: cover;
  display: block;
  background: var(--bg-active);
}
.version-name {
  padding: 6px 8px;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.version-del {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  font-size: var(--fs-sm);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s;
}
.version-card:hover .version-del {
  opacity: 1;
}
/* ═══ ОКНО ПРИВЕТСТВИЯ — «полиграфическая карточка» (23.09.2026) ══════════════════════════════
   Решение заказчика: одно окно, без эмодзи, коротко и картинкой. Замысел: веер из трёх карт с
   метками реза по углам (сразу видно — речь о настоящих картах и о типографии), заголовок
   антиквой Playfair Display (печатная традиция; шрифт свой, локальный — чужих хостов 0), шесть
   плиток с векторными значками одного штриха, внизу цена от сервера и две кнопки.
   Цвета — только токены: три темы переопределяют их у себя. Карты веера — бумага, их цвета
   одинаковы во всех темах (как на столе). Движение по правилам проекта: только opacity и подъём
   на 10 px, 0,55 с, cubic-bezier(.16,1,.3,1), ступень 90 мс; никаких scale/rotate при появлении;
   prefers-reduced-motion — без движения. */
.onboard-modal {
  align-items: center;
  padding: 16px 0;
}
.onboard-modal .ux-modal-box {
  max-width: 720px;
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  padding: 28px 30px 24px;
  animation: obUp 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes obUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
.ob-head {
  display: grid;
  grid-template-columns: 176px 1fr;
  gap: 26px;
  align-items: center;
}
.ob-fan {
  display: block;
  width: 176px;
  height: auto;
  color: var(--text-muted);
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.22));
}
.ob-crop {
  opacity: 0.7;
}
.ob-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}
.ob-title {
  margin: 8px 0 10px;
  font-family: 'Playfair Display', Georgia, 'Times New Roman', serif;
  font-size: 30px;
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  text-wrap: balance;
}
.ob-lead {
  margin: 0;
  max-width: 42ch;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.ob-grid {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.ob-tile {
  display: grid;
  grid-template-columns: 34px 1fr;
  grid-template-rows: auto auto;
  column-gap: 11px;
  align-items: center;
  padding: 12px 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-active);
  animation: obUp 0.55s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.ob-ico {
  grid-row: span 2;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  color: var(--accent);
  background: var(--accent-dim);
}
.ob-ico svg {
  width: 20px;
  height: 20px;
}
.ob-tile b {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text-primary);
}
.ob-tile span:not(.ob-ico) {
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--text-secondary);
}
.ob-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  animation: obUp 0.55s cubic-bezier(0.16, 1, 0.3, 1) 0.66s both;
}
.ob-price span {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ob-price b {
  display: block;
  margin: 2px 0 1px;
  font-family: 'Playfair Display', Georgia, 'Times New Roman', serif;
  font-size: 26px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text-primary);
}
.ob-price small {
  display: block; /* цена — строчный блок (ради линии под ней), подпись обязана встать ниже */
  font-size: 12px;
  color: var(--text-secondary);
}
.ob-actions {
  display: flex;
  gap: 10px;
  flex: 0 0 auto;
}
/* Кнопки окна — родные .ux-btn / .ux-primary, только габарит свой: 44 px — норма касания, и
   «Как это работает» выглядит кнопкой (ссылку-подпись не нажимают). */
.onboard-modal .ob-actions .ux-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-height: 44px;
  margin: 0;
  padding: 0 20px;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
}
.onboard-modal .ob-go {
  min-width: 150px;
  font-size: 15px;
  font-weight: 700;
}
@media (max-width: 700px) {
  .onboard-modal .ux-modal-box {
    padding: 18px 16px 14px;
  }
  .ob-head {
    grid-template-columns: 1fr;
    gap: 10px;
    justify-items: center;
    text-align: center;
  }
  .ob-fan {
    width: 112px;
  }
  .ob-title {
    margin: 6px 0 8px;
    font-size: 23px;
  }
  .ob-lead {
    font-size: 13.5px;
  }
  .ob-lead {
    margin: 0 auto;
  }
  .ob-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin-top: 14px;
  }
  /* на узком экране значок сбоку отнимал треть ширины — заголовки ломались в три строки;
     значок встаёт над текстом */
  .ob-tile {
    grid-template-columns: 1fr;
    justify-items: center;
    row-gap: 2px;
    padding: 10px 8px 9px;
    text-align: center;
  }
  .ob-ico {
    grid-row: auto;
    width: 30px;
    height: 30px;
    margin-bottom: 6px;
  }
  /* окно обязано помещаться в экран телефона целиком: вторая строка плитки здесь лишняя —
     заголовки говорят сами за себя, а подробности есть на странице «Как это работает» */
  .ob-tile span:not(.ob-ico) {
    display: none;
  }
  .ob-foot {
    gap: 12px;
    margin-top: 14px;
    padding-top: 12px;
    flex-direction: column;
    align-items: stretch;
    text-align: center;
  }
  .ob-actions {
    flex-direction: column-reverse;
  }
  .onboard-modal .ob-actions .ux-btn {
    width: 100%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .onboard-modal .ux-modal-box,
  .ob-tile,
  .ob-foot {
    animation: none;
  }
}

/* ═══ ОКНО ПРИВЕТСТВИЯ — СЮЖЕТ ДВИЖЕНИЯ (23.09.2026, просьба заказчика: «премиальный,
   эстетичный и эффектный анимационный сюжет… как первое впечатление») ═══════════════════════
   Сюжет за ~1,6 с, один раз: окно поднимается → три карты по очереди ложатся в веер (рубашка,
   туз пик, туз червей) → вокруг прорисовываются метки реза, как на печатном листе → строки
   заголовка → плитки, и их значки рисуются штрихом → под ценой прочерчивается линия.
   Дальше окно живёт тихо: раз в 10 с по картам и по кнопке «Начать» проходит медленный блик
   (правило проекта: редкий медленный блик — можно), под курсором плитки приподнимаются на
   2 px и по ним идёт мягкий свет, веер слегка следует за мышью.
   ЗАПРЕТЫ ПРОЕКТА СОБЛЮДЕНЫ: нет появления из точки (scale(0)), нет пружинных кривых, нет
   доворота при появлении — карты веера повёрнуты статично, движется только подъём; все движения
   ≥ 0,3 с по cubic-bezier(.16,1,.3,1); анимируются transform/opacity и штрих мелких SVG;
   prefers-reduced-motion — всё стоит. Подъём под курсором — свойством translate, а не
   transform: transform занят анимацией появления, и её заполнение переписало бы наведение. */
.ob-head {
  position: relative;
}
/* мягкий свет за веером — дышит медленно, почти незаметно */
.ob-head::before {
  content: '';
  position: absolute;
  left: -10px;
  top: 50%;
  width: 200px;
  height: 200px;
  margin-top: -100px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-dim), transparent 68%);
  opacity: 0.6;
  pointer-events: none;
  animation: obBreathe 7s ease-in-out 1.6s infinite;
}
@keyframes obBreathe {
  50% {
    opacity: 1;
  }
}
.ob-fan {
  position: relative;
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0);
  transition: transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.ob-deal {
  transform-box: fill-box;
  animation: obDeal 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.ob-deal:nth-of-type(1) {
  animation-delay: 0.15s;
}
.ob-deal:nth-of-type(2) {
  animation-delay: 0.27s;
}
.ob-deal:nth-of-type(3) {
  animation-delay: 0.39s;
}
@keyframes obDeal {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
}
.ob-crop path {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: obDraw 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.ob-crop path:nth-child(1) {
  animation-delay: 0.62s;
}
.ob-crop path:nth-child(2) {
  animation-delay: 0.7s;
}
.ob-crop path:nth-child(3) {
  animation-delay: 0.78s;
}
.ob-crop path:nth-child(4) {
  animation-delay: 0.86s;
}
@keyframes obDraw {
  to {
    stroke-dashoffset: 0;
  }
}
.ob-glint {
  transform-box: view-box;
  transform: translateX(0) skewX(-18deg);
  animation: obGlint 10s cubic-bezier(0.45, 0, 0.25, 1) 2.2s infinite;
}
@keyframes obGlint {
  0% {
    transform: translateX(0) skewX(-18deg);
  }
  14%,
  100% {
    transform: translateX(340px) skewX(-18deg);
  }
}
.ob-eyebrow,
.ob-title,
.ob-lead {
  animation: obUp 0.6s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.ob-eyebrow {
  animation-delay: 0.2s;
}
.ob-title {
  animation-delay: 0.3s;
}
.ob-lead {
  animation-delay: 0.42s;
}
/* плитки: общая задержка в переменной — её же берёт прорисовка значка */
.ob-grid .ob-tile {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  animation-delay: var(--d);
  transition:
    translate 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.ob-grid .ob-tile:nth-child(1) {
  --d: 0.5s;
}
.ob-grid .ob-tile:nth-child(2) {
  --d: 0.59s;
}
.ob-grid .ob-tile:nth-child(3) {
  --d: 0.68s;
}
.ob-grid .ob-tile:nth-child(4) {
  --d: 0.77s;
}
.ob-grid .ob-tile:nth-child(5) {
  --d: 0.86s;
}
.ob-grid .ob-tile:nth-child(6) {
  --d: 0.95s;
}
.ob-tile::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(
    150px circle at var(--mx, 50%) var(--my, 50%),
    var(--accent-dim),
    transparent 65%
  );
  opacity: 0;
  transition: opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.ob-tile:hover {
  translate: 0 -2px;
  border-color: var(--accent-dim);
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, 0.45);
}
.ob-tile:hover::before {
  opacity: 1;
}
.ob-ico svg * {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: obDraw 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(var(--d, 0s) + 0.18s);
}
.ob-ico {
  transition: background 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.ob-tile:hover .ob-ico {
  background: var(--accent-dim);
  box-shadow: inset 0 0 0 1px var(--accent-dim);
}
.ob-foot {
  animation-delay: 1.02s;
}
.ob-price b {
  position: relative;
  display: inline-block;
}
.ob-price b::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  opacity: 0.8;
  transform: scaleX(0);
  transform-origin: left center;
  animation: obLine 0.8s cubic-bezier(0.16, 1, 0.3, 1) 1.35s forwards;
}
@keyframes obLine {
  to {
    transform: scaleX(1);
  }
}
/* кнопки: подъём на 2 px, тень гуще; у «Начать» — стрелка вперёд и редкий блик */
.onboard-modal .ob-actions .ux-btn {
  transition:
    translate 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    color 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.onboard-modal .ob-actions .ux-btn:hover {
  translate: 0 -2px;
}
.onboard-modal .ob-actions .ux-btn:active {
  translate: 0 0;
  transition-duration: 0.12s;
}
.onboard-modal .ob-go {
  position: relative;
  overflow: hidden;
  gap: 8px;
  box-shadow: 0 8px 20px -10px var(--accent);
}
.onboard-modal .ob-go:hover {
  box-shadow: 0 14px 28px -12px var(--accent);
}
.onboard-modal .ob-go::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  transform: translateX(-120%) skewX(-18deg);
  animation: obBtnShine 10s cubic-bezier(0.45, 0, 0.25, 1) 2.9s infinite;
  pointer-events: none;
}
@keyframes obBtnShine {
  0% {
    transform: translateX(-120%) skewX(-18deg);
  }
  12%,
  100% {
    transform: translateX(340%) skewX(-18deg);
  }
}
.ob-arrow {
  width: 18px;
  height: 18px;
  transition: translate 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
.onboard-modal .ob-go:hover .ob-arrow {
  translate: 3px 0;
}
.onboard-modal .ob-about:hover {
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim),
    0 10px 22px -14px rgba(0, 0, 0, 0.5);
}
@media (prefers-reduced-motion: reduce) {
  .ob-head::before,
  .ob-deal,
  .ob-crop path,
  .ob-glint,
  .ob-eyebrow,
  .ob-title,
  .ob-lead,
  .ob-ico svg *,
  .ob-price b::after,
  .onboard-modal .ob-go::after {
    animation: none;
  }
  .ob-crop path,
  .ob-ico svg * {
    stroke-dashoffset: 0;
  }
  .ob-price b::after {
    transform: none;
  }
  .onboard-modal .ob-go::after {
    display: none;
  }
  .ob-fan,
  .ob-tile,
  .onboard-modal .ob-actions .ux-btn,
  .ob-arrow {
    transition: none;
    transform: none;
    translate: none;
  }
}

/* ===== Менеджер списков: поиск + фильтр-категории (иконки, рамки) ===== */
.mgr-search {
  position: relative;
  margin: 2px 2px 8px;
}
.mgr-search input {
  width: 100%;
  padding: 8px 10px 8px 30px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 9px;
  color: var(--text-primary);
  font-size: var(--fs-12-5);
  outline: none;
}
.mgr-search input:focus {
  border-color: var(--accent);
}
.mgr-search::before {
  content: '⌕';
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  font-size: var(--fs-lg);
  pointer-events: none;
}
/* ПРАВИЛО ПЛОТНОСТИ — то же, что у рангов в меню «Показ»: категорий два с лишним десятка, и
   столько же выпуклых пилюль рядом читались бы шумом, а не рельефом. Сетка лежит в общей
   ВДАВЛЕННОЙ канавке, выпуклая в ней ровно одна — выбранная категория. */
.mgr-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 0 2px 10px;
  padding: 6px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.mgr-chip {
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  background: none;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.mgr-chip:hover {
  color: var(--text-primary);
  transform: translateY(-1px);
}
.mgr-chip.active {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  border-color: transparent;
  color: var(--accent);
}
.mgr-count {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin: 0 4px 8px;
}
.mgr-empty {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  text-align: center;
  padding: 22px 8px;
  line-height: 1.5;
}

/* ===== CMYK-каналы (премиум: бейдж + −/+ + цветная шкала + число) ===== */
.cmyk2 {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-bottom: 10px;
}
.cmyk2-row {
  display: flex;
  align-items: center;
  gap: 7px;
}
.cmyk2-badge {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 7px;
  font-size: var(--fs-sm);
  font-weight: 700;
}
.cmyk2-btn {
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-2xl);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    color 0.12s ease,
    transform 0.08s ease;
}
.cmyk2-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--bg-hover);
}
.cmyk2-btn:active {
  transform: scale(0.9);
}
.cmyk2-track {
  flex: 1;
  min-width: 36px;
  height: 24px;
  position: relative;
  overflow: hidden;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg-active);
  cursor: ew-resize;
  touch-action: none;
  user-select: none;
}
.cmyk2-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 0;
  opacity: 0.9;
  pointer-events: none;
  transition: width 0.08s linear;
}
.cmyk2-val {
  width: 44px;
  flex: 0 0 auto;
  text-align: center;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text-primary);
  font-size: var(--fs-md);
  font-weight: 600;
  padding: 5px 2px;
  -moz-appearance: textfield;
}
.cmyk2-val:focus {
  border-color: var(--accent);
  outline: none;
}
.cmyk2-val::-webkit-outer-spin-button,
.cmyk2-val::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
/* Раскрывашка точной настройки CMYK */
.cmyk-disclosure {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 7px 4px;
  margin-bottom: var(--sp-1);
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  text-align: left;
}
/* СТРОКА-РАСКРЫВАШКА: в покое плоская, рельеф появляется под курсором, открытая — вдавлена.
   Тот же приём, что у строк слоёв в левой панели, и по той же причине: четыре выпуклые
   строки подряд превращают блок в стиральную доску (урок оплачен шапками аккордеона). */
.cmyk-disclosure {
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.cmyk-disclosure:hover {
  color: var(--accent);
  box-shadow: var(--nm-out-xs);
}
.cmyk-disclosure.open {
  box-shadow: var(--nm-in-sm);
}
.cmyk-caret {
  display: inline-block;
  transition: transform 0.15s ease;
  font-size: var(--fs-2xs);
}
.cmyk-disclosure.open .cmyk-caret {
  transform: rotate(90deg);
}
.cmyk-panel {
  display: none;
}
.cmyk-panel.open {
  display: block;
}

/* ===== Панель «История» (иллюстрированная) ===== */
.hist-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 4px 10px;
}
.hist-title {
  font-size: var(--fs-base);
  font-weight: 700;
  color: var(--text-primary);
  flex: 1;
}
.hist-iconbtn {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  cursor: pointer;
}
.hist-iconbtn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.hist-iconbtn:disabled {
  opacity: 0.4;
  cursor: default;
}
.hist-iconbtn svg {
  width: 16px;
  height: 16px;
}
.hist-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  position: relative;
}
.hist-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease;
}
.hist-row:hover {
  background: var(--bg-hover);
}
.hist-row.active {
  background: var(--accent-dim);
  border-color: var(--accent);
}
.hist-row.future {
  opacity: 0.45;
}
.hist-icon {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: var(--bg-active);
  color: var(--text-secondary);
}
.hist-row.active .hist-icon {
  background: var(--accent);
  color: #10141c;
}
.hist-icon svg {
  width: 15px;
  height: 15px;
}
.hist-label {
  flex: 1;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hist-row.active .hist-label {
  color: var(--accent);
  font-weight: 600;
}
.hist-step {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  background: var(--bg-active);
  border-radius: 4px;
  padding: 1px 6px;
}
/* E-329. Время шага. Читается вторым после названия действия, поэтому приглушено и без
   подложки — иначе спорило бы с номером шага за внимание. Моноширинные цифры: в столбце
   из десятков строк разноширокие цифры «пляшут» и мешают вести взгляд сверху вниз. */
.hist-time {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0.85;
}
.hist-row.active .hist-time {
  color: var(--accent);
  opacity: 1;
}
.hist-empty {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  text-align: center;
  padding: 24px 8px;
  line-height: 1.5;
}

/* Подсветка холста при перетаскивании файла проекта */
#canvas-area.drop-target {
  outline: 2px dashed var(--accent);
  outline-offset: -8px;
  background: rgba(106, 184, 238, 0.06);
}

.dropdown-icon {
  font-size: var(--fs-3xl);
  line-height: 1;
  margin-top: 2px;
  flex: 0 0 auto;
  color: var(--accent);
}
.dropdown-icon svg {
  width: 22px;
  height: 22px;
  display: block;
}

.dropdown-item strong {
  display: block;
  font-size: var(--fs-base);
  color: var(--text-primary);
  margin-bottom: 3px;
}

.dropdown-item small {
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  line-height: 1.4;
}

/* ===== РАБОЧАЯ ОБЛАСТЬ ===== */
#workspace {
  display: flex;
  height: calc(100vh - var(--toolbar-height));
  width: 100%;
}

/* ЧАСТЬ 2А: КОНЕЦ */
/* ЧАСТЬ 2Б: НАЧАЛО — Левая панель, Холст, Правая панель, Модалка пресетов */

/* ===== ЛЕВАЯ ПАНЕЛЬ ===== */
#panel-left {
  width: var(--panel-left-width);
  min-width: var(--panel-left-width);
  background: var(--bg-secondary);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Вкладки (Слои / Библиотека / Мои файлы) */
.panel-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  padding: var(--sp-2);
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--bg-tertiary), var(--bg-secondary));
  flex-shrink: 0;
}

.panel-tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 9px 4px 7px;
  font-size: var(--fs-10-5);
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--text-muted);
  text-align: center;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  position: relative;
  cursor: pointer;
  transition:
    color 0.16s ease,
    background 0.16s ease,
    border-color 0.16s ease,
    transform 0.1s ease,
    box-shadow 0.16s ease;
}
.panel-tab svg {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
}
.panel-tab span {
  line-height: 1;
}
.panel-tab:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
  transform: translateY(-1px);
}
.panel-tab.active {
  color: var(--accent);
  background: var(--accent-dim);
  border-color: var(--accent);
  box-shadow: 0 4px 12px rgba(106, 184, 238, 0.16);
}
/* БЕЗ НЕОНА (2026-08-17). Иконка активной вкладки светилась голубым ореолом. Активность уже
   объявлена цветом, фоном и рамкой — свечение было четвёртым способом сказать то же самое, и
   именно оно давало панели «светящийся» вид, на который жаловался заказчик. */
.panel-tab.active svg {
  color: var(--accent);
}

/* Контент вкладок */
.panel-content {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-2);
}

/* ===== ЛЕВОЕ МЕНЮ v4: Слои сверху (всегда видны) + ресурсы снизу ===== */
/* Ресурсы и формат уехали в верхнее меню — слои занимают всю высоту панели,
   прокрутка больше не нужна (места хватает). */
#panel-layers-region {
  flex: 1 1 auto;
  max-height: none;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Контекст-маркер «Редактируется: …» и баннер «МАСТЕР КОЛОДЫ» УДАЛЕНЫ вместе с разметкой:
   на вопрос «что изменит правка» отвечает плашка «Меняю: …» (.scope-head), и ответ там один. */

/* РЕГИОН ДЕЙСТВИЙ НАД КОЛОДОЙ — брат «Слоёв», а не их часть. Не сжимается: список слоёв
   листается сам (.panel-layers overflow-y:auto), а действия должны быть целыми — наполовину
   обрезанная кнопка «Случайная колода» читается как поломка. */
#panel-deck-region {
  /* E-309: было `flex: 0 0 auto` — регион не сжимался вовсе. Пока шрифт был 9–13 px, это не
     мешало; после подъёма шкалы блок вырос и на 1280×720 ВЫДАВИЛ список слоёв почти целиком —
     от него оставалась полоска. Слои — главное содержимое панели, поэтому уступает регион:
     он сжимается и листается сам, а не съедает чужое место. */
  flex: 0 1 auto;
  min-height: 0;
  max-height: 52vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border);
}
/* Шапка региона не уезжает при прокрутке его содержимого: иначе, пролистав действия, человек
   теряет из виду, к чему они относятся. */
#panel-deck-region > .region-header {
  position: sticky;
  top: 0;
  z-index: 1;
}
/* E-315: содержимое региона НЕ сжимается. Регион — flex-колонка с прокруткой, а у flex-детей
   по умолчанию flex-shrink:1: когда «Колода целиком» перестала помещаться, соседний блок
   «Знак заказчика» ужался с 42 px до 2 px и уехал за нижнюю кромку — до него нельзя было ни
   дотянуться мышью, ни увидеть его. Высоту держат дети, прокрутку — регион. */
#panel-deck-region > * {
  flex: 0 0 auto;
}

/* Блок «Колода целиком» под слоями мастера (Случайная колода / AI-студия). */
/* ── «КОЛОДА ЦЕЛИКОМ» — премиум-блок генерации внизу левой панели.
   Кнопки-градиенты с бликом (sheen) и живыми иконками; темы — через токены. ── */
/* Блок «Знак заказчика» (E-291, переработан в E-293).
   Был развёрнутой панелью на 391 px, которая выталкивала список слоёв за экран. Стал
   строкой ростом со строку слоя: в покое — миниатюра, название и шеврон, остальное по
   требованию. Постоянно занимать треть панели ради трёх кнопок нельзя. */
.logo-actions {
  display: flex;
  flex-direction: column;
  margin: 8px 12px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-tertiary);
  overflow: hidden;
}
.logo-actions .logo-head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}
.logo-actions .logo-head:hover {
  background: var(--bg-hover);
}
.logo-actions .logo-head:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.logo-actions .logo-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  overflow: hidden;
}
.logo-actions .logo-chip img {
  max-width: 20px;
  max-height: 20px;
  object-fit: contain;
}
.logo-actions .logo-head-name {
  flex: 1;
}
.logo-actions .logo-chev {
  display: inline-flex;
  color: var(--text-muted);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.logo-actions .logo-chev svg {
  width: 14px;
  height: 14px;
}
.logo-actions.is-open .logo-chev {
  transform: rotate(180deg);
}
/* Раскрытие: содержимое существует всегда (иначе не нажать с клавиатуры при переходе),
   но в свёрнутом виде не занимает места и не участвует в табуляции. */
.logo-actions .logo-body {
  display: none;
  flex-direction: column;
  gap: 8px;
  padding: 2px 10px 10px;
}
.logo-actions.is-open .logo-body {
  display: flex;
}
.logo-actions .logo-file-row {
  display: flex;
  gap: 6px;
  margin-top: 2px;
}
.logo-actions .logo-file-btn {
  flex: 1;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
  transition:
    border-color 0.18s ease,
    color 0.18s ease;
}
.logo-actions .logo-file-btn:hover {
  border-color: var(--accent);
  color: var(--text-primary);
}
/* Удаление — отдельного веса действие: краснеет только при наведении, чтобы не кричать
   постоянно, но и не притворяться обычной кнопкой. */
.logo-actions .logo-file-btn.is-danger:hover {
  border-color: var(--danger, #e5484d);
  color: var(--danger, #e5484d);
}
.logo-actions .logo-file-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
  .logo-actions .logo-chev {
    transition: none;
  }
}
.logo-actions .logo-prev {
  display: flex;
  align-items: center;
  justify-content: center;
  /* E-293: превью служит опознанию, а не любованию — в боковой панели место дорогое. */
  min-height: 56px;
  padding: 6px;
  border-radius: var(--radius-md);
  /* Шахматка: показывает прозрачность знака честно — на ней видно, что фон выбит. */
  background-color: var(--bg-secondary);
  background-image:
    linear-gradient(
      45deg,
      color-mix(in srgb, var(--text-muted) 14%, transparent) 25%,
      transparent 25%
    ),
    linear-gradient(
      -45deg,
      color-mix(in srgb, var(--text-muted) 14%, transparent) 25%,
      transparent 25%
    ),
    linear-gradient(
      45deg,
      transparent 75%,
      color-mix(in srgb, var(--text-muted) 14%, transparent) 75%
    ),
    linear-gradient(
      -45deg,
      transparent 75%,
      color-mix(in srgb, var(--text-muted) 14%, transparent) 75%
    );
  background-size: 12px 12px;
  background-position:
    0 0,
    0 6px,
    6px -6px,
    -6px 0;
}
.logo-actions .logo-prev img {
  max-width: 100%;
  max-height: 64px;
  object-fit: contain;
}
.logo-actions .logo-note {
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-muted);
}
/* БЕЗ КАРТОЧКИ-В-КАРТОЧКЕ. Здесь была своя рамка с акцентным градиентом — а блок и так живёт
   в регионе с шапкой «КОЛОДА ЦЕЛИКОМ» и собственной верхней границей. Выходила коробка внутри
   коробки: два контура вокруг одного и того же, и глазу приходилось разбирать, где кончается
   одно и начинается другое (жалоба заказчика 2026-08-17 про перенасыщенное меню).

   Плитки внутри — сами по себе яркие поверхности с заливкой; вторая рамка вокруг них не
   добавляла ни группировки, ни иерархии, только 26 px по высоте и лишний контур. Группировку
   держит шапка региона, а разделение — воздух. */
.deck-actions {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 10px 12px;
}
.deck-actions-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.deck-actions-title svg {
  width: 14px;
  height: 14px;
  color: var(--accent);
}
/* E-325. БЛОК СОЗДАНИЯ — КОМПАКТНЫЙ РЯД, А НЕ ТРИ БАННЕРА.
   Замер: «Колода целиком» занимала 397 px — больше, чем весь список слоёв (174 px). При этом
   она отвечает на другой вопрос: не «что я правлю», а «с чего начать». Три крупные кнопки с
   описаниями оправданы на пустом старте, но каждый день мешают: описания читают один раз,
   а место они занимают всегда. Стали тремя равными плитками в ряд — иконка и короткое имя;
   полные пояснения остались в подсказках при наведении. */
#deck-actions .deck-act-row {
  display: grid;
  /* ТРИ КОЛОНКИ — ПО ЧИСЛУ СПОСОБОВ СОЗДАТЬ, а «Улучшить» уходит строкой ниже (правило после
     этого блока). Здесь стояло repeat(3, 1fr) при ЧЕТЫРЁХ плитках: «Улучшить» добавили позже и
     сетку не тронули — плитка падала вторым рядом-сиротой, и блок занимал 156 px вместо 75.
     Это и был почти весь дефицит высоты панели, из-за которого генерация колоды уезжала за
     нижний край (жалоба заказчика 2026-08-17: «знак убирает вниз генерацию колод»).

     ПОЧЕМУ НЕ ЧЕТЫРЕ КОЛОНКИ. Пробовал: ряд стал 75 px, но подписям осталось по 42 px при
     нужных 54 («Картинка») и 57 («Улучшить») — буквы срезало. Замер тогда сказал «не обрезано»,
     потому что мерил сам .da-name: с nowrap он растягивается, его scrollWidth равен clientWidth,
     а срезает РОДИТЕЛЬ. Сравнивать надо ширину текста с внутренней шириной кнопки.

     Разведены не ради места, а по смыслу: три плитки — способы СОЗДАТЬ колоду, «Улучшить» —
     проверка уже созданной. Разные по природе действия и в один ряд не просились. */
  /* 23.09.2026: шесть долей — три плитки создания по две доли, нижняя строка «Тексты | Улучшить»
     по три: пятое действие не добавило ряда и высоты. */
  grid-template-columns: repeat(6, 1fr);
  gap: 4px;
}
#deck-actions .deck-act-row .deck-act-btn {
  grid-column: span 2;
}
#deck-actions .deck-act-row .deck-act-btn {
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 4px;
  min-height: 0;
  text-align: center;
}
/* «Улучшить» — во всю ширину под рядом создания: иконка и подпись в строку. Так подписи хватает
   места целиком, а высоты блок берёт 36 px вместо 81 (сирота-плитка в своём ряду сетки). */
#deck-actions .deck-act-row #deck-act-improve,
#deck-actions .deck-act-row #deck-act-texts {
  grid-column: span 3;
  flex-direction: row;
  justify-content: center;
  /* Строка проверки намеренно ниже плиток создания: она вторична по частоте и не должна
     спорить с ними за взгляд. 44 px — нижняя граница цели нажатия (Apple HIG), ниже не ужимать. */
  padding: 6px 10px;
  min-height: 44px;
}
#deck-actions .deck-act-row #deck-act-improve .da-text,
#deck-actions .deck-act-row #deck-act-texts .da-text {
  width: auto;
}
#deck-actions .deck-act-row #deck-act-improve .da-ico,
#deck-actions .deck-act-row #deck-act-texts .da-ico {
  width: 24px;
  height: 24px;
  border-radius: 7px;
}
#deck-actions .deck-act-row #deck-act-improve .da-ico svg,
#deck-actions .deck-act-row #deck-act-texts .da-ico svg {
  width: 15px;
  height: 15px;
}
#deck-actions .deck-act-row .da-hint {
  display: none; /* описание живёт в подсказке — на экране его место дороже */
}
#deck-actions .deck-act-row .da-name {
  font-size: var(--fs-3xs);
  line-height: 1.2;
  /* Дефисные переносы («Случай-ная») читаются как брак вёрстки — вместо них укоротили
     сами подписи. Слово должно помещаться целиком. */
  hyphens: none;
  overflow-wrap: normal;
  white-space: nowrap;
}
#deck-actions .deck-act-row .da-text {
  display: block;
  width: 100%;
  min-width: 0;
}
#deck-actions .deck-act-row .da-ico svg {
  width: 20px;
  height: 20px;
}
.deck-act-btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  padding: 9px 13px;
  min-height: 50px;
  border: none;
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-align: left;
  cursor: pointer;
  transition:
    transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow 0.18s ease,
    filter 0.18s ease;
}
/* БЛИК УДАЛЁН (2026-08-17). По кнопке при наведении пробегала полоса света. Она ничего не
   сообщала — ни о состоянии, ни о последствии нажатия: чистое украшение, а такие анимации
   первыми выдают «сделано автоматом» и утомляют на каждом наведении. Отклик на наведение
   остался там, где он осмыслен: подсветка фона и лёгкий подъём кнопки (см. transition выше). */
.deck-act-btn .da-ico {
  display: inline-flex;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.deck-act-btn .da-ico svg {
  width: 17px;
  height: 17px;
}
.deck-act-btn .da-text {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  line-height: var(--lh-tight);
  min-width: 0;
}
.deck-act-btn .da-name {
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: 0.01em;
}
.deck-act-btn .da-hint {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-regular);
  opacity: 0.72;
  /* E-309: было nowrap + многоточие. После подъёма шкалы подсказки перестали помещаться в
     одну строку и обрывались на полуслове («логотип или фото — в центр…»). Обрезанный текст
     хуже переноса: он ничего не объясняет, а место всё равно занимает. Разрешаем перенос —
     кнопка станет на строку выше, зато подпись читается целиком. */
  white-space: normal;
  overflow-wrap: anywhere;
}
.deck-act-btn:hover {
  transform: translateY(-1px);
  filter: brightness(1.06);
}
.deck-act-btn:active {
  transform: translateY(0) scale(0.97);
}
.deck-act-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.deck-act-btn.busy {
  opacity: 0.6;
  pointer-events: none;
}
/* «Случайная колода» — фирменный градиент; кубик подкручивается при наведении. */
.deck-act-btn.da-random {
  background: var(--accent-grad);
  color: #0e1116;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 30%, transparent);
}
.deck-act-btn.da-random:hover {
  box-shadow: 0 7px 20px color-mix(in srgb, var(--accent) 42%, transparent);
}
.deck-act-btn.da-random:hover .da-ico {
  transform: rotate(-14deg) scale(1.1);
}
html[data-theme='light'] .deck-act-btn.da-random {
  color: #fff;
}
/* «AI-студия» — глубокий фиолетовый градиент с живым свечением; искра мерцает. */
.deck-act-btn.da-ai {
  background: linear-gradient(135deg, #5b4bd4 0%, #8a4fd0 55%, #c04a9e 100%);
  color: #fff;
  box-shadow: 0 4px 14px rgba(140, 80, 210, 0.32);
  animation: da-ai-glow 3.2s ease-in-out infinite;
}
@keyframes da-ai-glow {
  0%,
  100% {
    box-shadow: 0 4px 14px rgba(140, 80, 210, 0.28);
  }
  50% {
    box-shadow: 0 5px 20px rgba(160, 85, 220, 0.46);
  }
}
.deck-act-btn.da-ai:hover .da-ico {
  transform: scale(1.12);
}
.deck-act-btn.da-ai:hover .da-ico svg {
  animation: da-sparkle 1.1s ease-in-out infinite;
}
@keyframes da-sparkle {
  0%,
  100% {
    transform: rotate(0deg) scale(1);
  }
  50% {
    transform: rotate(14deg) scale(1.12);
  }
}
/* «Логотип на колоду» / «Фото-колода» — ВТОРИЧНЫЕ CTA: подчинены главной «Случайной
   колоде» (progressive disclosure). Мягкая токеновая заливка вместо фирменного градиента —
   тише по весу, но такая же кликабельная площадь и доступность (фокус-ринг наследуется). */
/* Мягкая кнопка действия — ВЫДАВЛЕНА, как её родня в инспекторе. Стояло `box-shadow: none`,
   и на листе колоды рядом с рельефными плитками она читалась как надпись, а не как кнопка.
   Габарит держит прозрачная рамка: линию заменяет тень, размер остаётся прежним. */
.deck-act-btn.da-soft {
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-secondary));
  color: var(--text-primary);
  border: 1px solid transparent;
  box-shadow: var(--nm-out-sm);
}
.deck-act-btn.da-soft:active {
  box-shadow: var(--nm-in-sm);
}
.deck-act-btn.da-soft .da-ico {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  box-shadow: none;
  color: var(--accent);
}
.deck-act-btn.da-soft:hover {
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-secondary));
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
@media (prefers-reduced-motion: reduce) {
  .deck-act-btn,
  .deck-act-btn .da-ico {
    transition: none;
  }
  .deck-act-btn.da-ai {
    animation: none;
  }
  .deck-act-btn:hover::after,
  .deck-act-btn.da-ai:hover .da-ico svg {
    animation: none;
  }
}
/* ── Точечное обновление колоды: чипы «Обновить только палитра/рамка/фон/…» ── */
/* ── СЕЛЕКТОР «ОБЛАСТЬ ПРАВКИ» слоя лица (выбор поверхностей) ── */
/* Строка выбора охвата над списком слоёв (этап 2 единообразия) */
.scope-bar {
  border-bottom: 1px solid var(--border);
}
/* Единая плашка охвата «Меняю: X» (Фаза 1) — ЕДИНСТВЕННЫЙ ответ на «что изменит правка».
   Прежний #layer-context удалён целиком: он повторял тот же факт и успел с ним разойтись. */
/* E-325: шапка охвата — КНОПКА (она же раскрывает выбор). Сетка из восьми наборов нужна
   редко, а ответ «куда уйдёт правка» — всегда; поэтому на виду остаётся строка, а сетка
   прячется под неё. Замер до правки: плашка занимала 214 px из 666 (треть панели), списку
   слоёв оставалось 174 px — три строки из тринадцати. */
.scope-head {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-bottom: 6px; /* E-309: было 9 */
  width: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.scope-head:hover .scope-head-val {
  color: var(--accent);
}
.scope-head:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
.scope-head-chev {
  margin-left: auto;
  display: inline-flex;
  align-self: center;
  color: var(--text-muted);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.scope-head-chev svg {
  width: 13px;
  height: 13px;
}
.edit-scope.is-open .scope-head-chev {
  transform: rotate(180deg);
}
/* Свёрнуто — на экране только строка «Меняю: …». Содержимое остаётся в DOM (состояние
   кнопок не пересобирается), но не занимает места и не участвует в табуляции. */
.edit-scope .scope-seg,
.edit-scope .scope-axis,
.edit-scope .edit-scope-pick {
  display: none;
}
.edit-scope.is-open .scope-seg {
  display: grid;
}
/* РЯД ЦЕЛИКОМ, А НЕ ТОЛЬКО КНОПКИ. Скриншот панели вскрыл: подписи «СТОРОНА» и «КАРТЫ»
   оставались висеть в свёрнутой плашке без единой кнопки — правило скрытия знало про
   `.scope-seg`, но не про обёртку ряда, появившуюся в шаге 1. Смотреть надо на экран. */
.edit-scope.is-open .scope-axis {
  display: flex;
}
/* Внутри ряда кнопки идут ГОРИЗОНТАЛЬНО с переносом. Общее правило ставит сегменту `grid`,
   а grid без колонок — это столбик: второй скриншот показал шесть кнопок в шесть строк.
   Ряд обязан читаться как ряд, иначе разведение осей теряет смысл. */
.edit-scope.is-open .scope-axis .scope-seg {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.edit-scope.is-open .edit-scope-pick {
  display: block;
}
/* Свёрнутая плашка — ровно одна строка: лишние отступы съедали бы выигрыш. */
.edit-scope:not(.is-open) {
  padding: 6px 10px;
  margin-bottom: 6px;
}
.edit-scope:not(.is-open) .scope-head {
  margin-bottom: 0;
}
/* Свёрнутая строка держится ОДНОЙ строки: длинный охват («Рубашку — одна на всю колоду»)
   переносился на две и съедал выигрыш. Полный текст остаётся в подсказке. */
.edit-scope:not(.is-open) .scope-head-val {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}
@media (prefers-reduced-motion: reduce) {
  .scope-head-chev {
    transition: none;
  }
}
.scope-head-lab {
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  /* Разрядка ужата с 0.08em: на слове «МЕНЯЮ:» она давала лишние 5 px, а именно их не хватало
     самым длинным значениям («Все лица — 54 карты» просило 149 при 141). Прописные с малой
     разрядкой читаются так же, а место уходит туда, где оно решает. */
  letter-spacing: 0.04em;
  /* E-308: было --text-muted. На фоне самой плашки (rgb(35,39,48) — светлее панели) это давало
     контраст 4.40 при норме 4.5. Токен не виноват: на фоне панели он даёт 5.01, беда именно в
     сочетании со светлой подложкой плашки. --text-secondary на том же фоне — 5.94, с запасом. */
  color: var(--text-secondary);
  font-weight: var(--fw-bold);
}
.scope-head-val {
  font-size: var(--fs-sm);
  color: var(--text-primary);
  font-weight: var(--fw-bold);
}
.scope-seg {
  margin-bottom: 6px; /* E-309: было 8 — экономим высоту плашки, см. .edit-scope-pill */
}
/* Кнопка «Править выбранные» — переход от выделения на листе к правке набора */
/* Поле своего текста лица (own-режим) */
.face-text-input {
  width: 100%;
  margin: 6px 0;
  padding: 8px 10px;
  font-size: var(--fs-sm);
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  resize: vertical;
}
.face-text-input:focus {
  outline: none;
  border-color: var(--accent);
}
/* ЯКОРЬ «ЗНАЧКИ МАСТИ (ПИПСЫ)» — постоянная строка-переход в списке слоёв рубашки.
   Не погашена (в отличие от .is-unavail): это не «слой, которого здесь нет», а важный элемент
   дизайна, за которым человек идёт осознанно. Отделена от слоёв рубашки чертой — она не участвует
   в порядке наложения и не перетаскивается. */
.layers-anchor {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border);
}
.layer-item.is-jump.is-anchor {
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background 0.16s ease;
}
.layer-item.is-jump.is-anchor:hover {
  background: var(--bg-hover);
}
.layer-item.is-jump.is-anchor:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Значок строки-перехода. Геометрию раньше давал класс «глаза», который висел на этом же
   элементе; класс убран (он означал бы «переключатель видимости», которого у перехода нет),
   поэтому размеры описаны здесь — иначе значок сжимается и подпись съезжает. */
.layer-anchor-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  opacity: 0.75;
  font-size: var(--fs-md);
}
.layer-item.is-jump.is-anchor .layer-jump-hint {
  margin-left: auto;
  padding-left: 6px;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.16s ease;
}
.layer-item.is-jump.is-anchor:hover .layer-jump-hint,
.layer-item.is-jump.is-anchor:focus-visible .layer-jump-hint {
  opacity: 1;
}
/* Погашенные слои другой поверхности (этап 3): видны все слои проекта */
.layers-unavail {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border);
}
.layers-unavail-head {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 4px 8px;
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  border-radius: var(--radius-sm);
  transition:
    color 0.12s ease,
    background 0.12s ease;
}
.layers-unavail-head:hover {
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--text-muted) 10%, transparent);
}
.layers-unavail-chev {
  display: inline-block;
  font-size: 0.85em;
  transition: transform 0.15s ease;
}
.layers-unavail:not(.collapsed) .layers-unavail-chev {
  transform: rotate(90deg);
}
.layers-unavail.collapsed .layers-unavail-body {
  display: none;
}
.layer-item.is-unavail {
  opacity: 0.36;
  pointer-events: none;
  cursor: default;
}
/* ВЫКЛЮЧЕННЫЙ СЛОЙ: ПРИГЛУШЕНО ЗНАЧЕНИЕ, А НЕ ЧИТАЕМОСТЬ (жалоба 2026-08-13 «левое меню
   почти не читается»). Прежде строку гасил инлайновый opacity из JS — 0.45 у списка рубашки
   и 0.5 у списка лица, — и весь текст уезжал за порог AA: имя слоя 4.07:1, чип охвата 2.33:1,
   в светлой теме 2.85 и 2.08. Инлайн вдобавок шёл мимо токенов, так что тема не могла ничего
   поправить.
   Здесь гасится ровно то, что несёт СМЫСЛ «слоя нет на карте»: имя уходит в тихий токен
   (5.01:1 в тёмной, 4.83:1 в светлой — тише активного, но читаемо), превью и значки теряют
   насыщенность. Главный признак остаётся прежним и нетекстовым: перечёркнутый потушенный
   глаз. Прозрачность на всю строку НЕ ставим — она и была болезнью.
   Граница: .is-unavail выше не трогаем, у него другой смысл — «слой другой поверхности». */
.layer-item.is-layer-off .layer-name {
  color: var(--text-muted);
  font-weight: 400;
}
.layer-item.is-layer-off .layer-thumb,
.layer-item.is-layer-off .layer-swatch,
.layer-item.is-layer-off .layer-foil-badge {
  opacity: 0.6;
}
/* E-322: строка ВЕДЁТ к слоям другой поверхности — значит нажимается и выглядит нажимаемой.
   Приглушена меньше прежнего (0.36 читалось как «сломано»), но заметно тише активных слоёв:
   это не место правки, а переход к нему. */
.layer-item.is-unavail.is-jump {
  opacity: 0.62;
  pointer-events: auto;
  cursor: pointer;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  font: inherit;
  color: inherit;
  transition:
    opacity 0.16s ease,
    background 0.16s ease;
}
.layer-item.is-unavail.is-jump:hover {
  opacity: 1;
  background: var(--bg-hover);
}
.layer-item.is-unavail.is-jump:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  opacity: 1;
}
/* Стрелка появляется под курсором — подсказывает «уведёт», не мозоля глаза постоянно. */
.layer-item.is-unavail.is-jump .layer-jump-hint {
  margin-left: auto;
  padding-left: 6px;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.16s ease;
}
.layer-item.is-unavail.is-jump:hover .layer-jump-hint,
.layer-item.is-unavail.is-jump:focus-visible .layer-jump-hint {
  opacity: 1;
}
.layer-item.is-unavail .layer-visibility {
  border: 1.5px dashed var(--text-muted);
  border-radius: 4px;
  background: none;
}
/* Плашка «Правка» — УТОПЛЕННАЯ область (волна 5): внутри неё лежат органы, и по языку
   материала область под ними углублена, как разделы студии. Акцентную подсветку слева
   сохраняем — она отвечает на другой вопрос («это про то, что вы сейчас правите»), и рельеф
   её не заменяет. Линия по краю снята: границу теперь даёт сама вдавленность. */
.edit-scope {
  margin: 8px;
  padding: 10px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  background:
    radial-gradient(
      120% 90% at 15% 0%,
      color-mix(in srgb, var(--accent) 9%, transparent),
      transparent 60%
    ),
    var(--nm-groove);
  box-shadow: var(--nm-in);
}
.edit-scope-title {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.edit-scope-note {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  line-height: var(--lh-normal);
}
/* Честное предупреждение: общий слой в суженном охвате изменит всю колоду */
.edit-scope-warn {
  display: flex;
  gap: 7px;
  align-items: flex-start;
  padding: 8px 9px;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--warning) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent);
  border-radius: var(--radius-md);
}
.edit-scope-warn svg {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--warning);
}
.edit-scope-warn b {
  color: var(--warning);
  font-weight: var(--fw-bold);
}
.insp-scope-warn {
  margin: 8px 0 10px;
}
/* Строка распространения слоя на серию карт (Фаза 3) */
.insp-propagate {
  margin: 8px 0 10px;
  padding: 9px 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.insp-propagate-lab {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.insp-propagate-row {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.insp-propagate-btn {
  padding: 4px 9px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.insp-propagate-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
/* Строка «N карт со своим стилем не изменятся» + сброс их к общему */
.insp-locked {
  margin: 8px 0 10px;
  padding: 9px 10px;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-secondary);
  border: 1px dashed color-mix(in srgb, var(--warning) 45%, var(--border));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--warning) 8%, transparent);
}
.insp-locked-lab b {
  color: var(--warning);
}
.insp-locked-btn {
  margin-top: 8px;
  padding: 4px 10px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.insp-locked-btn:hover {
  border-color: var(--warning);
  color: var(--warning);
}
/* ПАСПОРТ КАРТЫ: перечень того, что у этой карты (группы, набора) настроено отдельно.
   Токены те же, что у соседних блоков панели — свой цвет здесь развёл бы одинаковые по смыслу
   плашки на два вида. Строка = слой + кнопка возврата. */
.insp-passport {
  margin: 8px 0 10px;
  padding: 9px 10px;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-secondary);
  border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
}
.insp-passport-lab {
  margin-bottom: 6px;
}
.insp-passport-lab b {
  color: var(--accent);
}
.insp-passport-row {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
  padding: 3px 0;
  border-top: 1px solid var(--border-light);
}
.insp-passport-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}
.insp-passport-btn {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  color: var(--text-secondary);
  cursor: pointer;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
/* Короткая вспышка: человек пришёл сюда с зелёной точки, и глаз должен найти место сам. */
.insp-passport-flash {
  animation: insp-passport-flash 1.2s ease-out;
}
@keyframes insp-passport-flash {
  0% {
    border-color: var(--accent);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent);
  }
  100% {
    box-shadow: 0 0 0 10px transparent;
  }
}
@media (prefers-reduced-motion: reduce) {
  .insp-passport-flash {
    animation: none;
  }
}
.insp-passport-btn:hover {
  color: var(--accent);
  border-color: var(--accent);
}
/* Индикатор связи рубашка↔лицо (Фаза 4): слой лица следует за рубашкой */
.face-link {
  margin: 6px 0 10px;
  padding: 9px 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border));
  border-left-width: 3px;
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
}
.face-link-head {
  display: flex;
  gap: 7px;
  align-items: flex-start;
}
.face-link-head svg {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--accent);
}
.face-link-txt {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  line-height: var(--lh-normal);
}
.face-link-detach {
  margin-top: 8px;
  padding: 4px 11px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.face-link-detach:hover {
  border-color: var(--accent);
  color: var(--accent);
}
/* Массовый сброс локальных правок колоды (двухступенчатый) */
.edit-scope-reset-all {
  width: 100%;
  margin-top: 8px;
  padding: 7px 10px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  background: var(--bg-secondary);
  border: 1px dashed var(--border-light);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.edit-scope-reset-all:hover {
  border-color: var(--text-muted);
  color: var(--text-primary);
}
.edit-scope-reset-all.armed {
  color: var(--warning);
  border-style: solid;
  border-color: color-mix(in srgb, var(--warning) 65%, transparent);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
}
/* Взведённый пункт меню распространения: у карт набора есть свои правки — второй клик
   их заменит. Тот же токен --warning, что и у .edit-scope-reset-all.armed. */
.prop-menu .theme-menu-item.armed {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warning) 55%, transparent);
}
.edit-scope-seg {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.edit-scope-pill {
  flex: 1 1 auto;
  /* E-309: после подъёма шрифтовой шкалы плашка охвата раздулась до 237 px — БОЛЬШЕ, чем сам
     список слоёв (155 px на 1280×720): семь пилюль перестали помещаться и расползлись на
     четыре строки. Плашка — вспомогательный контрол выбора, съедать треть панели ей нечем.
     Уменьшаем ВЫСОТУ и отступы, а не шрифт: читаемость подписей мы только что и чинили. */
  min-height: 26px;
  padding: 3px 7px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.edit-scope-pill:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.edit-scope-pill.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #0e1116;
}
html[data-theme='light'] .edit-scope-pill.active {
  color: #fff;
}
.edit-scope-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  margin-top: 5px; /* E-309: было 7 */
  min-height: 30px; /* E-309: было 34 */
  padding: 4px 10px;
  border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--border));
  border-radius: var(--radius-md);
  background: var(--accent-dim);
  color: var(--accent);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.edit-scope-pick svg {
  width: 14px;
  height: 14px;
}
.edit-scope-pick:hover,
.edit-scope-pick.active {
  border-style: solid;
  border-color: var(--accent);
}
.edit-scope-cur {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
}
.edit-scope-cur .esc-chip {
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--accent);
}
.edit-scope-cur .esc-reset {
  font-size: var(--fs-3xs);
  color: var(--text-muted);
  background: none;
  border: none;
  cursor: pointer;
  white-space: nowrap;
}
.edit-scope-cur .esc-reset:hover {
  color: var(--text-primary);
}
/* Поповер «Выбрать карты…» — сетка ранг×масть */
.scope-picker {
  padding: 10px;
  min-width: 214px;
}
.scope-grid {
  display: grid;
  grid-template-columns: 26px repeat(4, 1fr);
  gap: 3px;
}
.scope-head,
.scope-rank {
  border: none;
  background: none;
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  cursor: pointer;
  padding: 3px;
}
.scope-head {
  font-size: 14px;
}
.scope-head.red {
  color: var(--error);
}
.scope-head:hover,
.scope-rank:hover {
  color: var(--accent);
}
.scope-cell {
  height: 24px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg-secondary);
  cursor: pointer;
  transition:
    background 0.12s ease,
    border-color 0.12s ease;
}
.scope-cell.red {
  border-color: color-mix(in srgb, var(--error) 22%, var(--border));
}
.scope-cell:hover {
  border-color: var(--accent);
}
.scope-cell.on {
  background: var(--accent);
  border-color: var(--accent);
}
.scope-cell.on.red {
  background: var(--error);
  border-color: var(--error);
}
/* карты нет в колоде (путь Б: удалена по одной) — клетка погашена и не выбирается */
.scope-cell.absent,
.scope-cell.absent:hover {
  background: transparent;
  border-style: dashed;
  border-color: var(--border);
  opacity: 0.35;
  cursor: not-allowed;
}
.scope-foot {
  display: flex;
  gap: 6px;
  margin-top: 10px;
}
.scope-btn {
  flex: 1;
  min-height: 32px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
}
.scope-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.scope-btn.scope-done {
  background: var(--accent);
  border-color: var(--accent);
  color: #0e1116;
}
html[data-theme='light'] .scope-btn.scope-done {
  color: #fff;
}
.deck-regen {
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px dashed color-mix(in srgb, var(--border) 80%, transparent);
}
.deck-regen-title {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* E-308: та же причина, что у .scope-head-lab — светлая подложка блока роняла контраст
     --text-muted до 4.40. См. пояснение там. */
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.deck-regen-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
/* E-325: «Обновить только» свёрнут по умолчанию — вторичное действие не должно занимать
   место постоянно. Заголовок стал кнопкой: он и подпись, и переключатель. */
.deck-regen-title {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 0;
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
}
/* Та же строка-раскрывашка, что у точной настройки CMYK: рельеф под курсором, открытая
   вдавлена. Заголовок здесь И подпись, и переключатель (E-325), поэтому в покое он остаётся
   надписью — выдавленность обещала бы кнопку там, где её ещё не искали. */
.deck-regen-title {
  border-radius: var(--nm-radius);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.deck-regen-title:hover {
  color: var(--text-primary);
  box-shadow: var(--nm-out-xs);
}
.deck-regen-title[aria-expanded='true'],
.deck-regen-title.open {
  box-shadow: var(--nm-in-sm);
}
.deck-regen-title:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
.deck-regen-title .drt-chev {
  margin-left: auto;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
.deck-regen.is-collapsed .deck-regen-title {
  margin-bottom: 0;
}
.deck-regen.is-collapsed .deck-regen-title .drt-chev {
  transform: rotate(-90deg);
}
.deck-regen.is-collapsed .deck-regen-row {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .deck-regen-title .drt-chev {
    transition: none;
  }
}
.deck-regen-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 34px;
  padding: 5px 9px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    color 0.16s ease,
    background 0.16s ease,
    transform 0.16s ease;
}
.deck-regen-chip .drc-ico {
  display: inline-flex;
  width: 14px;
  height: 14px;
  color: var(--text-muted);
  transition: color 0.16s ease;
}
.deck-regen-chip .drc-ico svg {
  width: 100%;
  height: 100%;
}
.deck-regen-chip:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-dim);
  transform: translateY(-1px);
}
.deck-regen-chip:hover .drc-ico {
  color: var(--accent);
}
.deck-regen-chip:active {
  transform: translateY(0) scale(0.96);
}
.deck-regen-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
  .deck-regen-chip {
    transition: none;
  }
  .deck-regen-chip:hover {
    transform: none;
  }
}

/* Аккордеон «Слои»: клик по заголовку сворачивает/разворачивает список слоёв. */
#panel-layers-region > .region-header {
  cursor: pointer;
  user-select: none;
}
#panel-layers-region > .region-header:hover {
  color: var(--text-primary);
}
.region-header .rh-caret {
  flex: 0 0 auto;
  margin-left: auto;
  opacity: 0.7;
  transition: transform 0.2s ease;
}
#panel-layers-region.collapsed .region-header .rh-caret {
  transform: rotate(-90deg);
}
#panel-layers-region.collapsed #tab-layers,
#panel-layers-region.collapsed #tab-face-layers,
#panel-layers-region.collapsed #face-card-picker {
  display: none !important;
}
.region-header {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-shrink: 0;
  padding: 10px 12px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
  /* Дубль правила выше (в файле два одинаковых `.region-header`, выигрывает это). Держим их
     согласованными: заголовок ВЫРЕЗАН в фоне, а не наклеен поверх — он не действие. */
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  border-bottom: none;
}
.region-header svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  color: var(--accent);
}
.panel-layers {
  flex: 1;
  overflow-y: auto;
  padding: var(--sp-2);
}
#panel-resource-region {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* Ресурсные под-вкладки — 4 в ряд */
.panel-tabs.resource-tabs {
  grid-template-columns: repeat(4, 1fr);
}

/* История в модалке (переехала из левой панели в тулбар) */
.history-modal-body {
  overflow-y: auto;
  max-height: 62vh;
  padding: 12px 16px 16px;
}

/* Вкладка «Стили» — галерея пресетов прямо в панели */
.styles-head {
  padding: 4px 4px 10px;
}
.styles-title {
  font-size: var(--fs-base);
  font-weight: 700;
  color: var(--text-primary);
}
.styles-sub {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-top: 3px;
  line-height: 1.4;
}
/* Блок управления галереей: случайный стиль + рероллы по отдельности */
.styles-controls {
  margin: 4px 2px 12px;
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border);
}
.styles-random {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  margin-top: 2px;
}
.styles-random svg {
  flex: 0 0 auto;
}
.styles-facet-lab {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin: 10px 0 4px;
}

.styles-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 10px;
  padding: 2px;
}
#tab-styles .preset-card {
  padding: 6px 6px 2px;
}
#tab-styles .preset-card span {
  font-size: var(--fs-xs);
}
/* Разделитель-заголовок секции «По вашим примерам» (карточки-превью внизу галереи) */
.styles-examples-lab {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 16px 0 6px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-weight: var(--fw-bold);
  color: var(--text-secondary);
}

/* Слои */
.layer-item {
  display: flex;
  align-items: center;
  /* Зазор и боковые поля отданы ИМЕНИ: на 264 px панели строка несёт глаз (34), имя, чип охвата
     (26) и замок (34), и имени оставалось 95 px — «Угловые метки» просили 102 и получали
     многоточие. Ужимать сами кнопки нельзя: 34 px и так ниже нормы цели нажатия. */
  gap: 6px;
  /* ПЛОТНОСТЬ СПИСКА. Было 8px по вертикали — строка выходила 52 px, а слоёв у лица
     двенадцать: список требовал 623 px при 615 доступных и отбирал место у региона действий
     (он сжимается по flex: 0 1 auto ровно на общую нехватку). Из-за этого «Знак заказчика»
     и генерация колоды не помещались вместе — жалоба заказчика 2026-08-17.

     5px даёт 46 px строки и 72 px на двенадцати слоях. Ниже не ужимать: высоту держит не
     padding, а кнопка «глаза» 34×34 внутри — уменьшать её значило бы бить по цели нажатия,
     она и так ниже нормы (44 по Apple HIG). Место надо искать в другом месте, а не здесь. */
  padding: 5px 8px;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background 0.15s;
  margin-bottom: 2px;
}

.layer-item:hover {
  background: var(--bg-hover);
}

.layer-item.active {
  background: var(--accent-dim);
  border: 1px solid rgba(106, 184, 238, 0.25);
}

.layer-visibility,
.layer-lock {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-sm);
  border-radius: var(--radius-sm);
  transition: all 0.15s;
  opacity: 0.5;
}

/* ЗНАЧКИ СТРОКИ — ВЫРЕЗАННЫЕ ГНЁЗДА, А НЕ ВТОРЫЕ ПУЗЫРИ.
   Строка уже выдавлена из фона; выдавить на ней ещё и четыре кнопки значило бы поставить
   «пузырь на пузыре» — в неоморфизме так не делают, потому что источник света один и второй
   выступ читается как грязь. Управляющий элемент НА выступе принято ВРЕЗАТЬ: получается
   гнездо, из которого смотрит значок. Наведение поднимает его до вровень с плашкой, нажатие
   утапливает глубже. */
.layer-visibility,
.layer-lock,
.layer-scope,
.layer-shelf-remove {
  border-radius: var(--nm-radius);
  box-shadow: var(--nm-in);
  transition:
    box-shadow var(--nm-ease),
    opacity 0.15s ease;
}
.layer-visibility:hover,
.layer-lock:hover,
.layer-scope:hover,
.layer-shelf-remove:hover {
  opacity: 1;
  background: transparent;
  box-shadow: var(--nm-out-sm);
}
.layer-visibility:active,
.layer-lock:active,
.layer-scope:active,
.layer-shelf-remove:active {
  box-shadow: var(--nm-in);
}

.layer-visibility.active {
  opacity: 1;
}

/* Заблокированный слой — замок виден и подсвечен */
.layer-lock.active {
  opacity: 1;
  color: var(--warning);
}

/* ИМЯ СЛОЯ ГЛАВНЕЕ ЧИПА ОХВАТА (жалоба заказчика 2026-08-13: «левое меню почти не читается»).
   Замер: 3 имени из 13 на рубашке и 7 из 27 на лице были обрезаны, причём «Узор лица» и
   «Рамка лица» схлопывались в НОЛЬ ширины — строка отдавала всё место соседям. Имя слоя это
   его личность: без неё строка не сообщает ничего, тогда как чип охвата остаётся понятным по
   иконке и подсказке. Поэтому имя получает базовую ширину и не сжимается ниже неё, а подпись
   чипа уступает место первой. */
/* ИМЯ СЛОЯ ЧИТАЕТСЯ ЦЕЛИКОМ — ПЕРЕНОСОМ, А НЕ МНОГОТОЧИЕМ (жалоба заказчика 2026-08-21:
   «слой центр карты слева не прочитать — только „Центр к" и дальше продолжение»).
   Ужать соседей оказалось мало: замер после правки .layer-value дал «Центр карты» 79 px при
   нужных 88 — при шести элементах в строке шириной 264 px взять больше неоткуда. Многоточие
   здесь не подача, а потеря: «Центр к…» не отличить от «Центр карты» и «Центр колоды».
   Две строки — предел: третья превратила бы список в текст. Что не влезло и в две, уходит в
   многоточие, а целиком живёт в подсказке строки. */
.layer-name {
  flex: 1 1 auto;
  min-width: 6.5em;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
  white-space: normal;
  line-height: 1.2;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-primary);
}
/* Чип охвата ужимается первым: слово уходит в подсказку, иконка остаётся — факт с экрана не
   исчезает, меняется только подача (решение архитектора: «сжимаем, не удаляем»).
   ЗАМЕР ПОЙМАЛ: первая редакция дала чипу overflow:hidden и min-width:0 — вместе со словом
   схлопнулась и ИКОНКА (ширина 0), то есть чип перестал быть обнаружимым вовсе. */
.layer-item .layer-scope {
  flex: 0 0 auto;
}
/* В СТРОКЕ СЛОЯ у чипа остаётся ИКОНКА, слово уходит в подсказку. Панель шириной 264 px
   делится между глазом, миниатюрой, именем, чипом, свотчем и замком — на слово места нет, и
   платило за него именно имя. Факт не потерян: иконка различает состояния (🌐/▚, 🔗/✎), title
   объясняет словами, а бейдж охвата в инспекторе называет то же самое полностью.
   Контейнерный запрос тут не годится: у строки нет container-type, и правило просто молчало —
   поймано замером, а не чтением кода. */
.layer-item .layer-scope .ls-txt {
  display: none;
}

.layer-item.active .layer-name {
  color: var(--accent);
}

/* Индикатор фольги на слое */
.layer-foil-badge {
  font-size: var(--fs-2xs);
  padding: 2px 6px;
  background: linear-gradient(135deg, #d4a843, #f0d67b, #d4a843);
  color: #1a1a1a;
  border-radius: 10px;
  font-weight: 600;
  letter-spacing: 0.5px;
}

/* Библиотека */
.library-section {
  margin-bottom: var(--sp-4);
}

.library-section h4 {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
  padding: 8px 4px;
}

.library-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}

.library-item {
  aspect-ratio: 1;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  transition: all 0.2s;
  padding: var(--sp-2);
}

.library-item:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  transform: scale(1.05);
}

.library-item:active {
  cursor: grabbing;
  transform: scale(0.95);
}

.library-item svg {
  width: 100%;
  height: 100%;
  color: var(--text-secondary);
}

.library-item:hover svg {
  color: var(--accent);
}

/* Мои файлы — Dropzone */
.dropzone {
  border: 2px dashed var(--border-light);
  border-radius: var(--radius-lg);
  padding: 30px 20px;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s;
  margin-bottom: var(--sp-3);
}

.dropzone:hover,
.dropzone.drag-over {
  border-color: var(--accent);
  background: var(--accent-dim);
}

.dropzone p {
  font-size: var(--fs-base);
  color: var(--text-primary);
  margin: 10px 0 4px;
}

.dropzone small {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* Загруженные файлы */
.uploaded-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.uploaded-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 8px 10px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background 0.15s;
}

.uploaded-item:hover {
  background: var(--bg-hover);
}

.uploaded-item-icon {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-sm);
  background: var(--bg-active);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-md);
}

.uploaded-item-name {
  flex: 1;
  font-size: var(--fs-sm);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.uploaded-item-remove {
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: var(--fs-md);
  color: var(--text-muted);
  transition: all 0.15s;
}

.uploaded-item-remove:hover {
  background: var(--error);
  color: white;
}

/* ===== ЦЕНТРАЛЬНЫЙ ХОЛСТ ===== */
#canvas-area {
  flex: 1;
  position: relative;
  overflow: hidden;
  background: var(--bg-primary);
  /* Сетка точек как в Figma */
  background-image: radial-gradient(circle, var(--border) 0.5px, transparent 0.5px);
  background-size: 24px 24px;
}

#main-canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* Тень вокруг карты для ощущения "парящего объекта" */
  box-shadow: var(--shadow-lg);
  border-radius: 2px;
}

/* Слой финиша — несвязанный оверлей над дизайном (геометрия/трансформ синхронятся
   из JS с #main-canvas; обрезка углов через clip-path). Не перехватывает мышь. */
#finish-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transform-origin: center center;
  pointer-events: none;
  border-radius: 2px;
  z-index: 2;
  display: none;
}

/* Линейки */
/* Линейки убраны — холст показывается целиком, без полос по краям. */
.ruler {
  display: none;
}

/* ===== Сноски-ссылки вокруг карты (вид «С полями реза») ===== */
.trim-callouts {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
}
.tc-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.tc-line {
  stroke: var(--accent);
  stroke-width: 1.2;
  fill: none;
  stroke-dasharray: 4 3;
  opacity: 0;
  animation: tcFade 0.5s ease both;
  animation-delay: var(--d, 0ms);
}
.tc-anchor {
  fill: var(--accent);
  opacity: 0;
  animation: tcFade 0.5s ease both;
  animation-delay: var(--d, 0ms);
}
@keyframes tcFade {
  to {
    opacity: 0.6;
  }
}
.tc-chip {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border-radius: 9px;
  /* Сноска висит ПОВЕРХ КАРТЫ, а не на панели: выдавливать не из чего — под ней работа
     пользователя (тот же довод, что у стрелок перелистывания). Остаётся накладкой с тенью. */
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  color: var(--text-primary);
  font-size: var(--fs-xs);
  white-space: nowrap;
  cursor: pointer;
  pointer-events: auto;
  transform: translateY(-50%);
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    box-shadow 0.14s ease;
  animation: tcInR 0.42s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  animation-delay: var(--d, 0ms);
}
.tc-chip.tc-left {
  transform: translate(-100%, -50%);
  animation-name: tcInL;
}
.tc-chip:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
  box-shadow:
    0 0 0 1px var(--accent),
    var(--shadow-lg);
}
.tc-chip .tc-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  flex: 0 0 auto;
}
.tc-chip .tc-name {
  font-weight: 700;
}
.tc-chip .tc-val {
  color: var(--text-secondary);
}
.tc-chip.tc-flash {
  animation: tcFlash 0.5s ease;
}
@keyframes tcInR {
  from {
    opacity: 0;
    transform: translateY(-50%) translateX(12px);
  }
  to {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
  }
}
@keyframes tcInL {
  from {
    opacity: 0;
    transform: translate(-100%, -50%) translateX(-12px);
  }
  to {
    opacity: 1;
    transform: translate(-100%, -50%) translateX(0);
  }
}
@keyframes tcFlash {
  0%,
  100% {
    box-shadow: var(--shadow-lg);
  }
  40% {
    box-shadow:
      0 0 0 3px var(--accent-dim),
      0 0 0 1px var(--accent),
      var(--shadow-lg);
  }
}
/* Спотлайт (затемнение карты вокруг зоны инструмента при наведении на сноску) */
.tc-spot {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity 0.22s ease;
}
.tc-lines {
  z-index: 2;
}
.tc-chip {
  z-index: 3;
}
/* Иконка «что применено» в сноске */
.tc-ico {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border-radius: 4px;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  color: var(--accent);
}
.tc-ico img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.tc-ico.tc-swatch {
  border-radius: 50%;
}
.tc-ico.tc-svg svg {
  width: 12px;
  height: 12px;
}
/* Бейдж доп-эффекта (калейдоскоп/искажение/…) */
.tc-ex {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.2px;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--accent-dim);
  border-radius: 5px;
  padding: 1px 5px;
}
/* ── Контроль печатных зон: бейдж «мм до реза» на сноске ── */
.tc-zone {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.2px;
  border-radius: 5px;
  padding: 1px 5px;
  white-space: nowrap;
}
.tc-zone.tc-z-ok {
  color: var(--success);
  background: color-mix(in srgb, var(--success) 13%, transparent);
}
.tc-zone.tc-z-info {
  color: var(--accent);
  background: var(--accent-dim);
}
.tc-zone.tc-z-warn {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 16%, transparent);
}
.tc-zone.tc-z-danger {
  color: #fff;
  background: var(--error);
}
/* Нарушители: рамка чипа окрашивается, красный ещё и пульсирует (уважая reduced-motion) */
.tc-chip.tc-zwarn {
  border-color: color-mix(in srgb, var(--warning) 65%, transparent);
}
.tc-chip.tc-zdanger {
  border-color: var(--error);
  animation: tc-danger-pulse 1.6s ease-in-out infinite;
}
@keyframes tc-danger-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(231, 76, 60, 0.38);
  }
  50% {
    box-shadow: 0 0 0 5px rgba(231, 76, 60, 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .tc-chip.tc-zdanger {
    animation: none;
  }
}
/* Фокус по наведению: остальные сноски/линии тускнеют, выбранная — ярче */
.trim-callouts.tc-focused .tc-chip:not(.tc-hot) {
  opacity: 0.28;
}
.trim-callouts.tc-focused .tc-line:not(.tc-marching),
.trim-callouts.tc-focused .tc-anchor:not(.tc-hot) {
  opacity: 0.12 !important;
}
.tc-chip.tc-hot {
  border-color: var(--accent);
  box-shadow:
    0 0 0 1px var(--accent),
    var(--shadow-lg);
  z-index: 4;
}
/* Оживший путь сноска→инструмент (бегущие штрихи) */
.tc-line.tc-marching {
  stroke: var(--accent);
  stroke-width: 1.8;
  opacity: 1 !important;
  animation: tcMarch 0.5s linear infinite;
}
@keyframes tcMarch {
  to {
    stroke-dashoffset: -14;
  }
}
.tc-anchor.tc-hot {
  opacity: 1 !important;
  animation: tcPulse 1s ease-in-out infinite;
}
@keyframes tcPulse {
  0%,
  100% {
    r: 5;
  }
  50% {
    r: 7.5;
  }
}
@media (prefers-reduced-motion: reduce) {
  .tc-chip,
  .tc-line,
  .tc-anchor {
    animation: none;
    opacity: 1;
  }
  .tc-line,
  .tc-anchor {
    opacity: 0.6;
  }
  .tc-line.tc-marching,
  .tc-anchor.tc-hot {
    animation: none;
  }
}

#ruler-horizontal {
  top: 0;
  left: 0;
  right: 0;
  height: 20px;
  border-bottom: 1px solid var(--border);
}

#ruler-vertical {
  top: 0;
  left: 0;
  bottom: 0;
  width: 20px;
  border-right: 1px solid var(--border);
}

/* Рамка линии реза (overlay) */
.trim-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 50;
}

.trim-overlay .trim-line {
  position: absolute;
  border: 1px dashed var(--error);
  opacity: 0.6;
}

.trim-overlay .safe-zone {
  position: absolute;
  border: 1px dashed var(--accent);
  opacity: 0.4;
}

/* ===== ПРАВАЯ ПАНЕЛЬ (ИНСПЕКТОР) ===== */
#panel-right {
  width: var(--panel-right-width);
  min-width: var(--panel-right-width);
  background: var(--bg-secondary);
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.panel-title {
  font-size: var(--fs-12-5);
  font-weight: 700;
  letter-spacing: 0.2px;
  color: var(--text-primary);
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--bg-tertiary), var(--bg-secondary));
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
/* ===== СВОРАЧИВАНИЕ ИНСПЕКТОРА (js/18c) =====
   На 1280×720 контактный лист делит ширину между 13 колонками, и плитка ужимается до 50 px —
   рисунок карты не разобрать. Свёрнутая панель отдаёт листу свои 300 px (плитка ~72 px).
   Сама панель не сворачивается никогда: инструмент, прячущийся без спроса, хуже мелкой плитки. */
.inspector-collapse-btn {
  /* Кнопка лежит В ПАНЕЛИ, а не в заголовке: заголовок перезаписывается textContent при каждой
     смене слоя и унёс бы её с собой. Отсюда абсолютное позиционирование. */
  position: absolute;
  top: 11px;
  right: 8px;
  z-index: 2;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  line-height: 1;
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.inspector-collapse-btn:hover {
  background: var(--bg-tertiary);
  color: var(--text-primary);
}
#panel-right.collapsed {
  width: 34px;
  min-width: 34px;
}
/* Точка отсчёта для кнопки. Панель и так overflow:hidden, так что ничего не вылезет. */
#panel-right {
  position: relative;
}
/* Прячем СОДЕРЖИМОЕ, а не панель: кнопка обязана остаться на виду, иначе развернуть обратно
   можно будет только через перезагрузку — классическая ловушка сворачиваемых панелей. */
#panel-right.collapsed #inspector-content {
  display: none;
}
#panel-right.collapsed .panel-title {
  /* Заголовок в свёрнутом виде не нужен, но убрать его display:none нельзя — пропадёт
     высота шапки, и кнопка окажется на пустом месте. Гасим текстом-невидимкой. */
  padding: 13px 5px;
  border-bottom: none;
  /* Заголовок скрываем текстом-невидимкой, а не display:none: так кнопка остаётся внутри
     своего контейнера и не прыгает. */
  font-size: 0;
  gap: 0;
}
#panel-right.collapsed .panel-title::before {
  display: none;
}

.panel-title::before {
  content: '';
  width: 4px;
  height: 16px;
  border-radius: 3px;
  background: var(--accent-grad);
  flex: 0 0 auto;
}

#inspector-content {
  flex: 1;
  overflow-y: auto;
  padding: 12px 16px;
  /* E-340. ЗАПАС ПРОКРУТКИ СНИЗУ. Якорь пересборки (js/08) удерживает нажатый контрол на
     месте, подкручивая панель на разницу, — но только если прокручивать есть куда. Когда
     панель уже в самом верху, а содержимое над контролом укоротилось, удержать его нечем:
     он физически поднимается. Запас снизу даёт якорю ход в обе стороны и заодно позволяет
     дотянуть последнюю секцию до середины экрана, а не читать её у самой кромки. */
  padding-bottom: 45vh;
}

/* Секция инспектора */
.inspector-section {
  margin-bottom: var(--sp-5);
}

/* .inspector-section-title — единое правило ниже (было продублировано). */

/* Ползунки (Слайдеры) */
.slider-group {
  margin-bottom: 14px;
}

.slider-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}

.slider-label-text {
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--text-primary);
}

/* Значение слайдера: степперы −/+ + редактируемое поле (крупный ввод мышью) */
.slider-valwrap {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}
.slider-step {
  width: 26px;
  height: 24px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  touch-action: manipulation;
  transition:
    background 0.12s ease,
    border-color 0.12s ease,
    color 0.12s ease,
    transform 0.08s ease;
}
.slider-step:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--bg-hover);
}
.slider-step:active {
  transform: scale(0.88);
}
.slider-unit {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.slider-label-value {
  width: 46px;
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-primary);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 3px 4px;
  outline: none;
  -moz-appearance: textfield;
  appearance: textfield;
}
.slider-label-value:focus {
  border-color: var(--accent);
}
/* Прячем крошечные нативные стрелки — вместо них крупные степперы */
.slider-label-value::-webkit-outer-spin-button,
.slider-label-value::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Кастомный Range Slider */
input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  background: var(--bg-active);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg-secondary);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  transition: transform 0.1s;
}

input[type='range']::-webkit-slider-thumb:hover {
  transform: scale(1.2);
}

input[type='range']::-webkit-slider-thumb:active {
  transform: scale(1.3);
  background: var(--accent-hover);
}

input[type='range']::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--bg-secondary);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* Warning на ползунке (например, слишком тонкие линии) */
.slider-warning {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--sp-1);
  padding: 4px 8px;
  background: rgba(245, 176, 65, 0.1);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  color: var(--warning);
  line-height: 1.4;
}

.slider-warning-icon {
  flex-shrink: 0;
}

/* Кнопка "Перемешать" */
.btn-randomize {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 9px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: all 0.2s;
}

.btn-randomize:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}

.btn-randomize:active {
  transform: scale(0.97);
}

/* Инспектор цвета */
.color-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.color-preview {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  border: 2px solid var(--border-light);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: border-color 0.2s;
}

.color-preview:hover {
  border-color: var(--accent);
}

/* Двойной свотч (диагональ: RGB vs CMYK) */
.color-preview-split {
  position: absolute;
  inset: 0;
}

.color-preview-split::before,
.color-preview-split::after {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
}

.color-preview-split::before {
  clip-path: polygon(0 0, 100% 0, 0 100%);
  background: var(--color-rgb, #6ab8ee);
}

.color-preview-split::after {
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  background: var(--color-cmyk, #5a9ac7);
}

.color-hex-input {
  flex: 1;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 8px 10px;
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-family: 'Inter', monospace;
  outline: none;
  transition: border-color 0.2s;
}

.color-hex-input:focus {
  border-color: var(--accent);
}

/* Gamut Warning (Цвет вне охвата CMYK) */
.gamut-warning {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: rgba(245, 176, 65, 0.08);
  border: 1px solid rgba(245, 176, 65, 0.2);
  border-radius: var(--radius-md);
  font-size: var(--fs-xs);
  color: var(--warning);
  line-height: 1.4;
  margin-bottom: var(--sp-3);
}

/* Чекбокс фольги */
.foil-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all 0.2s;
}

.foil-toggle:hover {
  border-color: var(--accent);
}

.foil-toggle.active {
  border-color: #d4a843;
  background: rgba(212, 168, 67, 0.08);
}

.foil-checkbox {
  width: 18px;
  height: 18px;
  border-radius: var(--radius-sm);
  border: 2px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
  flex-shrink: 0;
}

.foil-toggle.active .foil-checkbox {
  background: linear-gradient(135deg, #d4a843, #f0d67b);
  border-color: transparent;
}

.foil-checkbox-check {
  color: #1a1a1a;
  font-size: var(--fs-xs);
  font-weight: 700;
  opacity: 0;
  transition: opacity 0.15s;
}

.foil-toggle.active .foil-checkbox-check {
  opacity: 1;
}

.foil-label {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-primary);
}

.foil-label small {
  display: block;
  font-size: var(--fs-2xs);
  font-weight: 400;
  color: var(--text-muted);
  margin-top: 2px;
}

/* ===== МОДАЛЬНОЕ ОКНО ПРЕСЕТОВ ===== */
.modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: modalFadeIn 0.3s ease;
}

@keyframes modalFadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(8px);
}

/* Окно из разметки (пресеты) — тот же материал, что у прочих диалогов (волна 5). Оно старше
   остальных и осталось единственным, где коробка была обведена линией. */
.modal-content {
  position: relative;
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  padding: 34px 36px 30px;
  max-width: 920px;
  width: 92%;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  text-align: center;
  box-shadow: var(--nm-out), var(--shadow-lg);
  animation: modalSlideIn 0.35s ease;
}

@keyframes modalSlideIn {
  from {
    opacity: 0;
    transform: translateY(20px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.modal-close {
  position: absolute;
  top: 12px;
  right: 14px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
  color: var(--text-secondary);
  font-size: var(--fs-md);
  line-height: 1;
  cursor: pointer;
  z-index: 2;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    color var(--nm-ease);
}
.modal-close:hover {
  background: var(--error);
  color: #fff;
  border-color: transparent;
  box-shadow: var(--nm-out-xs);
}
.modal-close:active {
  box-shadow: var(--nm-in-sm);
}
.modal-content h2 {
  font-size: var(--fs-3xl);
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: var(--sp-2);
}

.modal-subtitle {
  font-size: var(--fs-base);
  color: var(--text-secondary);
  margin-bottom: 32px;
}

/* Сетка пресетов (премиальная галерея) */
.preset-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 18px 16px;
  overflow-y: auto;
  padding: 6px 8px 8px;
  margin: 0 -8px;
}

.preset-card {
  position: relative;
  cursor: pointer;
  border-radius: 12px;
  padding: 8px 8px 4px;
  border: 1.5px solid transparent;
  transition:
    transform 0.22s cubic-bezier(0.2, 0.7, 0.2, 1),
    box-shadow 0.22s ease,
    border-color 0.2s ease;
  background: transparent;
}

/* Карточка пресета: в покое лежит плоско (их сетка крупная, и полтора десятка выпуклых плиток
   рядом дали бы рябь), под курсором поднимается рельефом, выбранная — ВДАВЛЕНА: «этот стиль
   уже применён». Литеральная тень заменена токеном. */
.preset-card:hover {
  border-color: transparent;
  transform: translateY(-6px);
  background: var(--nm-surface);
  box-shadow: var(--nm-out);
}

.preset-card:active {
  transform: translateY(-2px) scale(0.98);
}

/* Активный (выбранный) стиль — сильный акцент, как у активного узора */
.preset-card.active {
  border-color: transparent;
  background: var(--nm-groove);
  transform: none;
  box-shadow:
    var(--nm-in),
    inset 0 0 0 1px var(--accent);
}
.preset-card.active .preset-preview {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.preset-card.active span {
  color: var(--accent);
  font-weight: 600;
}
.preset-card.active::after {
  content: '✓';
  position: absolute;
  top: 9px;
  right: 9px;
  z-index: 2;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}

/* Превью в форме реальной карты-рубашки: скругление + тень */
.preset-preview {
  width: 100%;
  aspect-ratio: 63 / 88;
  background: var(--bg-active);
  position: relative;
  overflow: hidden;
  border-radius: 8px;
  box-shadow:
    0 6px 16px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}
.preset-preview canvas,
.preset-preview img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
/* Карта «Чистый холст» */
.preset-preview-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.03) 0 8px, transparent 8px 16px),
    var(--bg-tertiary);
  border: 1.5px dashed var(--border-light);
}
.preset-preview-blank span {
  font-size: var(--fs-4xl);
  font-weight: 300;
  color: var(--text-muted);
  padding: 0;
}
.preset-card:hover .preset-preview-blank span {
  color: var(--accent);
}

/* Визуальные заглушки пресетов (заменятся canvas-рендером) */
.preset-casino {
  background: linear-gradient(135deg, #1a3a5c 0%, #0d2137 100%);
  background-image: repeating-linear-gradient(
    45deg,
    transparent,
    transparent 3px,
    rgba(106, 184, 238, 0.08) 3px,
    rgba(106, 184, 238, 0.08) 4px
  );
}

.preset-royal {
  background: linear-gradient(180deg, #1a0a2e 0%, #0d0519 100%);
  background-image: radial-gradient(
    ellipse at center,
    rgba(212, 168, 67, 0.15) 0%,
    transparent 60%
  );
}

.preset-geometric {
  background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
  background-image:
    linear-gradient(60deg, rgba(106, 184, 238, 0.06) 25%, transparent 25%),
    linear-gradient(-60deg, rgba(106, 184, 238, 0.06) 25%, transparent 25%);
  background-size: 20px 35px;
}

.preset-tarot {
  background: linear-gradient(180deg, #1a0a2e 0%, #2d1045 50%, #1a0a2e 100%);
  background-image: radial-gradient(circle at center, rgba(200, 100, 255, 0.1) 0%, transparent 50%);
}

.preset-card span {
  display: block;
  padding: 10px 8px;
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text-secondary);
  text-align: center;
}

.preset-card:hover span {
  color: var(--accent);
}

/* ===== КАСТОМНЫЕ СКРОЛЛБАРЫ ===== */
::-webkit-scrollbar {
  width: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--bg-active);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* ===== СОВРЕМЕННЫЙ ПОЛИШ (UI v3) ===== */
/* Тулбар — лёгкая глубина и разделение */
#toolbar {
  background: linear-gradient(180deg, var(--bg-secondary), var(--bg-primary));
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.03),
    var(--shadow-sm);
}
.toolbar-divider {
  width: 1px;
  height: 22px;
  background: var(--border);
  margin: 0 6px;
}

/* Кнопки тулбара — мягче и современнее */
.tool-btn {
  height: 36px;
  border: 1px solid transparent;
}
.tool-btn:hover {
  border-color: var(--border-light);
}
.tool-btn.btn-primary {
  background: var(--accent-grad);
  color: #0e1116;
  box-shadow: 0 4px 14px rgba(106, 184, 238, 0.25);
}
.tool-btn.btn-primary:hover {
  filter: brightness(1.06);
  box-shadow: 0 6px 18px rgba(106, 184, 238, 0.35);
}

/* Панели — мягкие границы */
#panel-left {
  border-right: 1px solid var(--border);
  background: var(--bg-secondary);
}
#panel-right {
  border-left: 1px solid var(--border);
  background: var(--bg-secondary);
}

/* Заголовки секций инспектора — единое каноническое правило (слито из дубля) */
.inspector-section-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: 10px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--text-secondary);
}
/* Профессиональный акцент-маркер (вертикальная линия слева) */
.inspector-section-title::before {
  content: '';
  flex: 0 0 auto;
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: var(--sec-accent, var(--accent-grad));
  box-shadow: 0 0 6px var(--accent-dim);
}
/* Иконка слоя в заголовке секции — глиф в акцентном чипе (премиум) */
.inspector-section-title .ist-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-right: 1px;
  border-radius: var(--radius-sm);
  background: var(--accent-dim);
  font-size: var(--fs-sm);
  line-height: 1;
  filter: saturate(1.05);
}
.inspector-section-title .ist-text {
  flex: 1 1 auto;
  min-width: 0;
}
/* Бейдж «вся колода» — единая пометка глобальной (дековой) секции (этап 5 редизайна).
   E-339: бейдж УСТУПАЕТ место названию. Прежде он был неуступчивым (flex:0 0 auto + nowrap),
   а название сжималось — и «Значки масти (пипсы)» ломалось в три строки огрызком «Значки мас
   (пипсы)». Ради названия секцию и открывают; пометка охвата — служебная, ей и уступать.
   Максимум в 45% ширины заголовка: даже самая длинная подпись не съест больше половины. */
.insp-deck-badge {
  /* Не сжимаем и не обрезаем: обрезанная пометка («52 К…») бесполезнее отсутствующей.
     Место названию освободила КОРОТКАЯ формулировка (E-339), а не борьба вёрстки за
     пиксели — 60 px вместо 154 хватило, чтобы заголовок перестал ломаться. */
  flex: 0 0 auto;
  margin-left: auto;
  font-size: var(--fs-3xs); /* E-309: было 10px мимо шкалы */
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2px 7px;
  cursor: help;
  white-space: nowrap;
}
/* Чипы с иконкой-превью (стиль углов и пр.) */
.seg-chip.icon-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 7px 4px;
}
.seg-chip.icon-chip svg {
  width: 22px;
  height: 22px;
  opacity: 0.9;
}
.seg-chip.icon-chip .chip-label {
  font-size: var(--fs-2xs);
}

/* Тумблер CMYK / RGB в тулбаре */
#btn-cmyk {
  border: 1px solid var(--border-light);
  min-width: 64px;
  justify-content: center;
}
#btn-cmyk .btn-label {
  display: inline !important;
  font-weight: 600;
  letter-spacing: 0.03em;
}
#btn-cmyk.active {
  background: var(--accent-dim);
  border-color: rgba(106, 184, 238, 0.5);
  color: var(--accent);
}

/* Слой — активный с акцентной полоской */
/* ═══ СТРОКА СЛОЯ В НЕОМОРФИЗМЕ ══════════════════════════════════════════════════════════
   Строка — плашка, выдавленная из фона; ВЫБРАННАЯ — вдавленная. Прежде выбор показывался
   рамкой и полоской слева: в рельефном интерфейсе это третий язык, и рядом с выдавленными
   кнопками читалось как чужеродная наклейка.
   Акцентная полоска СЛЕВА ОСТАВЛЕНА поверх вдавленности: рельеф в тёмной теме мягок, и без
   неё активная строка опознаётся хуже (то же решение, что у пульса выбора — подчёркивать, а
   не заменять). */
.layer-item {
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    border-color 0.15s ease;
}
.layer-item:hover {
  box-shadow: var(--nm-out);
}
.layer-item.active {
  border-color: transparent;
  background: var(--nm-surface-in);
  box-shadow:
    var(--nm-in),
    inset 2px 0 0 var(--accent);
}

/* Слайдеры — заметный современный ползунок и трек */
input[type='range'] {
  height: 5px;
  background: linear-gradient(90deg, var(--accent-dim), var(--bg-active));
}
input[type='range']::-webkit-slider-thumb {
  width: 16px;
  height: 16px;
  background: var(--accent-grad);
  border: 2px solid var(--bg-secondary);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
}
input[type='range']::-moz-range-thumb {
  width: 16px;
  height: 16px;
  background: #6ab8ee;
  border: 2px solid var(--bg-secondary);
}

/* Тонкий скруглённый скроллбар */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-thumb {
  background: var(--bg-active);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--border-light);
  background-clip: padding-box;
}

/* Холст — мягкая подложка и тень для «премиум» восприятия */
#canvas-area {
  background:
    radial-gradient(circle at 50% 32%, rgba(106, 184, 238, 0.05), transparent 60%),
    var(--bg-primary);
}
#main-canvas {
  box-shadow: var(--shadow-lg);
  border-radius: 2px;
}

/* Плавность интерактивных элементов */
button {
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease,
    transform 0.08s ease,
    filter 0.15s ease;
}
button:active {
  transform: translateY(1px);
}

/* ===== КОМПОНЕНТЫ КОНТРОЛОВ (UI v3) ===== */
/* Сегментированные группы выбора */
.seg {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 6px 0;
}
.seg.equal > .seg-chip {
  flex: 1;
}
.seg.grid2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-bottom: var(--sp-3);
}
.seg.grid2 > .seg-chip {
  flex: none;
}
.seg-chip {
  flex: 1 1 22%;
  min-width: 64px;
  padding: 8px 6px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: 500;
  text-align: center;
  /* Длинные подписи (напр. «Полусмещение») не вылезают за кнопку, а переносятся */
  line-height: 1.25;
  overflow-wrap: break-word;
  word-break: break-word;
  hyphens: auto;
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease,
    box-shadow 0.18s ease,
    transform 0.08s ease;
}
.seg-chip:hover {
  border-color: var(--border-light);
  color: var(--text-primary);
  transform: translateY(-1px);
}
.seg-chip.active {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 700;
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 2px var(--accent),
    0 6px 16px var(--accent-dim);
}
/* То же самое у чипа-сегмента: активность держат рамка и фон, ореол лишний. */
.seg-chip.icon-chip.active svg {
  color: var(--accent);
}
/* Сильный акцент на используемой кнопке-превью: рамка превью + галочка-бейдж */
.seg-chip.has-thumb {
  position: relative;
}
.seg-chip.has-thumb.active .chip-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.seg-chip.has-thumb.active::after {
  content: '✓';
  position: absolute;
  top: 7px;
  right: 7px;
  width: 19px;
  height: 19px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
}
/* Компактная подпись над плашкой цвета */
.color-caption {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-secondary);
  margin: 2px 0 5px;
}

/* ===== Закреплённая панель цветов слоя (всегда на виду при прокрутке) ===== */
.pattern-colorbar {
  position: sticky;
  top: 0;
  z-index: 6;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
  /* тянемся на всю ширину инспектора и гасим его верхний паддинг */
  margin: -12px -16px 10px;
  padding: 10px 16px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.pattern-colorbar.single {
  grid-template-columns: 1fr;
}
/* НЕЛИПКАЯ панель цветов (инспектор УЗОРА): едет вместе с содержимым и лежит внутри
   тела своей секции «🎨 Цвет узора». Гасим всё, что делало её «крышкой» инспектора:
   прилипание, вылет за паддинги панели, полосу-фон и размытие под ней. */
.pattern-colorbar.inline {
  position: static;
  top: auto;
  z-index: auto;
  margin: 0 0 8px;
  padding: 0;
  background: none;
  border-bottom: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.pcolor-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  padding: 7px 9px;
  /* Рамку снимаем: в неоморфизме границу рисует РЕЛЬЕФ, и линия рядом с ним читается как
     второй контур — тот самый «наклеенный прямоугольник», от которого уходим. */
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  cursor: pointer;
  text-align: left;
  transition:
    border-color 0.14s ease,
    background 0.14s ease,
    box-shadow 0.14s ease;
}
.pcolor-chip:hover {
  border-color: var(--border-light);
  background: var(--bg-hover);
}
.pcolor-chip.active {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.pcolor-sw {
  position: relative;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  border-radius: 7px;
  overflow: hidden;
  border: 1px solid var(--border-light);
}
.pcolor-txt {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.pcolor-txt strong {
  font-size: var(--fs-11-5);
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.2;
  /* ПОДПИСЬ НЕ ВЫЛЕЗАЕТ ЗА СВОЙ ЧИП. Жалоба заказчика 2026-08-25: «подписи цветов узора выходят
     за свои границы блока». Замер: «Основной цвет» — 67 px текста в контейнере шириной 47.
     У обёртки min-width:0 стоял, а вот самому тексту сжиматься было нечем — он просто
     выезжал наружу. Полное имя остаётся в подсказке чипа, так что смысл не теряется. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pcolor-txt small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-10-5);
  color: var(--text-muted);
  font-family: 'Inter', monospace;
  letter-spacing: 0.02em;
}
/* Плавающий редактор цвета — привязан к чипу (виден при любой прокрутке) */
.pcolor-pop {
  position: fixed;
  z-index: 500;
  width: 274px;
  max-width: calc(100vw - 16px);
  max-height: 74vh;
  overflow-y: auto;
  padding: 12px 14px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  animation: mo-fade-up 0.16s ease both;
}
.seg-chip.sm {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-2xs);
  padding: 6px 4px;
}
/* Чип с мини-превью узора */
.seg-chip.has-thumb {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
  padding: 5px;
}
.chip-thumb {
  width: 100%;
  height: 42px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: #f4f1ea;
  display: block;
}
.seg-chip.has-thumb .chip-label {
  line-height: 1.15;
}

/* Спец-плитка «источников» (Из иконки/Из логотипа/AI-узор) — намеренно НЕ похожа
   на «бумажные» превью узоров: тёмная акцентная плитка с иконочным символом. */
.chip-thumb.chip-special {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 42px;
  width: 100%;
  border-radius: 4px;
  border: 1px solid var(--border-light);
  background: linear-gradient(135deg, var(--accent-dim), transparent 72%), var(--bg-active);
  color: var(--accent);
}
.chip-thumb.chip-special svg {
  width: 26px;
  height: 26px;
}
/* Подпись спец-кнопок — акцентная (сигнал «это генератор/источник») */
.seg-chip.chip-source .chip-label {
  color: var(--accent);
  font-weight: 600;
}
.seg-chip.chip-source:hover .chip-thumb.chip-special {
  border-color: var(--accent);
  background: linear-gradient(135deg, var(--accent-dim), transparent 60%), var(--bg-hover);
}
/* Активный спец-чип: плитка залита акцентом, символ контрастный */
.seg-chip.chip-source.active .chip-thumb.chip-special {
  background: var(--accent-grad, var(--accent));
  border-color: transparent;
  color: #fff;
}

/* Разделитель */
.divider {
  height: 1px;
  background: var(--border);
  margin: 16px 0;
}

/* Тумблер */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 0;
  margin-bottom: var(--sp-2);
}
.toggle-row .toggle-label {
  font-size: var(--fs-sm);
  color: var(--text-primary);
}
/* МЯГКИЙ РЕЛЬЕФ (волна 2). Дорожка — КАНАВКА, вырезанная в поверхности; ручка — единственное,
   что из неё выступает. Тот же язык, что у гнёзд строки слоя: при одном источнике света выступ
   на выступе читается как грязь, а тумблер — ровно случай «ручка ездит в пазу».
   Состояние «вкл» держится НЕ рельефом: в тёмной теме он мягок, и одна вдавленность на 40×22 px
   неразличима. Заливка канавки акцентом остаётся — рельеф добавляет пластику, а не заменяет
   признак. Тени берутся токенами: литерал увёл бы ручку в грязь на светлой теме. */
.toggle {
  width: 40px;
  height: 22px;
  border-radius: 11px;
  background: var(--nm-groove, var(--nm-surface-in));
  box-shadow: var(--nm-in-sm);
  cursor: pointer;
  position: relative;
  transition:
    background var(--nm-ease),
    box-shadow var(--nm-ease);
  flex: 0 0 auto;
}
.toggle .toggle-knob {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--nm-knob, #fff);
  position: absolute;
  top: 3px;
  left: 3px;
  transition: left 0.2s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: var(--nm-out-xs);
}
.toggle:hover .toggle-knob {
  background: #fff;
}
.toggle.on {
  background: linear-gradient(145deg, var(--accent), var(--accent-2, var(--accent)));
  box-shadow: var(--nm-in-sm);
}
.toggle.on .toggle-knob {
  left: 21px;
}
.toggle:active .toggle-knob {
  box-shadow: var(--nm-out-xs-press, var(--nm-out-xs));
}

/* Аккордеон-секции инспектора */
/* ── Премиум-аккордеон: группы инструментов с явными «осязаемыми» шапками ── */
.acc-header {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 9px;
  user-select: none;
  margin: 13px 0 0;
  padding: 9px 11px;
  border-radius: 9px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.022));
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-size: var(--fs-11-5);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
  transition:
    background 0.16s ease,
    border-color 0.16s ease,
    box-shadow 0.16s ease;
}
.acc-tools + .acc-header {
  margin-top: 2px;
}
.acc-header:hover {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.035));
  border-color: rgba(255, 255, 255, 0.18);
}
.acc-header:not(.collapsed) {
  border-bottom-color: transparent;
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.acc-header.collapsed {
  background: rgba(255, 255, 255, 0.022);
}
/* Крупный акцент-маркер группы */
.acc-header::before {
  content: '';
  flex: 0 0 auto;
  width: 3px;
  height: 14px;
  border-radius: 2px;
  background: var(--accent-grad, var(--accent));
}
/* Каретка-шеврон (CSS, без глифов) */
.acc-header::after {
  content: '';
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-left: auto;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.2s ease;
}
.acc-header:hover::after {
  border-color: var(--text-secondary);
}
.acc-header.collapsed::after {
  transform: translateY(0) rotate(-45deg);
}
.acc-body {
  padding: 12px 11px;
  margin-bottom: var(--sp-1);
  background: rgba(255, 255, 255, 0.028);
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 9px 9px;
  animation: accReveal 0.18s ease;
}
/* Сетка выбора узора — ограниченная по высоте со скроллом, чтобы параметры
   узора не «уезжали» далеко вниз. */
.pattern-type-grid {
  max-height: 320px;
  overflow-y: auto;
  padding-right: var(--sp-1);
  margin-bottom: var(--sp-1);
}
/* Блок ИСТОЧНИКОВ узора (иконка/логотип/AI) — 3 колонки, крупнее, акцентная рамка */
.pattern-source-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin-bottom: var(--sp-2);
}
.pattern-source-grid .seg-chip {
  border-color: color-mix(in srgb, var(--accent) 32%, var(--border));
  background: var(--accent-dim);
}
.pattern-source-grid .seg-chip:hover {
  border-color: var(--accent);
}
.pattern-source-grid .chip-thumb.chip-special {
  color: var(--accent);
}
.pattern-type-grid::-webkit-scrollbar {
  width: 8px;
}
.pattern-type-grid::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 6px;
}
.pattern-type-grid::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.22);
}
.acc-body.collapsed {
  display: none;
}
@keyframes accReveal {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* AI-генератор арта */
.ai-gen {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-tertiary);
  padding: var(--sp-3);
  margin-bottom: 14px;
}
.ai-gen h4 {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  margin: 0 0 8px;
  font-weight: 600;
}
.ai-input {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-primary);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  font-family: inherit;
  padding: 7px 9px;
  resize: vertical;
}
.ai-input:focus {
  outline: none;
  border-color: var(--accent);
}
.ai-row {
  display: flex;
  gap: 6px;
  margin-top: var(--sp-2);
}
.ai-seed {
  flex: 1;
}
/* .btn-soft.ai-dice — специфичность выше базовой .btn-soft (width:100%),
   поэтому кнопка-кубик остаётся компактной независимо от порядка правил */
.btn-soft.ai-dice {
  width: auto;
  margin: 0;
  flex: 0 0 auto;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Убираем бессмысленные спиннер-стрелки у поля «Сид» */
.ai-seed::-webkit-outer-spin-button,
.ai-seed::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.ai-seed {
  -moz-appearance: textfield;
  appearance: textfield;
}
.ai-seed-label {
  flex: 0 0 auto;
  align-self: center;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
/* ЕДИНАЯ схема action-кнопок (Случайный стиль / Случайная палитра / Случайная
   вариация / Сгенерировать …): accent-градиент, иконка + подпись по центру. */
.ai-gen-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  width: 100%;
  margin-top: var(--sp-2);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: none;
  background: var(--accent-grad);
  color: #0e1116;
  font-weight: 600;
  font-size: var(--fs-base);
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(106, 184, 238, 0.22);
  transition:
    filter 0.15s ease,
    box-shadow 0.16s ease,
    transform 0.12s ease;
}
.ai-gen-btn svg {
  flex: 0 0 auto;
}
.ai-gen-btn:hover {
  filter: brightness(1.07);
  box-shadow: 0 6px 20px rgba(106, 184, 238, 0.3);
}
.ai-gen-btn:active {
  transform: translateY(1px) scale(0.99);
}
.ai-gen-btn:disabled {
  opacity: 0.6;
  cursor: default;
  box-shadow: none;
}
.ai-status {
  font-size: var(--fs-xs);
  margin-top: var(--sp-2);
  min-height: 14px;
  color: var(--text-muted);
}
.ai-status.ok {
  color: var(--success);
}
.ai-status.err {
  color: var(--error);
}
.ai-status.load {
  color: var(--accent);
}
.ai-hint {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  line-height: 1.5;
  margin: 8px 0 0;
}

/* ===== АНИМИРОВАННЫЙ ЛОАДЕР AI-ГЕНЕРАЦИИ ===== */
.ai-loader-overlay {
  position: fixed;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 14px;
  overflow: hidden;
  background: rgba(10, 16, 26, 0.62);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  animation: ai-fade 0.25s ease;
}
.ai-loader-overlay.hidden {
  display: none;
}
/* бегущий блик по всей зоне */
.ai-loader-overlay::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    110deg,
    transparent 35%,
    rgba(255, 255, 255, 0.09) 50%,
    transparent 65%
  );
  transform: translateX(-100%);
  animation: ai-shimmer 1.7s ease-in-out infinite;
}
.ai-loader-card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: 18px 22px;
  text-align: center;
}
.ai-loader-ring {
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    transparent 0%,
    var(--accent, #6ab8ee) 85%,
    transparent 100%
  );
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 0);
  mask: radial-gradient(farthest-side, transparent calc(100% - 5px), #000 0);
  animation: ai-spin 0.9s linear infinite;
}
.ai-loader-suits {
  font-size: var(--fs-xl);
  letter-spacing: 7px;
  color: var(--accent, #6ab8ee);
  text-indent: 7px;
  animation: ai-pulse 1.5s ease-in-out infinite;
}
.ai-loader-text {
  color: #eef3f9;
  font-size: var(--fs-base);
  font-weight: 600;
  letter-spacing: 0.3px;
}
.ai-loader-text::after {
  content: '';
  animation: ai-dots 1.4s steps(4, end) infinite;
}
.ai-loader-sub {
  color: rgba(235, 240, 248, 0.62);
  font-size: var(--fs-xs);
  max-width: 220px;
  line-height: 1.4;
}
@keyframes ai-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes ai-shimmer {
  to {
    transform: translateX(100%);
  }
}
@keyframes ai-pulse {
  0%,
  100% {
    opacity: 0.45;
    transform: scale(0.96);
  }
  50% {
    opacity: 1;
    transform: scale(1.04);
  }
}
@keyframes ai-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes ai-dots {
  0% {
    content: '';
  }
  25% {
    content: '.';
  }
  50% {
    content: '..';
  }
  75% {
    content: '...';
  }
}

/* Переключатель карт (рубашка / тузы / джокер) */
/* Переключатель сторон карты — первичный сегмент в тулбаре (UX-аудит C1) */
#card-switcher {
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 3px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.card-tab {
  padding: 9px 14px;
  min-height: 40px;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  font-weight: 500;
  cursor: pointer;
}
.card-tab:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}
.card-tab.active {
  background: var(--accent-dim);
  color: var(--accent);
  border-color: var(--accent);
}

/* Drag-сортировка слоёв */
.layer-item[draggable='true'] {
  cursor: grab;
}
.layer-item.dragging {
  opacity: 0.45;
  cursor: grabbing;
  border-color: var(--accent) !important;
}

/* Иконка-подсказки рядом с параметром */
.hint-info {
  display: inline-block;
  margin-left: 5px;
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  cursor: help;
  opacity: 0.7;
}
.hint-info:hover {
  color: var(--accent);
  opacity: 1;
}

/* Панель управления секциями */
.acc-tools {
  display: flex;
  gap: 6px;
  margin-bottom: 10px;
}
.acc-tool {
  flex: 1;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-muted);
  font-size: var(--fs-10-5);
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.acc-tool:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}

/* Поиск по узорам */
.type-search {
  width: 100%;
  margin-bottom: var(--sp-2);
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-family: inherit;
}
.type-search:focus {
  outline: none;
  border-color: var(--accent);
}
.type-search::placeholder {
  color: var(--text-muted);
}

/* Встроенная сетка выбора иконок в инспекторе (узор «Из иконки») */
.inline-iconpicker {
  margin: 6px 0 10px;
}
.inline-icon-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  max-height: 236px;
  overflow-y: auto;
  margin-top: 6px;
  padding: 2px;
}
.inline-icon-grid .library-item {
  aspect-ratio: 1;
  padding: 6px;
  position: relative;
}
/* E-331. Подвал сетки иконок: счётчик и «Показать ещё». ВНЕ прокручиваемой сетки — кнопка
   подгрузки, уехавшая вместе со списком, не находится именно тогда, когда нужна. */
/* Столбцом, кнопка во всю ширину: инспектор узкий (~240 px), и в строку кнопка обрезалась
   до «Показат…». Так же устроена подгрузка в библиотеке левой панели — один приём на оба
   входа в один и тот же набор иконок. */
.inline-icon-more {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 6px;
}
.inline-icon-more:empty {
  display: none;
}
.inline-icon-more .mgr-count {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  text-align: center;
}
.inline-icon-more-btn {
  width: 100%;
  padding: 5px 8px;
  font-size: var(--fs-2xs);
}
.inline-icon-grid .library-item.active {
  border-color: var(--accent);
  background: var(--accent-dim);
  transform: translateY(-1px);
  box-shadow:
    inset 0 0 0 2px var(--accent),
    0 4px 12px var(--accent-dim);
}
/* Галочка-бейдж на выбранной иконке — сразу видно, какая выбрана. */
.inline-icon-grid .library-item.active::after {
  content: '✓';
  position: absolute;
  top: 2px;
  right: 3px;
  width: 13px;
  height: 13px;
  line-height: 13px;
  text-align: center;
  font-size: var(--fs-3xs);
  font-weight: 800;
  color: #0e1116;
  background: var(--accent);
  border-radius: 50%;
}
.inline-icon-grid .library-item.active svg {
  color: var(--accent);
}
.inline-icon-grid .mgr-empty,
.inline-icon-grid .mgr-count {
  grid-column: 1 / -1;
}

/* Список палитр */
/* Премиум-сетка палитр: 2 колонки, свотч-карточки с подъёмом при наведении (редизайн) */
.palette-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin: 8px 0 4px;
}
.palette-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 8px;
  border-radius: var(--nm-radius);
  /* Мягкий рельеф (волна 2): плитка ВЫДАВЛЕНА из панели, как карточка узора в инспекторе.
     Рамку в пиксель заменяет тень, но габарит держит прозрачный border — иначе плитки
     разъезжались бы на каждое наведение (урок inspector-no-jump). */
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  cursor: pointer;
  transition:
    transform 0.16s ease,
    border-color 0.16s ease,
    box-shadow 0.16s ease;
}
.palette-item:hover {
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: var(--nm-out);
}
/* Активная (выбранная) палитра — ВДАВЛЕНА: «эта уже применена, нажимать больше нечего».
   Акцентное кольцо и ✓ остаются — рельеф в тёмной теме мягок, и на плитке 2×N одной
   вдавленности мало, чтобы найти выбранную глазом. */
.palette-item.active {
  border-color: transparent;
  background: var(--accent-dim);
  box-shadow:
    var(--nm-in),
    inset 0 0 0 1px var(--accent);
  transform: none;
}
.palette-item.active .palette-name {
  color: var(--accent);
  font-weight: 600;
}
.palette-item.active::after {
  content: '✓';
  position: absolute;
  top: 6px;
  right: 6px;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  font-size: var(--fs-xs);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
  animation: pal-badge-pop 0.32s cubic-bezier(0.2, 1.3, 0.4, 1);
}
@keyframes pal-badge-pop {
  from {
    transform: scale(0);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}
/* Короткий пульс-акцент при выборе (вместо исчезновения/появления списка) */
.palette-item.pal-flash {
  animation: pal-flash 0.5s ease-out;
}
@keyframes pal-flash {
  0% {
    box-shadow:
      inset 0 0 0 1px var(--accent),
      0 0 0 1px var(--accent);
  }
  100% {
    box-shadow:
      inset 0 0 0 1px var(--accent),
      0 0 0 9px transparent;
  }
}
@media (prefers-reduced-motion: reduce) {
  .palette-item.active::after,
  .palette-item.pal-flash {
    animation: none;
  }
}
.palette-swatch {
  flex: 0 0 auto;
  width: 100%;
  height: 36px;
  border-radius: 6px;
  border: 1px solid rgba(0, 0, 0, 0.22);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.palette-name {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  text-align: center;
  line-height: 1.25;
  min-height: 2.4em;
  display: flex;
  align-items: center;
  justify-content: center;
}
.palette-item:hover .palette-name {
  color: var(--text-primary);
}

/* Мягкая кнопка действия */
.btn-soft {
  width: 100%;
  margin-top: var(--sp-2);
  padding: 9px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-sm);
}
.btn-soft:hover {
  border-color: var(--border-light);
  color: var(--text-primary);
}
/* Кнопка мультизагрузки фото на набор карт (P1 Персоны Б): акцент через токены —
   выделяет главное действие «пачка фото на выбранные», не ломая светлую тему. */
.btn-soft.face-batch-upload {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}
.btn-soft.face-batch-upload:hover {
  background: var(--accent-dim);
  color: var(--accent);
}

/* ===== АДАПТИВНОСТЬ (Планшеты) ===== */
@media (max-width: 1100px) {
  :root {
    --panel-left-width: 220px;
    --panel-right-width: 240px;
  }
  .preset-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Мобильные элементы скрыты на десктопе */
.mobile-only {
  display: none;
}
#mobile-backdrop {
  display: none;
}

@media (max-width: 768px) {
  /* Кнопки-переключатели панелей видны */
  .mobile-only {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 8px;
  }
  /* Логотип компактный, центр-тулбар прокручивается по горизонтали */
  .logo-text {
    display: none;
  }
  .logo {
    padding-right: var(--sp-2);
  }
  #toolbar {
    padding: 0 8px;
    gap: var(--sp-1);
  }
  .toolbar-center {
    position: static;
    transform: none;
    overflow-x: auto;
    flex: 1;
    justify-content: flex-start;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .toolbar-center::-webkit-scrollbar {
    display: none;
  }
  .tool-btn .btn-label {
    display: none;
  }
  #btn-download .btn-label {
    display: inline;
  }

  /* Панели → выезжающие drawer-панели поверх холста */
  #panel-left,
  #panel-right {
    position: fixed;
    top: var(--toolbar-height);
    bottom: 0;
    z-index: 200;
    width: 86vw;
    max-width: 340px;
    min-width: 0;
    display: flex;
    box-shadow: var(--shadow-lg);
    transition: transform 0.26s ease;
    will-change: transform;
  }
  #panel-left {
    left: 0;
    transform: translateX(-102%);
  }
  #panel-right {
    right: 0;
    transform: translateX(102%);
  }
  #panel-left.open,
  #panel-right.open {
    transform: translateX(0);
  }

  /* Затемнение под открытой панелью */
  #mobile-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    top: var(--toolbar-height);
    z-index: 150;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.26s ease;
  }
  #mobile-backdrop.show {
    opacity: 1;
    pointer-events: auto;
  }

  /* Холст занимает всю ширину */
  #canvas-area {
    width: 100%;
  }

  .preset-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }
  .modal-content {
    padding: var(--sp-6);
  }
}

@media (max-width: 420px) {
  #panel-left,
  #panel-right {
    width: 92vw;
  }
}

/* ЧАСТЬ 2Б: КОНЕЦ — Левая панель, Холст, Правая панель, Модалка пресетов */

/* ============================================================
   ПАНЕЛЬ «ГОТОВЫЙ ВИД» (эскиз финишной карты: обрезка + 3D)
   ============================================================ */
#finish-preview {
  position: absolute;
  right: 16px;
  bottom: 16px;
  z-index: 30;
  width: 150px;
  padding: 8px 8px 4px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  border-radius: 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  backdrop-filter: blur(12px) saturate(1.2);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  user-select: none;
  animation: fp-in 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}
#finish-preview.hidden {
  display: none;
}
@keyframes fp-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.96);
  }
}
.fp-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
.fp-title {
  flex: 1;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-secondary);
  white-space: nowrap;
}
.fp-modes {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 7px;
  background: var(--bg-tertiary);
}
.fp-mode {
  padding: 2px 7px;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    background 0.15s,
    color 0.15s;
}
.fp-mode:hover {
  color: var(--text-primary);
}
.fp-mode.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.fp-close {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 5px;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition:
    background 0.15s,
    color 0.15s;
}
.fp-close:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.fp-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 8px 16px;
  perspective: 760px;
}
.fp-card {
  position: relative;
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  transform-style: preserve-3d;
  will-change: transform;
}
.fp-card canvas {
  display: block;
  border-radius: 7px;
  box-shadow:
    0 6px 16px rgba(0, 0, 0, 0.4),
    0 1px 3px rgba(0, 0, 0, 0.3);
  transition: box-shadow 0.5s ease;
}
/* Блик-развёртка поверх карты (проявляется в 3D) */
.fp-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 7px;
  pointer-events: none;
  background: linear-gradient(120deg, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0) 46%);
  opacity: 0;
  transition: opacity 0.5s ease;
}
/* --- Режим 3D: наклон + направленная тень + блик --- */
#finish-preview.fp-3d .fp-card {
  transform: rotateY(-24deg) rotateX(9deg);
}
#finish-preview.fp-3d .fp-card canvas {
  box-shadow:
    22px 26px 44px -12px rgba(0, 0, 0, 0.55),
    0 2px 8px rgba(0, 0, 0, 0.4);
}
#finish-preview.fp-3d .fp-card::after {
  opacity: 1;
}
/* Кнопка тулбара в активном состоянии — как у прочих переключателей */
#btn-finish-preview.active {
  color: var(--accent);
  background: var(--accent-dim);
}
@media (prefers-reduced-motion: reduce) {
  #finish-preview,
  .fp-card,
  .fp-card canvas,
  .fp-card::after {
    animation: none;
    transition: none;
  }
}
/* На узких экранах — компактнее и не мешаем контенту */
@media (max-width: 640px) {
  #finish-preview {
    right: 10px;
    bottom: 10px;
    width: 118px;
  }
  .fp-title {
    font-size: var(--fs-2xs);
  }
}

/* ============================================================
   QR-КОД В ИНСПЕКТОРЕ МЕДАЛЬОНА
   ============================================================ */
.qr-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 6px 0;
}
.qr-field-label,
.qr-sublabel {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
}
.qr-sublabel {
  margin: 8px 0 2px;
}
.qr-input {
  width: 100%;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-base);
  outline: none;
  transition:
    border-color 0.15s,
    box-shadow 0.15s;
}
.qr-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.qr-input::placeholder {
  color: var(--text-muted);
}
.qr-color-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin: 6px 0;
}
.qr-note {
  margin: 8px 0 6px;
  padding: 7px 9px;
  border-radius: 8px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-muted);
}
.qr-gen {
  margin-top: var(--sp-1);
  font-weight: 600;
}
.qr-hint {
  margin: 4px 2px 8px;
  padding: 6px 9px;
  border-left: 2px solid var(--accent);
  border-radius: 0 6px 6px 0;
  background: var(--accent-dim);
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-secondary);
}

/* ---- Тулбар «Вид» ▾ и «Настройки» ▾ + их меню ---- */
/* Кнопка «Настройки» создаётся кодом (js/50), но выглядит как соседка по тулбару: та же
   каретка, тот же разворот при открытии. Разъехавшийся вид читался бы как «эта кнопка
   другого рода». */
#btn-view-menu,
#btn-settings-menu {
  position: relative;
}
#btn-view-menu .tb-caret,
#btn-settings-menu .tb-caret {
  position: absolute;
  right: 3px;
  bottom: 3px;
  opacity: 0.55;
  transition: transform 0.2s ease;
}
#btn-view-menu[aria-expanded='true'] .tb-caret,
#btn-settings-menu[aria-expanded='true'] .tb-caret {
  transform: rotate(180deg);
}
#btn-view-menu.active,
#btn-settings-menu.active {
  color: var(--accent);
  background: var(--accent-dim);
}
.view-menu {
  min-width: 288px;
  max-height: 82vh;
  overflow-y: auto;
}
.view-menu-ico {
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 7px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  color: var(--text-secondary);
}
.theme-menu-item.active .view-menu-ico {
  color: var(--accent);
  border-color: var(--accent);
}

/* ── Меню «Вид»: блоки Цветопроба / Тема / Инструменты слоя ── */
.view-block-label {
  padding: 4px 10px 6px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.view-proof {
  display: flex;
  gap: 6px;
  padding: 0 8px 4px;
}
.view-proof-pill {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 10px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  text-align: left;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.view-proof-pill:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.view-proof-pill.active {
  background: var(--accent-dim);
  border-color: var(--accent);
  color: var(--accent);
}
.view-proof-pill strong {
  font-size: var(--fs-sm);
  font-weight: 700;
}
.view-proof-pill small {
  font-size: var(--fs-2xs);
  color: var(--text-muted);
}
.view-proof-pill.active small {
  color: var(--accent);
  opacity: 0.85;
}
.view-tool-cycle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: calc(100% - 16px);
  margin: 0 8px 6px;
  padding: 8px 12px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-sm);
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease;
}
.view-tool-cycle:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.view-tool-cycle.active {
  border-color: var(--accent);
  color: var(--accent);
}
.view-tool-cycle b {
  font-weight: 700;
}
.view-tool-slider {
  padding: 4px 12px 8px;
}
.view-tool-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  margin-bottom: 4px;
}
.view-tool-head b {
  color: var(--text-primary);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.view-tool-slider input[type='range'] {
  width: 100%;
}
.view-tools-hint {
  padding: 4px 12px 10px;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  line-height: 1.4;
}

/* ---- 3D-вид: лёгкая непрерывная анимация парения ---- */
@keyframes fp-float {
  0%,
  100% {
    transform: rotateY(-25deg) rotateX(9deg) translateY(0);
  }
  50% {
    transform: rotateY(-15deg) rotateX(5deg) translateY(-5px);
  }
}
#finish-preview.fp-3d.fp-anim .fp-card {
  animation: fp-float 6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  #finish-preview.fp-3d.fp-anim .fp-card {
    animation: none;
  }
}

/* ---- Режимы «Вид» на главном холсте ---- */
/* «В обрез» и фокус-вид — мягкая тень ОТРЕЗАННОЙ карты.
   Почему это идёт вместе со скруглением (js/19 updateFinishPreview): clip-path срезает и
   box-shadow элемента — он рисуется по прямоугольной рамке и уходит вместе с углами. Без
   drop-shadow скруглённая карта осталась бы висеть плоско на фоне. Один клип — одна тень. */
#canvas-area[data-view='cut'] #main-canvas,
#canvas-area[data-view='focus'] #main-canvas {
  filter: drop-shadow(0 10px 26px rgba(0, 0, 0, 0.45));
}

/* Полноценный 3D-рендер карты (грани/толщина/ламинат) — заменяет холст в 3D. */
#card-3d {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  display: none;
  pointer-events: none;
  transform-origin: center center;
  will-change: transform;
}
/* В 3D скрываем главный холст через display:none (НЕ visibility:hidden) — иначе он
   остаётся слоем композитора и каждая перерисовка узора зря пере-загружает текстуру
   ~1.2М пикселей на GPU (микролаги). display:none убирает слой; buildFaceTex всё
   равно читает backing-store через drawImage. */
#canvas-area[data-view='3d-matte'] #main-canvas,
#canvas-area[data-view='3d-gloss'] #main-canvas {
  display: none;
}

/* Выбор цвета среза в меню «Вид» */
.view-menu-sep {
  height: 1px;
  margin: 6px 4px;
  background: var(--border);
}
.view-edge-label {
  padding: 2px 10px 6px;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-muted);
  letter-spacing: 0.02em;
}
.view-edges {
  display: flex;
  gap: var(--sp-2);
  padding: 0 10px 6px;
}
.view-edge {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--border-light);
  background: var(--ec, #f3ecdb);
  cursor: pointer;
  padding: 0;
  transition:
    transform 0.12s ease,
    box-shadow 0.12s ease;
}
.view-edge:hover {
  transform: scale(1.1);
}
.view-edge.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-dim);
}
/* Свотч «Свой цвет» торца: радужная заливка-подсказка + знак «+» (ясно, что это
   выбор произвольного цвета) + скрытый нативный пикер. */
.view-edge-custom {
  position: relative;
  overflow: hidden;
}
.view-edge-plus {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: var(--fs-xl);
  font-weight: 800;
  line-height: 1;
  color: #fff;
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.7),
    0 0 3px rgba(0, 0, 0, 0.5);
  pointer-events: none;
}
.view-edge-input {
  position: absolute;
  inset: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  border: 0;
  padding: 0;
  pointer-events: none;
}

/* ---- Пикер иконок медальона (выпадающее меню из инспектора) ---- */
.med-icon-pop {
  position: fixed;
  z-index: 500;
  width: 300px;
  max-width: calc(100vw - 16px);
  padding: var(--sp-2);
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: dropdownIn 0.18s ease;
}
.mip-head {
  display: flex;
  gap: 6px;
  align-items: center;
}
.mip-search {
  flex: 1;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: var(--fs-base);
  outline: none;
}
.mip-search:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.mip-close {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border: none;
  border-radius: 8px;
  background: var(--bg-secondary);
  color: var(--text-muted);
  cursor: pointer;
}
.mip-close:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
  box-shadow: var(--nm-out-xs);
}
.mip-close:active {
  box-shadow: var(--nm-in-sm);
}
/* Правило плотности: категорий десяток, иконок до двух сотен — выпуклые поштучно они дали бы
   рябь. Обе сетки лежат в канавке, выпуклый в каждой ровно один: выбранная категория и
   выбранная иконка. */
.mip-cats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  padding: 5px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.mip-cat {
  padding: 3px 9px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.mip-cat:hover {
  color: var(--text-primary);
}
.mip-cat.active {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--accent);
  border-color: transparent;
}
.mip-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--sp-1);
  padding: 6px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  max-height: 280px;
  overflow-y: auto;
  padding: 2px;
}
/* E-335. Подвал каталога медальона: счётчик и «Показать ещё» — вне прокручиваемой сетки,
   иначе кнопка уезжает вместе со списком именно тогда, когда она нужна. */
.mip-more {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) 2px 0;
}
.mip-more:empty {
  display: none;
}
.mip-more .mgr-count {
  flex: 1;
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  white-space: nowrap;
}
.mip-more-btn {
  flex: 0 0 auto;
  padding: 4px 10px;
  font-size: var(--fs-2xs);
}
.mip-item {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 8px;
  background: none;
  box-shadow: none;
  color: var(--text-primary);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
.mip-item:hover {
  border-color: transparent;
  background: var(--accent-dim);
  box-shadow: var(--nm-out-xs);
}
.mip-item:active,
.mip-item.active {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.mip-item svg {
  display: block;
}
.mip-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: var(--sp-5);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* Единая подсказка/примечание в инспекторе (было ~8 инлайн-стилей) */
.inspector-hint {
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-muted);
  margin: 4px 0 8px;
}

/* ===== ФОРМАТ КАРТЫ (левая панель) ===== */
#panel-cardsize-region {
  border-bottom: 1px solid var(--border);
}
/* Заголовок-кнопка (сворачивание) */
.cardsize-header {
  width: 100%;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
}
.cardsize-title {
  flex: 0 0 auto;
}
.cardsize-summary {
  display: none;
  min-width: 0;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cardsize-caret {
  margin-left: auto;
  flex: 0 0 auto;
  color: var(--text-muted);
  transition: transform 0.15s ease;
}
#panel-cardsize-region.collapsed .cardsize-caret {
  transform: rotate(-90deg);
}
#panel-cardsize-region.collapsed .cardsize-title {
  display: none;
}
#panel-cardsize-region.collapsed .cardsize-summary {
  display: inline-block;
}
#panel-cardsize-region.collapsed .cardsize-body {
  display: none;
}
.cardsize-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: 10px 12px 12px;
}
/* Селект пресета — рефайн: свой шеврон, hover/focus-ring */
.cardsize-select-wrap {
  position: relative;
}
.cardsize-select {
  width: 100%;
  height: 34px;
  padding: 0 30px 0 11px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 500;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  transition:
    border-color 0.16s ease,
    box-shadow 0.16s ease;
}
.cardsize-select:hover {
  border-color: rgba(255, 255, 255, 0.2);
}
.cardsize-select:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.cardsize-select-caret {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
  pointer-events: none;
}

/* Поля размеров (без спиннеров) + кнопка ориентации */
.cardsize-dims {
  display: flex;
  align-items: center;
  gap: 6px;
}
.cardsize-num {
  width: 100%;
  min-width: 0;
  height: 34px;
  padding: 0 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-primary);
  font-size: var(--fs-base);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
  -moz-appearance: textfield;
  transition:
    border-color 0.16s ease,
    box-shadow 0.16s ease;
}
.cardsize-num::-webkit-outer-spin-button,
.cardsize-num::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.cardsize-num:hover {
  border-color: rgba(255, 255, 255, 0.2);
}
.cardsize-num:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.cardsize-orient {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    border-color 0.16s ease,
    background 0.16s ease,
    color 0.16s ease,
    transform 0.12s ease;
}
.cardsize-orient:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}
.cardsize-orient:active {
  transform: scale(0.9);
}
.cardsize-orient:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.cardsize-unit {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: 500;
  white-space: nowrap;
}

/* Тумблер скругления углов */
.cardsize-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  min-height: 26px;
}
.cardsize-toggle-label {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}
.cardsize-switch {
  position: relative;
  flex: 0 0 auto;
  width: 38px;
  height: 22px;
  cursor: pointer;
}
.cardsize-switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.cardsize-switch-track {
  position: relative;
  display: block;
  width: 38px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.13);
  border: 1px solid var(--border);
  transition:
    background 0.18s ease,
    border-color 0.18s ease;
}
.cardsize-switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
  transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.cardsize-switch input:checked ~ .cardsize-switch-track {
  background: var(--accent);
  border-color: var(--accent);
}
.cardsize-switch input:checked ~ .cardsize-switch-track .cardsize-switch-thumb {
  transform: translateX(16px);
}
.cardsize-switch input:focus-visible ~ .cardsize-switch-track {
  box-shadow: 0 0 0 3px var(--accent-dim);
}

/* «Случайная вариация» и «Случайная палитра» используют единую схему .ai-gen-btn —
   здесь только контекстные отступы. */
.variation-btn {
  margin: 4px 0 8px;
}
.palette-random-btn {
  margin: 6px 0 14px;
}

/* ===== «МОИ ФАЙЛЫ» — премиум-карточки с явной кнопкой «Сделать логотипом» ===== */
.upl-card {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 9px;
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-bottom: var(--sp-2);
  background: var(--bg-tertiary);
  transition: border-color 0.16s ease;
}
.upl-card.is-logo {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-dim);
}
.upl-thumb {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 8px;
  background: #fff center/contain no-repeat;
  border: 1px solid var(--border);
}
.upl-right {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.upl-namerow {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.upl-name {
  flex: 1;
  min-width: 0;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.upl-badge {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--accent-dim);
  color: var(--accent);
  font-size: var(--fs-9-5);
  font-weight: 700;
  letter-spacing: 0.02em;
}
.upl-actions {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.upl-subrow {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.upl-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-xs);
  font-weight: 500;
  transition:
    border-color 0.15s ease,
    background 0.15s ease,
    color 0.15s ease;
}
.upl-subrow .upl-btn {
  /* Основание — по содержимому: при flex-basis:0 три подписи («Узор», «Медальон», «Сюда (12)»)
     делят ширину поровну и средняя обрезается. Растём от своей ширины и переносимся строкой. */
  flex: 1 1 auto;
  min-width: max-content;
  white-space: nowrap;
}
/* «На эту карту» — пер-карточное действие, а два соседа рядом красят всю колоду: разный смысл
   видно глазом. ПУНКТИР ЗДЕСЬ ЗАПРЕЩЁН: в этом же списке пунктирная рамка уже значит
   «недоступно» (.upl-btn-logo:disabled), и включённая кнопка читалась бы как выключенная —
   смотрел на снимок. Отличаем сплошной акцентной рамкой. */
.upl-btn-here {
  border-color: var(--accent);
  color: var(--accent);
}
.upl-btn-here:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  border-color: var(--border);
  color: var(--text-muted);
}
.upl-btn:hover {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
}
.upl-btn svg {
  flex: 0 0 auto;
}
.upl-btn-logo {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 600;
}
.upl-btn-logo:disabled {
  opacity: 0.75;
  cursor: default;
  border-style: dashed;
}
.upl-del {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.upl-del:hover {
  border-color: #e0554f;
  color: #e0554f;
}

/* ===== «Все стороны» — контактный лист (рубашка + 4 туза + джокер) ===== */
#allsides-sheet {
  position: absolute;
  inset: 0;
  display: none;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr;
  gap: 14px;
  padding: 18px;
  background: var(--bg-primary, #0e1013);
  z-index: 30;
  overflow: auto;
}
/* Плитка под курсором с файлами (E-279): человек должен видеть, КУДА упадёт фотография,
   до того как отпустит кнопку. Цвета — токенами, иначе светлая тема получит невидимую рамку. */
.allsides-card.photo-drop {
  outline: 2px dashed var(--accent, #6ea8fe);
  outline-offset: -2px;
  background: color-mix(in srgb, var(--accent, #6ea8fe) 12%, transparent);
  border-radius: var(--radius-md);
}
.allsides-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  min-height: 0;
  padding: 10px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  cursor: pointer;
  position: relative; /* якорь для пульса выбора (::after) */
  transition:
    border-color 0.15s ease,
    transform 0.12s ease,
    box-shadow 0.15s ease;
}
.allsides-card:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.35);
}
/* Выбранная карта на контактном листе (Фаза 2) — рамка охвата правки */
.allsides-card.is-selected {
  border-color: var(--accent);
  box-shadow:
    0 0 0 2px var(--accent),
    0 8px 22px rgba(0, 0, 0, 0.35);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-secondary));
}
/* ПУЛЬС ВЫБОРА (просьба заказчика 2026-08-13: «пусть обводка пульсирует, чтобы лучше было
   видно, что выбрано»). Пульсирует ОТДЕЛЬНЫЙ слой поверх плитки, а не box-shadow самой карты:
   тень пересчитывается в главном потоке и на листе из 55 карт встаёт вместе с рендером — ровно
   та болезнь, что была у заставки. Здесь анимируются transform и opacity, их доводит
   композитор. Сама обводка при этом остаётся на месте: пульс её подчёркивает, а не заменяет —
   иначе в момент затухания выбор выглядел бы снятым. */
.allsides-card.is-selected::after {
  content: '';
  position: absolute;
  inset: -2px;
  border: 2px solid var(--accent);
  border-radius: inherit;
  pointer-events: none;
  animation: sel-pulse 1.6s ease-out infinite;
}
/* ПОДПИСЬ ВЫБРАННОЙ КАРТЫ (просьба заказчика 2026-08-13: «такую же премиальную анимацию и на
   индексах выделенных карт, которые подписаны под картами»). Ритм ТОТ ЖЕ, что у обводки
   (1.6 s, та же кривая): два разных ритма рядом читаются как сбой, один — как замысел.
   Анимируются transform и opacity — их доводит композитор, поэтому пульс не встаёт вместе с
   рендером листа. Само кольцо вокруг подписи не трогает текст: расходится и гаснет. */
.allsides-card.is-selected .allsides-label {
  position: relative;
  color: var(--accent);
  font-weight: 700;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  border-radius: 999px;
  padding: 1px 10px;
}
.allsides-card.is-selected .allsides-label::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 1.5px solid var(--accent);
  border-radius: inherit;
  pointer-events: none;
  animation: sel-label-pulse 1.6s ease-out infinite;
}
@keyframes sel-label-pulse {
  0% {
    opacity: 0.9;
    transform: scale(1);
  }
  70% {
    opacity: 0;
    transform: scale(1.28);
  }
  100% {
    opacity: 0;
    transform: scale(1.28);
  }
}
@media (prefers-reduced-motion: reduce) {
  .allsides-card.is-selected .allsides-label::before {
    animation: none;
    opacity: 0.7;
  }
}
@keyframes sel-pulse {
  0% {
    opacity: 0.85;
    transform: scale(1);
  }
  70% {
    opacity: 0;
    transform: scale(1.055);
  }
  100% {
    opacity: 0;
    transform: scale(1.055);
  }
}
@media (prefers-reduced-motion: reduce) {
  .allsides-card.is-selected::after {
    animation: none;
    opacity: 0.6;
  }
}
.allsides-thumb {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
/* Метка «свой стиль»: ВНИЗУ карты, справа от номинала — САЛАТОВАЯ, уверенный пульс */
.allsides-ov-dot {
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #a3e635;
  box-shadow: 0 0 0 0 rgba(163, 230, 53, 0.75);
  /* ТОЧКА ПРИНИМАЕТ МЫШЬ. Здесь стояло pointer-events: none, и это молча гасило ДВЕ вещи
     сразу: подсказку с перечнем изменённых слоёв (title показывается только при наведении на
     элемент, который вообще ловит курсор) и нажатие, открывающее блок «Отдельные настройки».
     Выбор карты остаётся работой плитки — клик по точке не гасится и всплывает к ней. */
  pointer-events: auto;
  cursor: pointer;
  animation: ov-dot-pulse 1.4s ease-in-out infinite;
}
/* Зона нажатия шире самой точки: 10 px — не размер, в который человек попадает уверенно. */
.allsides-ov-dot::after {
  position: absolute;
  inset: -7px;
  content: '';
}
@keyframes ov-dot-pulse {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(163, 230, 53, 0.75);
  }
  50% {
    transform: scale(1.25);
  }
  70% {
    box-shadow: 0 0 0 9px rgba(163, 230, 53, 0);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(163, 230, 53, 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .allsides-ov-dot {
    animation: none;
  }
}
/* Скругление плитки — ОТ НАСТРОЙКИ ФОРМАТА, а не константой. Здесь стояло 6px, и обзор колоды
   показывал скруглённые карты даже при выключенном скруглении (жалоба 2026-08-14). Переменную
   ставит js/19 при каждом пересчёте масштаба: радиус считается долей ширины карты, поэтому
   одинаково верен и на мелкой плитке, и на крупной. */
.allsides-thumb img,
.allsides-thumb canvas {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: var(--deck-card-radius, 6px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
}
.allsides-label {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
}
@media (max-width: 900px) {
  #allsides-sheet {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Вся колода — скролл-контейнер с масштабируемой сеткой (семантический зум). */
#allsides-sheet.deck-mode {
  display: block;
  overflow: auto;
  padding: 0;
  cursor: zoom-in;
}
#allsides-sheet.deck-mode.deck-panning {
  cursor: grabbing;
}
/* LOD-сетка: число колонок = --deck-cols (уровень зума). Карты пере-раскладываются
   (не тянется битмап) → чёткость сохраняется. Ширина ряда = 100% → скролл при
   переполнении по вертикали работает нативно. */
#allsides-sheet.deck-mode .deck-grid {
  display: grid;
  /* minmax(0, 1fr), а НЕ 1fr. У `1fr` нижняя граница — min-content, поэтому длинная подпись
     в ЛЮБОЙ строке распирала ВСЮ колонку: слово «Рубашка» в последнем ряду делало первую
     колонку 71 px против 46 у остальных (замер 2026-08-14), и на листе туз выглядел крупнее
     соседей. Тот же порог съедал эффект сворачивания инспектора: освободившиеся 266 px
     доставались только «узким» колонкам, а первая уже стояла на своём min-content и не росла
     вовсе (проба E-314 мерит именно первую плитку и видела 71 → 71). */
  grid-template-columns: repeat(var(--deck-cols, 13), minmax(0, 1fr));
  /* Плитка не шире, чем позволяет ВЫСОТА области (--deck-cardmax считает js/19). Колонки делят
     ширину и о высоте ничего не знают: без крышки на глубоком масштабе карта уходила за нижний
     край, и «одна карта на экран» была недостижима. Крышка почти всегда не срабатывает (на
     обзорных уровнях колонка узкая) — поэтому и центрирование ниже незаметно, пока карт много. */
  justify-items: center;
  grid-auto-rows: auto;
  gap: var(--deck-gap, 6px);
  /* E-287: снизу — ЗАПАС ПРОКРУТКИ под плавающую плашку масштаба. Это не отъём рабочей
     площади (тот вариант отнимал у листа 52 px высоты и был отменён): область осталась во
     всю высоту, просто содержимое можно докрутить так, чтобы последний ряд вышел из-под
     плашки. Плавающая панель поверх прокручиваемого полотна — норма для холста-редактора;
     недопустимо лишь одно — контент, который из-под неё не достать. */
  padding: var(--sp-3) var(--sp-3) 56px;
  align-content: start;
  box-sizing: border-box;
}
/* ═══ ВИД «КАРТА КРУПНО + КОЛОДА МЕЛКО» ══════════════════════════════════════════════════
   Просьба заказчика 2026-08-19; полоса СНИЗУ — его решение (Р1) и канон Lightroom: карта
   портретная, нижний ряд портретных миниатюр отдаёт максимум высоты крупному кадру, а правый
   край занят инспектором.

   Плитки те же самые, что в обзоре колоды, — второй набор миниатюр был бы вторым писателем
   факта «как выглядит карта N». Отличается ТОЛЬКО раскладка: полоса вместо сетки. */
#canvas-area[data-view='focus'] {
  /* Высота ленты объявлена ТОКЕНОМ и продублирована на :root — её читает не только сам вид,
     но и всплывающие уведомления, которые живут в <body> и о ленте иначе не узнают. */
  --focus-strip: var(--focus-strip-h);
}
/* УВЕДОМЛЕНИЕ НЕ ЛОЖИТСЯ НА ЛЕНТУ. Тост прибит к низу экрана — в обычных видах там пусто, а
   в виде «карта крупно» внизу стоит полоса-навигатор. Замер 2026-08-21: тост перекрывал
   середину плиток и ПЕРЕХВАТЫВАЛ щелчок (elementFromPoint отдавал .toast, а не карту), так
   что после любого действия с уведомлением полоса на 4.5 с переставала слушаться. */
body:has(#canvas-area[data-view='focus']) .toast {
  bottom: calc(var(--focus-strip-h) + var(--sp-4));
}
#canvas-area[data-view='focus'] #allsides-sheet.deck-mode {
  inset: auto 0 0 0;
  height: var(--focus-strip);
  overflow-x: auto;
  overflow-y: hidden;
  cursor: default;
  border-top: 1px solid var(--border);
  background: var(--bg-secondary, var(--bg-primary));
}
/* Один ряд, без переносов: полоса — это лента, а не маленькая сетка. */
#canvas-area[data-view='focus'] #allsides-sheet.deck-mode .deck-grid {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  min-width: min-content;
}
#canvas-area[data-view='focus'] #allsides-sheet.deck-mode .allsides-card {
  flex: 0 0 84px;
  width: 84px;
}
/* Крупный кадр поднимается на половину полосы — иначе центр экрана и центр свободного места
   расходятся, и карта выглядит съехавшей вниз. Двигаем ТОЛЬКО `top`: inline-transform
   принадлежит зуму и панораме (applyTransform, js/09), спорить с ним нельзя. */
#canvas-area[data-view='focus'] #main-canvas {
  top: calc(50% - var(--focus-strip) / 2);
}
/* Плашка масштаба не должна нырять под полосу: она плавающая и по праву лежит поверх холста,
   но поверх МИНИАТЮР она закрывает собой ровно то, ради чего вид затевался. Селектор взят
   ЗАМЕРОМ живого DOM (.zoom-control), а не по памяти — первая редакция целилась в .deck-zoom,
   которого в разметке нет, и плашка спокойно осталась лежать на плитках. */
#canvas-area[data-view='focus'] .zoom-control {
  bottom: calc(var(--focus-strip) + 14px);
}

#allsides-sheet.deck-mode .allsides-card {
  padding: var(--sp-1);
  gap: 3px;
  border-radius: 7px;
  will-change: transform; /* для FLIP-анимации перехода между уровнями */
  min-width: 0; /* иначе элемент сетки не даёт колонке ужаться до честной доли */
  width: 100%;
  max-width: var(--deck-cardmax, none);
}
/* ПЛЮСИК «ДОБАВИТЬ КАРТУ» (путь Б, 24.09.2026) — последняя плитка листа, в размер карты. Не карта:
   пунктир вместо рубашки, значок и подпись приглушены, при наведении — цвет акцента и подъём на 2 px
   (как у карт). Заблокирован у потолка 100 карт. */
#allsides-sheet.deck-mode .deck-add-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: var(--sp-1);
  border-radius: 7px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  min-width: 0;
  width: 100%;
  max-width: var(--deck-cardmax, none);
  transition:
    color 0.2s ease,
    transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
#allsides-sheet.deck-mode .deck-add-tile:hover,
#allsides-sheet.deck-mode .deck-add-tile:focus-visible {
  color: var(--accent);
  transform: translateY(-2px);
  outline: none;
}
#allsides-sheet.deck-mode .deck-add-box {
  width: 100%;
  aspect-ratio: 63 / 88;
  display: grid;
  place-items: center;
  border: 1.5px dashed currentColor;
  border-radius: var(--deck-card-radius, 6px);
  opacity: 0.8;
}
#allsides-sheet.deck-mode .deck-add-box svg {
  width: 34%;
  height: auto;
}
#allsides-sheet.deck-mode .deck-add-label {
  font-size: clamp(9px, calc(var(--deck-cardw, 100px) * 0.12), 22px);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
#allsides-sheet.deck-mode .deck-add-tile.locked,
#allsides-sheet.deck-mode .deck-add-tile.locked:hover {
  opacity: 0.4;
  color: var(--text-muted);
  transform: none;
  cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  #allsides-sheet.deck-mode .deck-add-tile {
    transition: none;
  }
}
/* Кружок чата Битрикса в генераторе СКРЫТ (решение заказчика 24.09.2026: «мешается, его некуда
   поставить — пусть вызывается из меню „Написать нам“»). Окно чата открывает пункт «Чат с нами»;
   на главной странице кружок остаётся справа (там свой файл стилей). Классы — самого виджета. */
.b24-widget-button-wrapper,
.b24-widget-button-shadow {
  display: none !important;
}
/* «Написать нам» — меню двух пунктов под кнопкой шапки (решение заказчика 24.09.2026) */
.write-us-menu {
  position: fixed;
  z-index: 10050;
  min-width: 280px;
  padding: 6px;
  border-radius: var(--nm-radius, 12px);
  background: var(--nm-surface, var(--bg-secondary));
  border: 1px solid var(--border);
  box-shadow: var(--nm-out-sm, 0 10px 30px rgba(0, 0, 0, 0.35));
  animation: write-us-in 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes write-us-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.write-us-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.write-us-item svg {
  flex: 0 0 auto;
  margin-top: 1px;
  color: var(--accent);
}
.write-us-item span {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.write-us-item b {
  font-weight: 600;
  font-size: 13px;
}
.write-us-item small {
  font-size: 11.5px;
  color: var(--text-muted);
}
.write-us-item:hover,
.write-us-item:focus-visible {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  outline: none;
}
@media (prefers-reduced-motion: reduce) {
  .write-us-menu {
    animation: none;
  }
}

/* Крестик «удалить карту» — только на выбранной плитке-якоре (путь Б, шаг 9) */
#allsides-sheet.deck-mode .deck-del {
  position: absolute;
  top: -6px;
  right: -6px;
  z-index: 3;
  width: clamp(18px, calc(var(--deck-cardw, 100px) * 0.2), 28px);
  height: clamp(18px, calc(var(--deck-cardw, 100px) * 0.2), 28px);
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-primary);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  cursor: pointer;
  transition:
    color 0.2s ease,
    background 0.2s ease,
    transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
#allsides-sheet.deck-mode .deck-del svg {
  width: 58%;
  height: 58%;
}
#allsides-sheet.deck-mode .deck-del:hover,
#allsides-sheet.deck-mode .deck-del:focus-visible {
  background: var(--error);
  border-color: transparent;
  color: #fff;
  transform: translateY(-1px);
  outline: none;
}
#allsides-sheet.deck-mode .deck-del.locked,
#allsides-sheet.deck-mode .deck-del.locked:hover {
  opacity: 0.45;
  background: var(--bg-secondary);
  color: var(--text-muted);
  transform: none;
  cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
  #allsides-sheet.deck-mode .deck-del {
    transition: none;
  }
}
#allsides-sheet.deck-mode .allsides-thumb {
  aspect-ratio: 63 / 88; /* ровные ряды одинаковой высоты на любом уровне */
}
#allsides-sheet.deck-mode .allsides-label {
  font-size: clamp(9px, calc(var(--deck-cardw, 100px) * 0.12), 22px);
  /* Колонки теперь равные, поэтому длинная подпись обязана ужиматься сама, а не толкать сетку. */
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Пилюля выбранной карты на обзорном уровне занимала 20 px из 48 — «Рубашка» обрезалась
   в «Рубаш». На листе плитка мелкая, и поля пилюли соразмерны ей, а не одиночной карте. */
#allsides-sheet.deck-mode .allsides-card.is-selected .allsides-label {
  padding: 1px 4px;
}
#allsides-sheet.deck-mode .allsides-thumb img,
.allsides-thumb canvas {
  box-shadow: 0 2px 7px rgba(0, 0, 0, 0.4);
  /* Картинку нельзя «схватить» мышью — тянем весь холст (drag-pan). */
  pointer-events: none;
  -webkit-user-drag: none;
  user-select: none;
}
#allsides-sheet.deck-mode .deck-grid {
  user-select: none;
}
/* Премиум-FLIP: карты слегка приподняты (тень), поверх соседей. */
#allsides-sheet.deck-mode .deck-flipping .allsides-card {
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
  position: relative;
  z-index: 1;
}
/* Индикатор масштаба колоды. */
/* ===== Зум-контрол у холста (js/09): −, %(сброс), +, вписать ===== */
/* Видимые органы масштаба — новичок, случайно зазумивший, возвращается к 100%
   кликом по «%». Все цвета — только CSS-токены (работает в тёмной и светлой темах). */
/* E-287. МЕСТО. Контрол стоит в ПРАВОМ нижнем углу холста, а не в левом.
   Левый угол — начало сетки: карты растут слева направо и сверху вниз, поэтому плашка там
   всегда лежит на карте (заказчик видел её на плитке «Рубашка»). Правый нижний угол в обоих
   режимах свободен: в листе последний ряд короткий (рубашка + два джокера) и жмётся влево,
   в одиночном виде холст карты по центру, а стрелки перелистывания — по вертикали и внизу
   по центру. Прежняя попытка лечить перекрытие полосой снизу была хуже болезни: она отнимала
   у листа 52 px рабочей высоты ради плашки в 38 px.
   ВИД. Плавающая панель над рабочей поверхностью: матовое стекло, тонкая рамка, шкала теней
   как у соседней панели «Готовый вид» (единая elevation в продукте). В покое приглушена —
   поверх содержимого не должно быть ничего кричащего; при наведении, фокусе с клавиатуры и
   при смене масштаба выходит на полную видимость. */
.zoom-control {
  position: absolute;
  right: 14px;
  bottom: 14px;
  z-index: 40;
  display: flex;
  align-items: stretch;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--bg-secondary) 92%, transparent);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  user-select: none;
  opacity: 0.82;
  transition:
    opacity 0.2s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Полная видимость — когда человек к ней обратился или когда масштаб только что менялся
   (класс ставит тот же код, что показывает подпись). */
.zoom-control:hover,
.zoom-control:focus-within,
.zoom-control.active {
  opacity: 1;
  box-shadow: var(--shadow-lg);
}
/* Пока лист тащат мышью, плашка уходит с глаз: в этот момент человек смотрит на карты.
   Признак ставится на <body> (js/19), а не на самом листе: лист и плашка живут в разных
   родителях, соседского селектора между ними нет. */
body.deck-panning-on .zoom-control {
  opacity: 0.3;
}
.zoom-control .zc-btn,
.zoom-control .zc-ind {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    background 0.18s ease,
    color 0.18s ease,
    opacity 0.18s ease;
}
.zoom-control .zc-ind {
  min-width: 52px;
  padding: 0 8px;
  font-size: var(--fs-xs);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--text-primary);
}
/* Зум-контрол — те же правила: выступ под курсором, вдавливание при нажатии. Индикатор
   процента тоже кнопка (щелчок по нему сбрасывает масштаб), поэтому ведёт себя как кнопка. */
.zoom-control .zc-btn,
.zoom-control .zc-ind {
  border-radius: var(--nm-radius);
  /* Гнёзда, а не выступы: сам зум-контрол — уже выдавленная плашка (см. правило ниже по
     файлу), и второй выступ на ней дал бы «пузырь на пузыре». */
  box-shadow: var(--nm-in);
  transition:
    box-shadow var(--nm-ease),
    color 0.15s ease;
}
.zoom-control .zc-btn:hover,
.zoom-control .zc-ind:hover {
  background: transparent;
  color: var(--accent);
  box-shadow: var(--nm-out-sm);
}
.zoom-control .zc-btn:active,
.zoom-control .zc-ind:active {
  background: transparent;
  box-shadow: var(--nm-in);
}
.zoom-control .zc-btn:focus-visible,
.zoom-control .zc-ind:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  color: var(--accent);
}
.zoom-control .zc-btn:disabled {
  opacity: 0.35;
  cursor: default;
  color: var(--text-muted);
  background: transparent;
}
.zoom-control .zc-fit {
  color: var(--text-muted);
}
/* E-316: кнопки просмотра карты (переворот, 3D) отделены от органов масштаба тонкой чертой —
   это другой род действия, и глаз не должен искать границу. */
.zoom-control .zc-flip {
  margin-left: 4px;
  padding-left: 6px;
  border-left: 1px solid var(--border);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
/* Включённый объём подсвечен: тумблер показывает СОСТОЯНИЕ, а не только действие. */
.zoom-control .zc-3d.is-on {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  color: var(--accent);
}
.zoom-control .zc-3d.is-on:hover {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
}
/* Палец толще курсора: на сенсорном вводе органы дорастают до 44 px. */
@media (pointer: coarse) {
  .zoom-control .zc-btn,
  .zoom-control .zc-ind {
    min-width: 44px;
    height: 44px;
  }
  .zoom-control .zc-ind {
    min-width: 64px;
  }
  .zoom-control {
    opacity: 1; /* без наведения приглушать нечем — на сенсоре hover не бывает */
  }
}
@media (prefers-reduced-motion: reduce) {
  .zoom-control,
  .zoom-control .zc-btn,
  .zoom-control .zc-ind,
  .zoom-control .zc-note {
    transition: none;
  }
}

/* E-285: подпись к масштабу ВНУТРИ зум-контрола. Прежде это была отдельная плашка в правом
   нижнем углу (.deck-zoom-hint) — второй индикатор той же величины, что и проценты слева.
   Оба висели поверх сетки и закрывали карты. Теперь один индикатор: кнопки, проценты и
   подпись «≈ N карт · M в ряд» в одном месте. Ширина анимируется, чтобы контрол не прыгал. */
.zoom-control .zc-note {
  display: inline-flex;
  align-items: center;
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  transition:
    max-width 0.28s ease,
    opacity 0.28s ease,
    padding 0.28s ease;
  padding: 0;
}
.zoom-control .zc-note.show {
  max-width: 190px;
  opacity: 1;
  padding: 0 8px 0 6px;
  border-left: 1px solid var(--border);
  margin-left: 4px;
}
@media (max-width: 1100px) {
  #allsides-sheet.deck-mode .deck-grid {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }
}
.deck-building {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  min-height: 46vh;
}
.deck-building-text {
  font-size: var(--fs-13-5);
  color: var(--text-secondary);
  letter-spacing: 0.03em;
  animation: dlPulse 1.5s ease-in-out infinite;
}
@keyframes dlPulse {
  0%,
  100% {
    opacity: 0.55;
  }
  50% {
    opacity: 1;
  }
}
/* Веер карт: масти раскрываются из стопки и складываются обратно */
.deck-loader {
  position: relative;
  width: 130px;
  height: 92px;
}
.dl-card {
  position: absolute;
  left: 50%;
  bottom: 4px;
  width: 40px;
  height: 58px;
  margin-left: -20px;
  border-radius: 6px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: var(--sp-1);
  font-size: var(--fs-lg);
  font-weight: 700;
  color: #fff;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
  transform-origin: 50% 92%;
  animation: dlFan 1.8s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
.dl-card:nth-child(1) {
  background: linear-gradient(160deg, #3a3a40, #1c1c20);
}
.dl-card:nth-child(2) {
  background: linear-gradient(160deg, #e05a4c, #b0241a);
}
.dl-card:nth-child(3) {
  background: linear-gradient(160deg, #3f86d8, #1b57a0);
}
.dl-card:nth-child(4) {
  background: linear-gradient(160deg, #34b06a, #167a44);
}
@keyframes dlFan {
  0%,
  12% {
    transform: rotate(0deg) translateY(0);
  }
  50%,
  62% {
    transform: rotate(var(--a)) translateY(-10px);
  }
  100% {
    transform: rotate(0deg) translateY(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .dl-card,
  .deck-building-text {
    animation: none;
  }
}

/* ===== СТУДИЯ (модалка) — просторный, приятный layout ===== */
.studio-modal {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(6, 8, 12, 0.66);
  backdrop-filter: blur(4px);
  animation: studioFade 0.18s ease;
}
.studio-modal.hidden {
  display: none;
}
@keyframes studioFade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/* Окно студии — тот же материал, что у прочих диалогов (волна 3): рельеф говорит, из чего
   окно сделано, отброшенная тень — что оно поверх всего. */
.studio-dialog {
  width: 92vw;
  max-width: 900px;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out), var(--shadow-lg);
  overflow: hidden;
  animation: studioPop 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes studioPop {
  from {
    transform: translateY(12px) scale(0.98);
    opacity: 0;
  }
  to {
    transform: none;
    opacity: 1;
  }
}
.studio-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 20px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--bg-tertiary), var(--bg-secondary));
  flex: 0 0 auto;
}
.studio-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: 0.01em;
}
/* Закрывашка — гнездо, как у флайаута: шапка уже поднята, второй выступ читался бы грязью. */
.studio-close {
  width: 30px;
  height: 30px;
  border-radius: var(--nm-radius);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--fs-md);
  transition:
    border-color 0.15s ease,
    color 0.15s ease;
}
.studio-close:hover {
  border-color: transparent;
  color: var(--accent);
  box-shadow: var(--nm-out-xs);
}
.studio-close:active {
  box-shadow: var(--nm-in-sm);
}
.studio-body {
  display: grid;
  grid-template-columns: 1fr 0.82fr;
  align-items: start;
  gap: var(--sp-4);
  padding: 18px;
  overflow-y: auto;
}
.studio-col {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: 0;
}
/* Раздел студии — УТОПЛЕННАЯ область, а не выпуклая плашка: внутри неё лежат органы, и
   выпуклость на выпуклости при одном источнике света читается как грязь. */
.studio-card {
  background: var(--nm-groove);
  border: 1px solid transparent;
  box-shadow: var(--nm-in);
  border-radius: var(--nm-radius);
  padding: var(--sp-4);
}
.studio-hero {
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(106, 184, 238, 0.1), transparent 60%),
    var(--bg-tertiary);
  border-color: rgba(106, 184, 238, 0.3);
}
.studio-h {
  font-size: var(--fs-base);
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: var(--sp-3);
}
.studio-textarea,
.studio-input {
  width: 100%;
  background: var(--nm-surface-in);
  border: 1px solid transparent;
  box-shadow: var(--nm-in);
  border-radius: var(--nm-radius);
  color: var(--text-primary);
  padding: 10px 12px;
  font-size: var(--fs-base);
  font-family: inherit;
  resize: vertical;
  outline: none;
  transition: border-color 0.15s ease;
}
.studio-textarea:focus,
.studio-input:focus {
  border-color: transparent;
  box-shadow:
    var(--nm-in),
    0 0 0 2px var(--accent-dim);
}
.studio-input {
  flex: 1;
  resize: none;
}
.studio-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0;
}
/* Чип-подсказка темы: их пятеро, не сетка — выпуклые поштучно, правило плотности тут не
   применяется (канавка под пятью пилюлями выглядела бы случайной рамкой). */
.studio-chip {
  font-size: var(--fs-xs);
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease),
    background var(--nm-ease);
}
.studio-chip:active {
  box-shadow: var(--nm-in-sm);
}
.studio-chip:hover {
  border-color: transparent;
  color: var(--accent);
  background: var(--accent-dim);
  box-shadow:
    var(--nm-out-xs),
    0 0 0 1px var(--accent-dim);
}
.studio-row {
  display: flex;
  gap: var(--sp-2);
  margin-top: var(--sp-1);
}
.studio-row .ai-gen-btn {
  flex: 1;
  margin-top: 0;
}
.studio-row .btn-soft {
  flex: 0 0 auto;
  white-space: nowrap;
}
.studio-status {
  min-height: 16px;
  font-size: var(--fs-11-5);
  margin-top: 10px;
  color: var(--text-muted);
  line-height: 1.4;
}
.studio-status.thinking {
  color: var(--accent);
}
.studio-status.ok {
  color: #7fd0a0;
}
.studio-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #0e1116;
  border-radius: 50%;
  display: inline-block;
  animation: studioSpin 0.7s linear infinite;
}
@keyframes studioSpin {
  to {
    transform: rotate(360deg);
  }
}
.studio-slider-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.studio-slider-row input[type='range'] {
  flex: 1;
}
.studio-slider-val {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  min-width: 84px;
  text-align: right;
}
.studio-vars {
  margin-top: var(--sp-2);
}
.studio-vars-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--sp-2);
}
.studio-vars-grid img {
  width: 100%;
  display: block;
  aspect-ratio: 0.72;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    transform 0.12s ease;
}
.studio-vars-grid img:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.studio-styles-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 12px 0;
  max-height: 340px;
  overflow-y: auto;
}
.studio-style-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-secondary);
  cursor: pointer;
  transition:
    border-color 0.15s ease,
    transform 0.12s ease;
}
.studio-style-card:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.studio-style-card img,
.studio-style-noimg {
  width: 100%;
  display: block;
  aspect-ratio: 0.72;
  object-fit: cover;
}
.studio-style-noimg {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: var(--fs-xs);
}
.studio-style-name {
  font-size: var(--fs-xs);
  padding: 6px 8px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.studio-style-acts {
  position: absolute;
  top: 4px;
  right: 4px;
  display: flex;
  gap: var(--sp-1);
  opacity: 0;
  transition: opacity 0.15s ease;
}
.studio-style-card:hover .studio-style-acts {
  opacity: 1;
}
.studio-style-act {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  border: none;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  cursor: pointer;
  font-size: var(--fs-xs);
}
.studio-style-act:hover {
  background: var(--accent);
  color: #0e1116;
}
.studio-empty {
  grid-column: 1 / -1;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  padding: var(--sp-4);
  text-align: center;
}
@media (max-width: 720px) {
  .studio-body {
    grid-template-columns: 1fr;
  }
}

/* ===== Студия v2: живое превью + единые кнопки ===== */
.studio-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 40px;
  padding: 0 16px;
  font-size: var(--fs-sm);
  font-weight: 600;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--nm-surface);
  border: 1px solid transparent;
  box-shadow: var(--nm-out-sm);
  border-radius: var(--nm-radius);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--nm-ease),
    transform 0.1s ease,
    box-shadow var(--nm-ease);
}
.studio-btn:hover {
  border-color: transparent;
  background: var(--bg-hover);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.studio-btn:active {
  transform: translateY(1px);
  box-shadow: var(--nm-in-sm);
}
.studio-btn:disabled {
  opacity: 0.6;
  cursor: default;
}
.studio-btn.primary {
  color: #0e1116;
  border: none;
  background: linear-gradient(135deg, #7cc3ff, #a78bfa);
  box-shadow: 0 4px 14px rgba(120, 150, 240, 0.28);
}
.studio-btn.primary:hover {
  filter: brightness(1.06);
  box-shadow: 0 6px 18px rgba(120, 150, 240, 0.38);
}
/* превью */
.studio-preview {
  display: flex;
  flex-direction: column;
}
.studio-preview-img {
  display: block;
  width: 100%;
  height: 300px;
  object-fit: contain;
  background: #0b0c10;
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: var(--sp-3);
}
/* кнопки в ряду не растягивают инпут: инпут гибкий, кнопка по контенту */
.studio-row .studio-input {
  flex: 1;
  min-width: 0;
}
/* тоньше вертикальный ритм карточек */
.studio-card + .studio-card {
  margin-top: 0;
}

/* ===== Дизайнерские кнопки перемотки карт на холсте ===== */
/* Фростед-«таблетка», адаптивная к теме: белая в светлой, тёмная в тёмной.
   Стрелка читабельная (не серая), акцент — на наведении/фокусе. */
/* СТЕКЛО, А НЕ РЕЛЬЕФ — решение волны 2. Стрелки висят НАД ХОЛСТОМ, а не на панели, и
   выдавливать их не из чего: неоморфизм говорит «этот орган вылеплен из поверхности», а
   поверхности под ними нет — там карта пользователя. Поэтому у них размытие фона и обычная
   тень: они читаются как накладка поверх работы, чем и являются. */
.card-nav-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-secondary) 86%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  color: color-mix(in srgb, var(--text-primary) 70%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 14;
  opacity: 0.94;
  box-shadow: var(--shadow-md);
  transition:
    color 0.18s ease,
    border-color 0.18s ease,
    background 0.18s ease,
    box-shadow 0.18s ease,
    opacity 0.18s ease,
    transform 0.16s cubic-bezier(0.2, 0.85, 0.25, 1);
}
.card-nav-btn:hover {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-secondary));
  opacity: 1;
  transform: translateY(-50%) scale(1.09);
  box-shadow: var(--shadow-lg);
}
.card-nav-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  color: var(--accent);
}
.card-nav-btn:active {
  transform: translateY(-50%) scale(0.95);
}
.card-nav-prev {
  left: 22px;
}
.card-nav-next {
  right: 22px;
}
.card-nav-label {
  position: absolute;
  bottom: 46px;
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 16px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg-secondary) 88%, transparent);
  -webkit-backdrop-filter: blur(10px) saturate(1.05);
  backdrop-filter: blur(10px) saturate(1.05);
  border: 1px solid var(--border);
  font-size: var(--fs-12-5);
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--text-primary);
  z-index: 14;
  pointer-events: none;
  box-shadow: var(--shadow-md);
}
/* В режиме «Вся колода» стрелки/лейбл прячем (лист перекрывает холст) */
#canvas-area[data-view='all'] .card-nav-btn,
#canvas-area[data-view='all'] .card-nav-label {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .card-nav-btn {
    transition:
      color 0.15s ease,
      border-color 0.15s ease,
      background 0.15s ease;
  }
  .card-nav-btn:hover,
  .card-nav-btn:active {
    transform: translateY(-50%);
  }
}
@media (max-width: 720px) {
  .card-nav-btn {
    width: 40px;
    height: 40px;
  }
  .card-nav-prev {
    left: 8px;
  }
  .card-nav-next {
    right: 8px;
  }
}

/* ===== Глобальный селектор групп колоды (премиальные сегменты) ===== */
.scope-selector {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin: 4px 0 12px;
}
.scope-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 9px 4px 7px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  cursor: pointer;
  position: relative;
  transition:
    color 0.16s ease,
    border-color 0.16s ease,
    background 0.16s ease,
    box-shadow 0.16s ease,
    transform 0.16s cubic-bezier(0.2, 0.8, 0.25, 1);
}
.scope-pill .scope-ic {
  font-size: var(--fs-xl);
  line-height: 1;
}
.scope-pill .scope-lb {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-primary);
}
.scope-pill .scope-hint {
  font-size: var(--fs-9-5);
  color: var(--text-muted);
  letter-spacing: 0.03em;
}
.scope-pill:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
  background: var(--bg-hover);
  transform: translateY(-1px);
}
.scope-pill:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.scope-pill.active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-secondary));
  box-shadow:
    inset 0 0 0 1px var(--accent),
    var(--shadow-sm);
}
.scope-pill.active .scope-lb {
  color: var(--accent);
}

/* ===== Toast-уведомления (вынесено из инлайн-хардкода, A3) ===== */
/* Кнопка действия в уведомлении (E-289): «Оставить как есть» рядом с сообщением о том,
   что продукт сделал сам. Отмена должна быть там же, где новость о действии. */
.toast-act {
  margin-left: 4px;
  padding: 6px 12px;
  border-radius: var(--nm-radius);
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: box-shadow var(--nm-ease);
}
.toast-act:active {
  box-shadow: var(--nm-in-sm);
}
.toast-act:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.toast-act:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.toast--action {
  max-width: 620px;
}
.toast {
  position: fixed;
  bottom: var(--sp-6);
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  /* Уведомление — накладка ПОВЕРХ работы, но живёт на панели-подложке, поэтому материал ей
     положен. Цветная полоса слева остаётся: она отвечает на другой вопрос — успех это или
     ошибка, — и рельеф её не заменяет. */
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-left: 4px solid var(--text-muted);
  border-radius: var(--nm-radius);
  padding: var(--sp-3) var(--sp-5);
  display: flex;
  align-items: center;
  gap: 10px;
  z-index: 9999;
  font-size: var(--fs-base);
  color: var(--text-primary);
  max-width: 480px;
  box-shadow: var(--nm-out-sm), var(--shadow-lg);
  opacity: 0;
  transition:
    opacity 0.3s ease,
    transform 0.3s ease;
}
.toast.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
.toast--success {
  border-color: var(--success);
  border-left-color: var(--success);
}
.toast--warning {
  border-color: var(--warning);
  border-left-color: var(--warning);
}
.toast--error {
  border-color: var(--error);
  border-left-color: var(--error);
}
.toast--info {
  border-color: var(--accent);
  border-left-color: var(--accent);
}
.toast-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  color: var(--text-muted);
}
.toast-ico svg {
  width: 22px;
  height: 22px;
}
.toast--success .toast-ico {
  color: var(--success);
}
.toast--warning .toast-ico {
  color: var(--warning);
}
.toast--error .toast-ico {
  color: var(--error);
}
.toast--info .toast-ico {
  color: var(--accent);
}

/* Инфо-плашка в инспекторе (пояснения состояния, напр. пипсы на тузах) */
/* РАЗДЕЛИТЕЛЬ СМЫСЛОВЫХ ГРУПП ВНУТРИ БЛОКА ИНСПЕКТОРА.
   Жалоба заказчика (2026-08-11): «справа всё идёт сплошной трубой просто вниз, блоки не
   отделены друг от друга». Внутри одного блока живут РАЗНЫЕ вопросы — из чего значок, где он
   стоит, какого размера, — и без границы они читаются как один длинный список. Разделитель
   тонкий и с подписью: линия без слов делит, но не объясняет. */
.insp-group-sep {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0 8px;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.insp-group-sep::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}
.inspector-note {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: var(--sp-2) 10px;
  margin: var(--sp-1) 0 var(--sp-2);
  line-height: var(--lh-normal);
}
/* Заметка-ПРЕДУПРЕЖДЕНИЕ: правка ОБЩЕГО актива внутри скоупной секции (общий логотип
   при выбранном наборе). Спокойная заметка тут не годится — её читают как сноску, а
   цена ошибки 52 карты. Цвет — только токеном (--warning есть в обеих темах). */
.inspector-note.is-warn {
  color: var(--text-primary);
  background: color-mix(in srgb, var(--warning) 12%, transparent);
  border-color: color-mix(in srgb, var(--warning) 45%, transparent);
  border-left-color: var(--warning);
}

/* C4 — иерархия тулбара: «Вид» как заметный меню-контрол, «Сброс» приглушён */
.tool-btn--menu {
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
}
.tool-btn--menu:hover {
  border-color: var(--accent);
  background: var(--bg-hover);
}
.tool-btn--muted {
  opacity: 0.6;
}
.tool-btn--muted:hover {
  opacity: 1;
}

/* D1 — групповые подзаголовки в меню «Скачать» */
.dropdown-group-header {
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
}
.dropdown-group-header:not(:first-child) {
  margin-top: var(--sp-1);
  border-top: 1px solid var(--border);
  padding-top: 10px;
}

/* D2 — панель экспорта в предпросмотре «Вся колода» */

/* ===== «🎲 Собрать колоду» — герой случайной генерации (RD2) ===== */
.deck-hero {
  margin-bottom: var(--sp-3);
  padding: var(--sp-3);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-tertiary));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: var(--radius-lg);
  text-align: center;
}
.deck-hero-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--accent);
  color: var(--bg-primary);
  border: none;
  border-radius: var(--radius-md);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  cursor: pointer;
  transition:
    background 0.16s ease,
    transform 0.12s ease;
}
.deck-hero-btn:hover {
  background: var(--accent-hover);
}
.deck-hero-btn:active {
  transform: scale(0.98);
}
.deck-hero-ico {
  font-size: var(--fs-xl);
}
.deck-hero-sub {
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  line-height: var(--lh-normal);
}
.deck-hero-extra:not(:empty) {
  margin-top: var(--sp-2);
}

/* ===== Лента вариантов + фиксация слоёв (RD3) ===== */
.deck-locks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  margin-bottom: var(--sp-2);
}
.deck-locks-lab {
  width: 100%;
  font-size: var(--fs-2xs);
  color: var(--text-muted);
  text-align: left;
}
.deck-lock-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  cursor: pointer;
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
}
.deck-lock-chip input {
  accent-color: var(--accent);
  cursor: pointer;
}
.deck-variants {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-1);
  margin-bottom: var(--sp-2);
  min-height: 40px;
}
.deck-variants-hint {
  grid-column: 1 / -1;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-align: center;
  padding: var(--sp-2);
}
.deck-variant {
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-secondary);
  transition:
    border-color 0.16s ease,
    transform 0.12s ease;
}
.deck-variant:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}
.deck-variant img {
  display: block;
  width: 100%;
  height: auto;
}
.deck-more-btn {
  width: 100%;
  padding: var(--sp-2);
  background: var(--bg-tertiary);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.deck-more-btn:hover {
  border-color: var(--accent);
}

/* ===== Отдельный инструмент «Генератор колоды» (модал, RD4) ===== */
.deck-gen-modal .ux-modal-box {
  max-width: 400px;
  width: 90vw;
}
.deck-gen-modal .ux-sub {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-top: var(--sp-1);
  line-height: var(--lh-normal);
}
.deck-hero.in-modal {
  margin: var(--sp-3) 0 0;
  background: transparent;
  border: none;
  padding: 0;
  text-align: left;
}

/* ===== Премиум-оверлей ожидания (RD5): веер карт + кольцо прогресса + ETA ===== */
/* ЯРЛЫК ПЕРЕКЛЮЧАТЕЛЯ ВИДА — «Смотрю:». Подача НАМЕРЕННО та же, что у левого «Меняю:»
   (.scope-head-lab): мелкие прописные, приглушённый цвет, та же разрядка. Пара глаголов и
   объясняет разницу — верх показывает, лево выбирает. Разойдутся стили — пропадёт и смысл. */
.switcher-lab {
  align-self: center;
  margin-right: 8px;
  padding-left: 2px;
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: var(--fw-bold);
  color: var(--text-secondary);
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

/* ═══ ЗАСТАВКА ОЖИДАНИЯ — НЕОМОРФИЗМ (18.09.2026, решения заказчика) ══════════════════════
   Заказчик: «переделать полностью, в стилистике неоморфизма, как весь продукт; аврору убрать
   совсем; строку КАРТ РЕГИОН убрать; указатель — кольцо; проценты всегда». Правила движения —
   раздел переноса в CLAUDE.md («не как дешёвый мультик»): без scale(0) и пружин, ≥0.3 с,
   cubic-bezier(.16,1,.3,1), prefers-reduced-motion. Всё, что движется, — transform/opacity:
   главный поток при генерации занят кусками ~700 мс (busy-overlay-smooth).
   Цвета — ТОЛЬКО токенами: карточка живёт в трёх темах (theme-light.css переопределяет nm-*). */
.busy-overlay {
  position: fixed;
  inset: 0;
  z-index: 4000;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Скрим без backdrop-filter: blur() блюрил всю страницу (54 карты) каждый кадр. */
  background: var(--busy-scrim);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.busy-overlay.visible {
  opacity: 1;
}
/* Отложенный показ (opts.отложить): первые 400 мс узла нет на экране вовсе. */
.busy-overlay.pending {
  display: none;
}
.busy-card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 320px;
  max-width: 360px;
  padding: 28px 32px 24px;
  background: var(--nm-surface);
  border: 0;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out);
  /* Появление: проявление + подъём 10 px, 0.6 с, кривая заказчика. Уход — быстрее входа. */
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
.busy-overlay.visible .busy-card {
  opacity: 1;
  transform: translateY(0);
}
.busy-overlay.done .busy-card {
  opacity: 0;
  transition-duration: 0.3s;
}
/* ── Кольцо: выпуклый диск, вдавленная канавка, дуга акцентом, приподнятая сердцевина ── */
.busy-visual {
  position: relative;
  width: 120px;
  height: 120px;
  margin: 2px 0 8px;
  border-radius: 50%;
  background: var(--nm-surface);
  box-shadow: var(--nm-out);
}
.busy-groove {
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.busy-core {
  position: absolute;
  inset: 22px;
  border-radius: 50%;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  z-index: 3;
}
.busy-ring {
  display: none; /* дорожку рисует канавка; svg-подложка оставлена в разметке ради проб */
}
/* КОНЦЫ ДУГИ ПЛОСКИЕ, А НЕ КРУГЛЫЕ. Круглая шапка выступает за линию клипа на пол-толщины —
   и на нуле процентов из ниоткуда появлялись две точки (поймано пробой). */
.busy-ring-fg {
  fill: none;
  stroke: var(--accent);
  stroke-width: 8;
  stroke-linecap: butt;
}
/* ПОЛОВИНКИ ДУГИ. Клип неподвижен, вращается содержимое — тогда «сколько показано» задаёт
   transform, и композитор доводит его сам, пока главный поток занят рендером карт.
   Тень/фильтр на вращаемый элемент НЕ вешаем: фильтр отправил бы анимацию в главный поток. */
.busy-half {
  position: absolute;
  inset: 0;
  width: 120px;
  height: 120px;
  z-index: 2;
}
.busy-half > i {
  display: block;
  width: 120px;
  height: 120px;
  transform: rotate(180deg);
  will-change: transform;
}
.busy-half svg {
  display: block;
  width: 120px;
  height: 120px;
  transform: rotate(-90deg);
}
.busy-half-a {
  clip-path: inset(0 0 0 50%);
}
.busy-half-b {
  clip-path: inset(0 50% 0 0);
}
.busy-half-b > i {
  transform: rotate(360deg);
}
.busy-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 5;
  font-size: 24px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2px;
  color: var(--text-primary);
}
.busy-title {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--text-primary);
  text-align: center;
}
.busy-step {
  min-height: 1.4em;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.busy-eta {
  min-height: 1.3em;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
/* ВЫХОД ИЗ ДОЛГОГО ОЖИДАНИЯ — выпуклая кнопка по образцу .tool-btn; нажатая/отменяющая —
   вдавленная. Подчинена кольцу (главный герой карточки), высота 40 px — цель не мелкая. */
.busy-cancel {
  align-self: center;
  margin-top: 12px;
  min-height: 40px;
  padding: 0 22px;
  border: 0;
  border-radius: 999px;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition:
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    opacity 0.3s ease;
}
.busy-cancel:hover {
  transform: translateY(-2px);
}
.busy-cancel:active,
.busy-cancel:disabled {
  transform: none;
  box-shadow: var(--nm-in-sm);
}
.busy-cancel:disabled {
  opacity: 0.7;
  cursor: default;
}
.busy-cancel:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.busy-cancel[hidden] {
  display: none;
}
/* Режим «сколько ждать — неизвестно» (сервер): бегущая дуга. Крутим КОНТЕЙНЕР transform'ом
   по той же причине, что и прогресс. Цифры нет — обещать процент нечем. */
.busy-overlay.indeterminate .busy-pct {
  display: none;
}
.busy-overlay.indeterminate .busy-half {
  clip-path: none;
}
.busy-overlay.indeterminate .busy-half-b {
  display: none;
}
.busy-overlay.indeterminate .busy-half-a > i {
  animation: busySpin 1.1s linear infinite;
}
.busy-overlay.indeterminate .busy-half-a .busy-ring-fg {
  stroke-dasharray: 90 240;
}
@keyframes busySpin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .busy-overlay,
  .busy-card,
  .busy-cancel {
    transition: none;
  }
  .busy-overlay.indeterminate .busy-half-a > i {
    animation: none;
  }
}

/* «Единая колода» — мастер-галочка связи лица с рубашкой (слои лица) */
.deck-unify-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 8px 10px;
  margin-bottom: var(--sp-1);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--accent) 10%, var(--bg-tertiary));
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--text-primary);
}
.deck-unify-row small {
  color: var(--text-muted);
  font-size: var(--fs-2xs);
}
.deck-unify-cb {
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
  cursor: pointer;
  flex-shrink: 0;
}

/* Метка-ориентир в инспекторе (напр. какая рамка на рубашке) */
.inspector-ref {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-tertiary));
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
  border-radius: 8px;
  padding: 6px 10px;
  margin: 2px 0 6px;
}
.inspector-ref b {
  color: var(--accent);
}

/* ===== Премиум сегмент-контрол (ровный ряд, активный сегмент «приподнят») ===== */
.seg[class*='cols-'] {
  display: grid;
  gap: 3px;
  padding: 3px;
  margin: 6px 0 var(--sp-3);
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.seg.cols-2 {
  grid-template-columns: repeat(2, 1fr);
}
.seg.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}
.seg.cols-4 {
  grid-template-columns: repeat(4, 1fr);
}
.seg[class*='cols-'] > .seg-chip {
  flex: none;
  min-width: 0;
  border: 1px solid transparent;
  background: transparent;
  border-radius: calc(var(--radius-md) - 3px);
  padding: 7px 4px;
  font-weight: var(--fw-semibold);
  box-shadow: none;
}
.seg[class*='cols-'] > .seg-chip:hover {
  color: var(--text-primary);
  background: color-mix(in srgb, var(--bg-secondary) 60%, transparent);
}
.seg[class*='cols-'] > .seg-chip.active {
  background: var(--bg-secondary);
  color: var(--accent);
  border-color: transparent;
  box-shadow: var(--shadow-sm);
}
.seg[class*='cols-'] > .seg-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ============================================================================
   A11y: единый видимый фокус для НЕ-button контролов + бегунок слайдера,
   единый вид отключённого состояния. (button:focus-visible задан выше глобально.)
   ========================================================================== */
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
[role='button']:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Слайдер: фокус — подсветка бегунка (не рамка вокруг трека) */
input[type='range']:focus-visible {
  outline: none;
}
input[type='range']:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent);
}
input[type='range']:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent);
}
/* Единое отключённое состояние (роль disabled видна визуально) */
button:disabled,
button[disabled],
.btn-soft[disabled],
.btn-soft.is-disabled,
.studio-btn[disabled],
input:disabled,
select:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ===== Лёгкий чип обработки (средние операции: тяжёлые узоры) ===== */
/* E-321: индикатор пересчёта — КРУПНАЯ плашка в ЦЕНТРЕ рабочей области.
   Был мелкий чип в 22 px от нижнего края экрана: человек смотрит на карту, а сообщение
   появляется там, куда он не смотрит, — «сменил свойство, на экране ничего, непонятно, идёт
   процесс или нет». Плашка переехала туда же, где результат, и выросла до читаемого размера.
   Курсор не перехватывает (pointer-events:none) — работать можно, не дожидаясь. */
.processing-chip {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.96);
  z-index: 9998;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 24px;
  background: color-mix(in srgb, var(--bg-secondary) 94%, transparent);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 14px);
  color: var(--text-primary);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold, 600);
  box-shadow: var(--shadow-lg, 0 18px 50px rgba(0, 0, 0, 0.45));
  opacity: 0;
  transition:
    opacity 0.18s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.18s cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}
.processing-chip.visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}
.proc-spin {
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--accent) 32%, transparent);
  border-top-color: var(--accent);
  animation: procspin 0.7s linear infinite;
}
@keyframes procspin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .proc-spin {
    animation: none;
  }
  .processing-chip {
    transition: opacity 0.16s ease;
    transform: translate(-50%, -50%);
  }
  .processing-chip.visible {
    transform: translate(-50%, -50%);
  }
}

/* Статус Студии: деградация до локального фолбэка (нейросеть недоступна) */
.studio-status.warn {
  color: var(--warning);
}

/* ===== Плашка результата «Колода готова → Скачать / Доработать» ===== */
.deck-ready-banner {
  /* ВНИЗУ, А НЕ СВЕРХУ (жалоба 2026-08-10 21:32: «сама плашка поверх карт встаёт — нехорошо»).
     Замер на 1600×1050: сверху плашка накрывала 7 плиток контактного листа — и накрывала
     ПЕРВЫЙ ряд, то есть именно то, что человек идёт смотреть после генерации. Снизу — 0:
     лист заканчивается на 645 px, ниже свободно. Зум-контрол живёт в правом нижнем углу,
     плашка по центру — они расходятся. */
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translate(-50%, 10px);
  z-index: 9997;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 8px 10px 8px 14px;
  background: var(--bg-secondary);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: var(--radius-pill, 999px);
  box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.3));
  opacity: 0;
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}
.deck-ready-banner.visible {
  opacity: 1;
  transform: translate(-50%, 0);
}
/* Бейдж оценки — ВИДИМО нажимаемая вещь. Жалоба: «непонятно, что можно нажимать на кнопки
   просмотра статистики». Курсора-руки мало: он появляется только когда мышь уже там. */
.deck-ready-banner button.dr-grade {
  transition:
    background 0.15s ease,
    transform 0.12s ease;
}
.deck-ready-banner button.dr-grade:hover {
  background: color-mix(in srgb, #c9a24a 32%, transparent) !important;
  transform: translateY(-1px);
}
.deck-ready-banner .dr-txt {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold, 600);
  color: var(--text-primary);
  margin-right: var(--sp-1);
}
.deck-ready-banner .dr-dl,
.deck-ready-banner .dr-more {
  padding: 6px 14px;
  border-radius: var(--radius-pill, 999px);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold, 600);
  border: 1px solid transparent;
  cursor: pointer;
}
.deck-ready-banner .dr-dl {
  background: var(--accent);
  color: #fff;
}
.deck-ready-banner .dr-more {
  background: transparent;
  color: var(--text-secondary);
  border-color: var(--border);
}
.deck-ready-banner .dr-more:hover {
  color: var(--text-primary);
  background: var(--bg-tertiary);
}
@media (prefers-reduced-motion: reduce) {
  .deck-ready-banner {
    transition: opacity 0.2s ease;
    transform: translate(-50%, 0);
  }
}

/* ===== Брендовая колода: форма брифа ===== */
.brand-deck-modal .ux-modal-box {
  max-width: 520px;
  width: 92vw;
}
.brand-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: var(--sp-3) 0;
}
.brand-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.brand-field-lab {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold, 600);
  color: var(--text-secondary);
}
.brand-input {
  width: 100%;
  padding: 9px 11px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-family: inherit;
}
.brand-input::placeholder {
  color: var(--text-muted, #8a93a3);
}
.brand-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-sm);
  color: var(--text-primary);
  cursor: pointer;
}
.brand-go {
  margin-top: var(--sp-2);
}
.brand-status {
  min-height: 18px;
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  text-align: center;
}
.brand-status.ok {
  color: var(--accent);
}
.brand-status.err {
  color: var(--error);
}

/* ===== Брендовая колода: превью (3 образца) + отчёт критика единства ===== */
.brand-preview {
  margin-top: var(--sp-3);
}
.brand-preview-cap {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.brand-preview-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-2);
}
.brand-preview-cell {
  margin: 0;
  text-align: center;
}
.brand-preview-cell img {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-tertiary);
  display: block;
}
.brand-preview-cell figcaption {
  margin-top: 3px;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
}
.brand-report {
  margin-top: var(--sp-3);
}
.brand-report-title {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold, 600);
  color: var(--text-primary);
  margin-bottom: 5px;
}
.brand-report-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.brand-report-list li {
  font-size: var(--fs-xs);
}
.brand-report-list li.ok {
  color: var(--text-secondary);
}
.brand-report-list li.bad {
  color: var(--error);
}

/* Студия: индикатор логотипа в едином сценарии */
.studio-logo-note {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin: 6px 0 2px;
  padding: 7px 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.studio-logo-note b {
  color: var(--accent);
}

/* Студия: строка «лого-note + кнопка загрузки» */
.studio-logo-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 2px;
}
.studio-logo-row .studio-logo-note {
  flex: 1;
  margin: 0;
}
/* Иконка загруженного логотипа (для понимания, какой логотип загружен). */
.studio-logo-thumb {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 8px;
  background:
    repeating-conic-gradient(#e9edf3 0% 25%, #cfd6df 0% 50%) 0 / 12px 12px,
    #fff;
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
.studio-logo-thumb img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* ============ Рекламная анимация типографии (во время AI-генерации) ============ */
.print-ad-overlay {
  position: fixed;
  inset: 0;
  z-index: 2147483600; /* выше модалки Студии (2147483000) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 32px;
  color: #f4f1ea;
  overflow: hidden;
  background:
    radial-gradient(1200px 700px at 50% -10%, #24304d 0%, transparent 60%),
    radial-gradient(900px 600px at 100% 110%, #3a2140 0%, transparent 55%),
    linear-gradient(160deg, #0d1017 0%, #141a26 55%, #0d1017 100%);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.print-ad-overlay.show {
  opacity: 1;
}
/* Плавающие карты-масти на фоне */
.print-ad-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.print-ad-bg span {
  position: absolute;
  font-size: clamp(60px, 12vw, 160px);
  color: rgba(255, 255, 255, 0.045);
  animation: padFloat 14s linear infinite;
  will-change: transform;
}
@keyframes padFloat {
  0% {
    transform: translateY(110vh) rotate(-20deg);
  }
  100% {
    transform: translateY(-40vh) rotate(20deg);
  }
}
/* Премиум-компоновка по центру */
.print-ad-inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}
/* Виньетка для глубины */
.print-ad-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 42%, transparent 45%, rgba(0, 0, 0, 0.55) 100%);
}
/* Веер карт за брендом */
.print-ad-fan {
  position: relative;
  height: 84px;
  width: 230px;
  margin-bottom: 4px;
}
.print-ad-fan .pac {
  position: absolute;
  left: 50%;
  top: 6px;
  width: 50px;
  height: 70px;
  margin-left: -25px;
  border-radius: 7px;
  background: linear-gradient(158deg, #fffef9 0%, #f4efe2 55%, #e6dfce 100%);
  color: #17202e;
  padding: 5px 6px;
  box-shadow:
    0 12px 26px rgba(0, 0, 0, 0.5),
    inset 0 0 0 1px rgba(201, 162, 74, 0.55),
    inset 0 0 0 3px rgba(255, 255, 255, 0.6);
  transform: translateX(var(--dx)) rotate(var(--rot));
  transform-origin: bottom center;
  animation: padFanIn 0.7s cubic-bezier(0.34, 1.4, 0.4, 1) both;
}
.print-ad-fan .pac b {
  position: absolute;
  top: 4px;
  left: 6px;
  font-size: 15px;
  font-weight: 800;
  line-height: 1;
}
.print-ad-fan .pac i {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 26px;
  font-style: normal;
}
.print-ad-fan .pac-red {
  color: #c0392b;
}
.print-ad-fan .pac-0 {
  animation-delay: 0.05s;
}
.print-ad-fan .pac-1 {
  animation-delay: 0.12s;
}
.print-ad-fan .pac-2 {
  animation-delay: 0.19s;
  z-index: 2;
}
.print-ad-fan .pac-3 {
  animation-delay: 0.26s;
}
.print-ad-fan .pac-4 {
  animation-delay: 0.33s;
}
@keyframes padFanIn {
  from {
    opacity: 0;
    transform: translateX(0) rotate(0) translateY(14px);
  }
}
.print-ad-brand {
  display: flex;
  align-items: center;
  gap: 16px;
}
.print-ad-logo {
  position: relative;
  width: 58px;
  height: 80px;
  border-radius: 10px;
  background: linear-gradient(150deg, #f6e3a8 0%, #e9c46a 45%, #c9970f 100%);
  color: #1a1205;
  display: grid;
  place-items: center;
  font-size: 36px;
  font-weight: 800;
  box-shadow:
    0 14px 38px rgba(201, 151, 15, 0.4),
    inset 0 0 0 2px rgba(255, 255, 255, 0.35),
    inset 0 -8px 16px rgba(120, 80, 0, 0.25);
  transform: rotate(-7deg);
  animation: padLogoTilt 3.6s ease-in-out infinite alternate;
  overflow: hidden;
}
.print-ad-logo::after {
  /* блик-скольжение (фольга) */
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    115deg,
    transparent 30%,
    rgba(255, 255, 255, 0.75) 48%,
    transparent 62%
  );
  transform: translateX(-120%);
  animation: padShine 3.6s ease-in-out infinite;
}
@keyframes padShine {
  0%,
  55% {
    transform: translateX(-120%);
  }
  75%,
  100% {
    transform: translateX(120%);
  }
}
@keyframes padLogoTilt {
  from {
    transform: rotate(-7deg) translateY(0);
  }
  to {
    transform: rotate(5deg) translateY(-6px);
  }
}
.print-ad-brand-txt {
  text-align: left;
}
.print-ad-eyebrow {
  font-size: clamp(9px, 1vw, 11px);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: #b99a52;
  margin-bottom: 4px;
  font-weight: 700;
}
.print-ad-brand-name {
  font-family: 'Playfair Display', 'Georgia', 'Times New Roman', serif;
  font-size: clamp(34px, 5vw, 62px);
  font-weight: 800;
  letter-spacing: 0.02em;
  background: linear-gradient(
    92deg,
    #c79a3e 0%,
    #f4e2ad 26%,
    #fff6df 44%,
    #e9c46a 60%,
    #b1801a 100%
  );
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  line-height: 1;
  filter: drop-shadow(0 3px 14px rgba(233, 196, 106, 0.3));
  animation: padGoldSheen 5s ease-in-out infinite;
}
@keyframes padGoldSheen {
  0%,
  100% {
    background-position: 0% 0;
  }
  50% {
    background-position: 100% 0;
  }
}
.print-ad-brand-sub {
  font-size: clamp(12px, 1.4vw, 15px);
  color: #aeb9c9;
  letter-spacing: 0.14em;
  margin-top: 6px;
}
/* Золотой разделитель с ромбом */
.print-ad-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  width: min(440px, 80vw);
  color: #c9a24a;
}
.print-ad-divider i {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(201, 162, 74, 0.7), transparent);
}
.print-ad-divider span {
  font-size: 13px;
  opacity: 0.9;
}
/* Слайды преимуществ */
.print-ad-slides {
  position: relative;
  z-index: 2;
  width: min(560px, 90vw);
  height: 132px;
}
.print-ad-slide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 20px 24px 20px 22px;
  border-radius: 18px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.03));
  border: 1px solid rgba(201, 162, 74, 0.22);
  box-shadow:
    0 18px 40px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(10px);
  opacity: 0;
  transform: translateY(16px) scale(0.97);
  transition:
    opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
.print-ad-slide::before {
  content: '';
  position: absolute;
  left: 0;
  top: 16px;
  bottom: 16px;
  width: 3px;
  border-radius: 3px;
  background: linear-gradient(180deg, #f4e2ad, #c9970f);
}
.print-ad-slide.active {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.print-ad-slide .pas-ico {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 30px;
  background: radial-gradient(
    circle at 35% 30%,
    rgba(233, 196, 106, 0.28),
    rgba(233, 196, 106, 0.06)
  );
  border: 1px solid rgba(233, 196, 106, 0.4);
  box-shadow: inset 0 0 14px rgba(233, 196, 106, 0.15);
}
.print-ad-slide .pas-txt b {
  display: block;
  font-size: 19px;
  font-weight: 700;
  color: #fff;
  margin-bottom: 4px;
}
.print-ad-slide .pas-txt span {
  font-size: 14px;
  color: #c3ceda;
  line-height: 1.4;
}
.print-ad-dots {
  display: flex;
  gap: 7px;
  z-index: 2;
}
.print-ad-dots i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
  transition: all 0.3s ease;
}
.print-ad-dots i.on {
  background: #e9c46a;
  width: 20px;
  border-radius: 4px;
}
/* Прогресс генерации */
.print-ad-progress {
  z-index: 2;
  width: min(560px, 90vw);
  text-align: center;
}
/* Золотые частицы (боке) */
.print-ad-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 1;
}
.print-ad-particles i {
  position: absolute;
  width: var(--s, 3px);
  height: var(--s, 3px);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(244, 226, 173, 0.95), rgba(233, 196, 106, 0));
  animation: padParticle linear infinite;
  opacity: 0;
}
@keyframes padParticle {
  0% {
    transform: translateY(24px) scale(0.5);
    opacity: 0;
  }
  25% {
    opacity: 0.9;
  }
  75% {
    opacity: 0.6;
  }
  100% {
    transform: translateY(-46px) scale(1.15);
    opacity: 0;
  }
}
.print-ad-bar {
  height: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  overflow: hidden;
  margin-bottom: 12px;
  box-shadow: inset 0 0 0 1px rgba(201, 162, 74, 0.14);
}
.print-ad-bar i {
  display: block;
  height: 100%;
  width: 34%;
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    transparent,
    #e9c46a 30%,
    #fff6df 50%,
    #e9c46a 70%,
    transparent
  );
  box-shadow: 0 0 12px rgba(233, 196, 106, 0.6);
  animation: padBar 1.5s ease-in-out infinite;
}
@keyframes padBar {
  0% {
    margin-left: -32%;
  }
  100% {
    margin-left: 102%;
  }
}
.print-ad-status {
  font-size: 14px;
  color: #cdd6e2;
  min-height: 18px;
  letter-spacing: 0.01em;
}
.print-ad-skip {
  position: absolute;
  top: 20px;
  right: 22px;
  z-index: 3;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: #e6ecf3;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.2s ease;
}
.print-ad-skip:hover {
  background: rgba(255, 255, 255, 0.16);
}
.print-ad-foot {
  z-index: 2;
  font-size: 13px;
  color: #8ea0b8;
  letter-spacing: 0.03em;
}
.print-ad-foot b {
  color: #e9c46a;
}
@media (prefers-reduced-motion: reduce) {
  .print-ad-bg span,
  .print-ad-logo,
  .print-ad-bar i {
    animation: none;
  }
}

/* Студия — превью результата генерации (рубашка + лица) */
.studio-result {
  display: none;
  margin-top: 10px;
}
.studio-result.show {
  display: block;
  animation: studioResIn 0.4s ease;
}
@keyframes studioResIn {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.studio-result-h {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 8px;
}
.studio-result-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 7px;
  margin-bottom: 10px;
}
.studio-result-grid figure {
  margin: 0;
  text-align: center;
}
.studio-result-grid img {
  width: 100%;
  aspect-ratio: 5 / 7;
  object-fit: contain;
  border-radius: 6px;
  background: var(--bg-tertiary, #1a1d24);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
}
.studio-result-grid figcaption {
  font-size: var(--fs-2xs);
  color: var(--text-secondary);
  margin-top: 3px;
}
@media (max-width: 560px) {
  .studio-result-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Состояние AI-пресет-чипов во время генерации (обратная связь + защита от дребезга) */
.seg-chip:disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}
.seg-chip.busy {
  opacity: 0.9;
  border-color: var(--accent);
  animation: chipBusyPulse 1s ease-in-out infinite;
}
@keyframes chipBusyPulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(201, 162, 74, 0.35);
  }
  50% {
    box-shadow: 0 0 0 4px rgba(201, 162, 74, 0);
  }
}

/* ===== Профессиональный отчёт контроля качества (Студия, js/33) ===== */
.qc-panel {
  margin: 0 0 12px;
  padding: 14px 16px;
  border-radius: 14px;
  background:
    radial-gradient(120% 100% at 50% -20%, rgba(201, 162, 74, 0.1), transparent 60%),
    linear-gradient(165deg, var(--bg-secondary, #14161e), var(--bg-tertiary, #0f1017));
  border: 1px solid rgba(201, 162, 74, 0.28);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
.qc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}
.qc-title {
  font-size: var(--fs-sm, 13px);
  font-weight: 700;
  letter-spacing: 0.3px;
  color: var(--text-primary, #f0ead8);
}
.qc-grade {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 18px;
  font-weight: 700;
  padding: 3px 12px;
  border-radius: 999px;
  white-space: nowrap;
  color: #14161e;
}
.qc-g-aplus,
.qc-g-A {
  background: linear-gradient(160deg, #f7de95, #cfa64c);
}
.qc-g-B {
  background: linear-gradient(160deg, #a7d3f5, #5aa0dc);
}
.qc-g-C {
  background: linear-gradient(160deg, #f2d79a, #d9a94e);
}
.qc-g-D,
.qc-g-fail {
  background: linear-gradient(160deg, #f0a79e, #d05a4e);
  color: #fff;
}
.qc-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 12px;
}
.qc-badge {
  font-size: var(--fs-2xs, 11px);
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.qc-badge.ok {
  color: #7fe0a8;
  background: rgba(70, 190, 120, 0.12);
  border-color: rgba(70, 190, 120, 0.35);
}
.qc-badge.bad {
  color: #f2a29a;
  background: rgba(210, 90, 78, 0.14);
  border-color: rgba(210, 90, 78, 0.4);
}
.qc-dims {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px 16px;
}
@media (max-width: 560px) {
  .qc-dims {
    grid-template-columns: 1fr;
  }
}
.qc-dim {
  display: grid;
  grid-template-columns: 92px 1fr 26px;
  align-items: center;
  gap: 8px;
}
.qc-dl {
  font-size: var(--fs-2xs, 11px);
  color: var(--text-secondary, #9fb0c8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.qc-bar {
  height: 6px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.qc-bar > i {
  display: block;
  height: 100%;
  border-radius: 4px;
  transition: width 0.5s cubic-bezier(0.3, 0.7, 0.3, 1);
}
.qc-bar > i.hi {
  background: linear-gradient(90deg, #46be78, #7fe0a8);
}
.qc-bar > i.ok {
  background: linear-gradient(90deg, #5aa0dc, #a7d3f5);
}
.qc-bar > i.mid {
  background: linear-gradient(90deg, #d9a94e, #f2d79a);
}
.qc-bar > i.low {
  background: linear-gradient(90deg, #d05a4e, #f0a79e);
}
.qc-dv {
  font-size: var(--fs-2xs, 11px);
  font-variant-numeric: tabular-nums;
  color: var(--text-primary, #f0ead8);
  text-align: right;
}
.qc-line {
  margin-top: 10px;
  font-size: var(--fs-2xs, 11px);
  line-height: 1.5;
}
.qc-str {
  color: #8fdcac;
}
.qc-iss {
  color: #e9c877;
}
.qc-fail {
  color: #f2a29a;
  font-weight: 600;
}

/* ═══════════════════════════════════════════════════════════════════════
   ПРЕМИУМ-ИНСПЕКТОР (правое меню): слайдеры с заливкой, графические кнопки,
   крупные степперы −/+, премиум-подсказки. Токены дизайн-системы КАРТ РЕГИОН.
   ═══════════════════════════════════════════════════════════════════════ */

/* — Слайдер: ЗАЛИВКА трека до бегунка (--fill из createSlider) + глубина — */
.slider-group input[type='range'] {
  height: 6px;
  border-radius: var(--radius-pill);
  background: linear-gradient(
    to right,
    var(--accent) 0%,
    var(--accent) var(--fill, 0%),
    var(--bg-active) var(--fill, 0%),
    var(--bg-active) 100%
  );
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}
.slider-group input[type='range']::-webkit-slider-thumb {
  width: 17px;
  height: 17px;
  background: radial-gradient(circle at 35% 30%, #ffffff 0%, var(--accent) 58%);
  border: 2px solid var(--bg-secondary);
  box-shadow:
    0 2px 7px rgba(0, 0, 0, 0.55),
    0 0 0 1px var(--accent);
}
.slider-group input[type='range']::-webkit-slider-thumb:hover {
  transform: scale(1.18);
  background: radial-gradient(circle at 35% 30%, #ffffff 0%, var(--accent-hover) 58%);
}
.slider-group input[type='range']::-moz-range-thumb {
  width: 17px;
  height: 17px;
  background: radial-gradient(circle at 35% 30%, #ffffff 0%, var(--accent) 58%);
  border: 2px solid var(--bg-secondary);
  box-shadow: 0 2px 7px rgba(0, 0, 0, 0.55);
}

/* — Степперы −/+ : премиум (объём, крупная читаемая глифа) — */
.slider-valwrap {
  gap: 3px;
}
.slider-step {
  width: 28px;
  height: 26px;
  font-size: var(--fs-lg);
  background: linear-gradient(180deg, var(--bg-hover), var(--bg-tertiary));
  box-shadow: var(--shadow-sm);
}
.slider-step:hover {
  background: linear-gradient(180deg, var(--accent-dim), var(--bg-hover));
  border-color: var(--accent);
  color: var(--accent);
}
.slider-step:disabled,
.slider-step.disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}
.seg-chip:disabled,
.seg-chip.disabled {
  opacity: 0.42;
  cursor: not-allowed;
  pointer-events: none;
}
.slider-label-value {
  width: 48px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
}
.slider-label-value:focus {
  border-color: var(--accent);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.3),
    0 0 0 3px var(--accent-dim);
}

/* — ГРАФИЧЕСКАЯ кнопка действия .btn-soft: объём, иконка+текст, hover-подъём — */
.btn-soft {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 12px;
  min-height: 40px;
  border-radius: var(--radius-md);
  background: linear-gradient(180deg, var(--bg-hover), var(--bg-tertiary));
  box-shadow: var(--shadow-sm);
  font-weight: var(--fw-semibold);
  transition:
    transform 0.12s ease,
    border-color 0.15s ease,
    background 0.15s ease,
    box-shadow 0.18s ease,
    color 0.15s ease;
}
.btn-soft:hover {
  transform: translateY(-1px);
  border-color: var(--accent);
  color: var(--text-primary);
  background: linear-gradient(180deg, var(--accent-dim), var(--bg-hover));
  box-shadow: var(--shadow-md);
}
.btn-soft:active {
  transform: translateY(0) scale(0.985);
  box-shadow: var(--shadow-sm);
}
.btn-soft svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

/* — ТЕХНИЧЕСКАЯ ИНФО-ПАНЕЛЬ (технический вид): палитра/логотип/формат — */
/* ── ТЕХПАСПОРТ МАКЕТА — стеклянная плашка над картой (технический вид).
   Каждый параметр — кликабельный чип «подпись + значение» (переход к слою). ── */
.tech-info {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  width: max-content;
  max-width: min(94%, 1040px);
  padding: 5px 8px;
  border-radius: var(--radius-lg);
  border: 1px solid color-mix(in srgb, var(--border-light) 72%, transparent);
  background: color-mix(in srgb, var(--bg-secondary) 84%, transparent);
  backdrop-filter: blur(16px) saturate(140%);
  box-shadow:
    var(--shadow-md),
    inset 0 1px 0 color-mix(in srgb, #fff 8%, transparent);
  animation: ti-in 0.32s cubic-bezier(0.22, 1, 0.36, 1) both;
  user-select: none;
}
@keyframes ti-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
.tech-info .ti-brand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px 0 6px;
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
}
.tech-info .ti-brand-ico {
  display: inline-flex;
  width: 13px;
  height: 13px;
  color: var(--accent);
}
.tech-info .ti-brand-ico svg {
  width: 100%;
  height: 100%;
}
/* Бейдж охвата: в виде лица панель честно говорит, что описывает рубашку. */
.tech-info .ti-brand-scope {
  margin-left: 6px;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  background: var(--accent-dim);
  color: var(--accent);
  letter-spacing: 0.06em;
}
/* Режим контактного листа (Все стороны/Вся колода): renderAllNow выходит рано и
   updateTrimCallouts не вызывается — гасим сноски и техпаспорт по data-view,
   иначе их невидимые кнопки остаются в Tab-порядке ПОД листом. */
#canvas-area[data-view='all'] .trim-callouts,
#canvas-area[data-view='all'] .tech-info {
  display: none !important;
}
.tech-info .ti-sep {
  width: 1px;
  margin: 4px 1px;
  background: color-mix(in srgb, var(--border) 80%, transparent);
}
.tech-info .ti-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 40px;
  padding: 4px 11px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-2xs);
  cursor: pointer;
  white-space: nowrap;
  animation: ti-chip-in 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: var(--d, 0ms);
  transition:
    background 0.16s ease,
    border-color 0.16s ease,
    transform 0.16s ease,
    box-shadow 0.16s ease;
}
@keyframes ti-chip-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
/* Чипы техпанели: в покое плоские, рельеф появляется под курсором. Панель узкая, чипов в ней
   до восьми в один ряд — выпуклые поштучно они слились бы в рябь; тот же довод, что у строк
   слоёв и строк палитры команд. */
.tech-info .ti-chip:hover {
  background: var(--accent-dim);
  border-color: transparent;
  transform: translateY(-1px);
  box-shadow: var(--nm-out-xs);
}
.tech-info .ti-chip:active {
  transform: translateY(0) scale(0.97);
  box-shadow: var(--nm-in-sm);
}
.tech-info .ti-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.tech-info .ti-chip.ti-flash {
  animation: ti-flash 0.5s ease;
}
@keyframes ti-flash {
  0% {
    background: var(--accent);
    border-color: var(--accent);
  }
  100% {
    background: var(--accent-dim);
    border-color: transparent;
  }
}
.tech-info .ti-chip-ico {
  display: inline-flex;
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  color: var(--text-muted);
  transition: color 0.16s ease;
}
.tech-info .ti-chip:hover .ti-chip-ico {
  color: var(--accent);
}
.tech-info .ti-chip-ico svg {
  width: 100%;
  height: 100%;
}
.tech-info .ti-chip-body {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  line-height: var(--lh-tight);
}
.tech-info .ti-chip-k {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.tech-info .ti-chip-v {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.tech-info .ti-chip-v small {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-regular);
  color: var(--text-muted);
}
.tech-info .ti-chip.is-off .ti-chip-v {
  font-weight: var(--fw-regular);
  color: var(--text-muted);
}
.tech-info .ti-sw {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 4px;
  border: 1px solid var(--border-light);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
.tech-info .ti-logo-img {
  width: 16px;
  height: 16px;
  object-fit: contain;
  border-radius: 3px;
  border: 1px solid var(--border);
  background: #fff;
}
/* Меню размеров карты (чип «Формат»): мини-превью пропорций формата */
.ti-size-menu .ti-size-thumb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  color: var(--accent);
}
.ti-size-menu .ti-size-thumb i {
  display: block;
  border: 1.5px solid currentColor;
  border-radius: 2px;
  opacity: 0.85;
}
.ti-size-menu .ti-size-custom {
  font-style: normal;
  font-size: 13px;
}
@media (prefers-reduced-motion: reduce) {
  .tech-info,
  .tech-info .ti-chip {
    animation: none;
  }
  .tech-info .ti-chip:hover {
    transform: none;
  }
}

/* — Кнопки с SVG-иконкой (единый графический язык вместо emoji) — */
.btn-iconed {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 32px; /* гарантированная кликабельная зона даже вне .btn-soft */
}
.btn-iconed svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}
.btn-iconed .btn-ic-label {
  min-width: 0;
}

/* — Чипы БЫСТРЫХ ЗНАЧЕНИЙ под слайдером (S/M/L и т.п.) — */
.slider-presets {
  display: flex;
  gap: var(--sp-1);
  margin-top: 7px;
}
.slider-preset-chip {
  flex: 1 1 0;
  min-height: 26px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg-tertiary);
  color: var(--text-secondary); /* AA-контраст (был --text-muted ~3:1) */
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  cursor: pointer;
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    color 0.14s ease,
    transform 0.08s ease;
}
.slider-preset-chip:disabled,
.slider-preset-chip.disabled {
  opacity: 0.42;
  cursor: not-allowed;
  pointer-events: none;
}
.slider-preset-chip:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--bg-hover);
}
.slider-preset-chip:active {
  transform: scale(0.94);
}
.slider-preset-chip.active {
  border-color: var(--accent);
  background: var(--accent-dim);
  color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* — Премиум-подсказка ⓘ: чипс-триггер тултипа — */
.hint-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-left: 6px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-light);
  font-size: var(--fs-3xs);
  font-style: normal;
  color: var(--text-muted);
  opacity: 0.85;
  transition:
    color 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease;
}
.hint-info:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-dim);
  opacity: 1;
}

/* ═══ СЛАЙД-ШОУ КОЛОДЫ (E-336) ═══════════════════════════════════════════════════════════
   Витрина работы: колода крупно, в движении, без интерфейса. Фон намеренно ГЛУБОКИЙ и
   нейтральный в обеих темах — карты печатаются на белой бумаге, и любой цветной подмес
   врал бы о том, как они будут выглядеть. Виньетка не для красоты: она уводит взгляд от
   краёв экрана к картам. */
.slideshow {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: grid;
  place-items: center;
  background:
    radial-gradient(ellipse at 50% 45%, rgba(30, 34, 44, 0.86) 0%, rgba(9, 11, 16, 0.97) 70%),
    #06070a;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.45s ease,
    visibility 0.45s;
  cursor: none; /* курсор прячем: любое его движение и так закрывает показ */
}
.slideshow.on {
  opacity: 1;
  visibility: visible;
}
.ss-stage {
  position: relative;
  width: min(92vw, 1100px);
  height: min(76vh, 720px);
  transform-style: preserve-3d;
  perspective: 1600px;
}
/* Карта: положение задаётся переменными из сцены — так одна анимация обслуживает все
   раскладки, и добавление новой не требует нового ключевого кадра. */
.ss-card {
  position: absolute;
  left: 50%;
  top: 50%;
  height: 74%;
  width: auto;
  margin: 0;
  border-radius: 14px;
  box-shadow:
    0 30px 60px rgba(0, 0, 0, 0.55),
    0 2px 8px rgba(0, 0, 0, 0.4);
  transform-origin: 50% 60%;
  will-change: transform, opacity;
  animation: ss-in 1s cubic-bezier(0.16, 0.84, 0.36, 1) both;
  /* Медленное дыхание после входа: статичная картинка на экране читается как зависшая. */
  transform: translate3d(calc(-50% + var(--x, 0px)), calc(-50% + var(--y, 0px)), var(--z, 0px))
    rotate(var(--rot, 0deg)) rotateY(var(--tilt, 0deg)) scale(var(--scale, 1));
}
@keyframes ss-in {
  from {
    opacity: 0;
    transform: translate3d(calc(-50% + var(--x, 0px)), calc(-50% + var(--y, 0px) + 90px), -320px)
      rotate(calc(var(--rot, 0deg) * 2.4)) rotateY(calc(var(--tilt, 0deg) - 30deg))
      scale(calc(var(--scale, 1) * 0.82));
  }
  to {
    opacity: 1;
    transform: translate3d(calc(-50% + var(--x, 0px)), calc(-50% + var(--y, 0px)), var(--z, 0px))
      rotate(var(--rot, 0deg)) rotateY(var(--tilt, 0deg)) scale(var(--scale, 1));
  }
}
.ss-card.leaving {
  animation: ss-out 0.85s cubic-bezier(0.4, 0, 0.7, 0.2) both;
  pointer-events: none;
}
@keyframes ss-out {
  to {
    opacity: 0;
    transform: translate3d(calc(-50% + var(--x, 0px)), calc(-50% + var(--y, 0px) - 70px), 220px)
      rotate(calc(var(--rot, 0deg) * 0.4)) rotateY(calc(var(--tilt, 0deg) + 22deg))
      scale(calc(var(--scale, 1) * 1.06));
  }
}
.ss-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6vh;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 13px;
  letter-spacing: 0.02em;
  transition: opacity 1.2s ease;
}
.ss-hint.fade {
  opacity: 0;
}
body.slideshow-on {
  overflow: hidden;
}
/* Бережный режим: показ остаётся (это витрина, а не украшение), но карты только проявляются
   и гаснут — без полёта, поворотов и глубины. */
.slideshow.reduced .ss-card,
.slideshow.reduced .ss-card.leaving {
  animation: ss-fade 0.6s ease both;
}
@keyframes ss-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ss-card,
  .ss-card.leaving {
    animation: ss-fade 0.6s ease both;
  }
}
/* Кнопка показа на плашке масштаба — видна всегда, в отличие от 3D и переворота: показ
   уместен и на одной карте, и в обзоре колоды (там он даже нагляднее). */
.zc-show.is-on {
  color: var(--accent);
}

/* ═══ ПОКАЗ: СТОЛ, СВЕТ И ПОДПИСИ (E-337) ════════════════════════════════════════════════
   Заказчик: «должно быть очень премиальным и информативным, красивым с точки зрения дизайна
   и просмотра готового макета, как будто в карты играют».
   Премиальность здесь — не украшения поверх, а три вещи, которые делают сцену сценой:
   направленный свет (глаз читает объём), опора под картами (они лежат, а не висят в пустоте)
   и спокойная типографика подписи (карта главная, текст служебный). */
.ss-felt {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(
      ellipse 60% 45% at 50% 22%,
      rgba(255, 246, 224, 0.09) 0%,
      rgba(255, 246, 224, 0) 62%
    ),
    radial-gradient(ellipse 42% 16% at 50% 74%, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0) 70%);
}
/* Блик по карте: узкая мягкая полоса «от лампы». Смешивание overlay, чтобы блик подчинялся
   рисунку карты, а не забеливал его — иначе тёмные рубашки выцветают. */
.ss-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(
    118deg,
    rgba(255, 255, 255, 0.16) 0%,
    rgba(255, 255, 255, 0) 34%,
    rgba(255, 255, 255, 0) 66%,
    rgba(255, 255, 255, 0.07) 100%
  );
  mix-blend-mode: overlay;
  pointer-events: none;
}
.ss-card {
  outline: 1px solid rgba(255, 255, 255, 0.06); /* кромка листа: без неё карта «тонет» в фоне */
  outline-offset: -1px;
}
.ss-card.is-hero {
  box-shadow:
    0 42px 80px rgba(0, 0, 0, 0.62),
    0 4px 14px rgba(0, 0, 0, 0.45);
}
/* Подпись: имя карты словами. Не заголовок и не ярлык — служебная строка, которая отвечает
   на «что я вижу», не отвлекая от самой карты. */
.ss-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 13vh;
  text-align: center;
  color: rgba(255, 255, 255, 0.82);
  font-size: clamp(15px, 1.5vw, 21px);
  letter-spacing: 0.06em;
  opacity: 0;
  transform: translateY(8px);
}
.ss-caption.show {
  animation: ss-cap 0.7s ease 0.25s both;
}
@keyframes ss-cap {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.ss-cap-sign {
  margin-left: 0.45em;
  font-size: 1.15em;
  color: rgba(255, 255, 255, 0.9);
}
.ss-cap-sign.red {
  color: #e0555f;
}
/* Счётчик отснятого: колода снимается на ходу, и человек вправе видеть, что показ ещё
   наполняется, а не «застрял» на десятке карт. Когда всё снято — тихо гаснет. */
.ss-progress {
  position: absolute;
  right: 3vw;
  bottom: 3.4vh;
  color: rgba(255, 255, 255, 0.32);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  opacity: 0;
  transition: opacity 0.5s ease;
}
.ss-progress.loading {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .ss-caption.show {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* E-340. Погашенный контрол: место занято, управление недоступно.
   Заведено потому, что исчезающий контрол СДВИГАЕТ соседей — и кнопка, которой человек
   только что пользовался, уезжает из-под курсора. Пустое место дешевле прыжка: промахнуться
   мимо кнопки хуже, чем увидеть неактивный ползунок, который вдобавок объясняет, чего не
   хватает (подсказка на самом элементе). */
.ctl-disabled {
  opacity: 0.4;
  pointer-events: none;
  filter: grayscale(0.4);
}

/* ===== ЖИВАЯ ПОДСКАЗКА СМЫСЛА (js/45-motion-hints.js, задача 2.4а) =====
   Слой абсолютный и НЕ участвует в потоке: подсказка не имеет права двигать вёрстку — иначе
   контрол уедет из-под курсора ровно в тот момент, когда его тянут (этот дефект в проекте уже
   был, E-340). pointer-events:none — не перехватывает ни мышь, ни клавиатуру: подсказка
   объясняет, а не мешает работать. Цвета — только токены, иначе светлая тема выцветает. */
#motion-hint-layer {
  position: fixed;
  z-index: 400;
  width: 56px;
  height: 56px;
  pointer-events: none;
  color: var(--accent);
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(0.94);
  transition:
    opacity 0.14s ease,
    transform 0.14s ease;
}
#motion-hint-layer.visible {
  opacity: 1;
  transform: scale(1);
}
/* Системный запрет анимаций уважаем дважды: модуль отдаёт статичную схему вместо движения,
   а здесь гасим и собственное появление слоя. */
@media (prefers-reduced-motion: reduce) {
  #motion-hint-layer {
    transition: none;
  }
}

/* ═══ ВЕРДИКТ КОНТРОЛЯ КАЧЕСТВА (п. 2.7) ═══════════════════════════════════════════════════
   Разбор оценки после генерации: балл, разбивка по измерениям, за что снято.
   Цвета — ТОЛЬКО токенами: хардкод фона ломает светлую тему (правило проекта). */
.qcv-overlay {
  position: fixed;
  inset: 0;
  z-index: 10050;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-primary) 72%, transparent);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.18s ease;
}
.qcv-overlay.visible {
  opacity: 1;
}
.qcv-sheet {
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  position: relative;
  padding: 20px 22px 18px;
  background: var(--bg-secondary);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: var(--radius-lg, 14px);
  box-shadow: var(--shadow-lg, 0 18px 48px rgba(0, 0, 0, 0.45));
  transform: translateY(8px) scale(0.985);
  transition:
    transform 0.22s cubic-bezier(0.2, 0.9, 0.3, 1.2),
    opacity 0.18s ease;
}
.qcv-overlay.visible .qcv-sheet {
  transform: none;
}
.qcv-close {
  position: absolute;
  top: 10px;
  right: 12px;
  background: none;
  border: 0;
  color: var(--text-muted);
  font-size: 15px;
  cursor: pointer;
  line-height: 1;
  padding: 4px;
}
.qcv-close:hover {
  color: var(--text-primary);
}
.qcv-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 6px;
}
.qcv-num {
  font-size: 44px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.qcv-of {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.qcv-grade {
  margin-left: auto;
  padding: 3px 12px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 13px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
}
.qcv-grade.fail {
  background: rgba(226, 96, 96, 0.16);
  color: #e26060;
  border-color: rgba(226, 96, 96, 0.42);
}
.qcv-say {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  line-height: 1.5;
  margin: 4px 0 14px;
}
.qcv-say b {
  color: var(--text-primary);
}
.qcv-rows {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.qcv-row {
  display: grid;
  grid-template-columns: 116px 1fr 52px;
  align-items: center;
  gap: 9px;
  font-size: 12px;
}
.qcv-name {
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.qcv-track {
  height: 7px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--text-muted) 22%, transparent);
  overflow: hidden;
}
.qcv-track > i {
  display: block;
  height: 100%;
  border-radius: 4px;
  /* Шкалы наполняются только когда оверлей объявил «поехали» (js/47). Ширину несёт переменная
     --w из разметки: инлайновый width перебил бы правило и шкала стояла бы заполненной с
     первого кадра — анимации не было бы, а проба, спрашивающая «класс появился», этого бы не
     заметила. */
  width: 0;
  transition: width 0.7s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.qcv-run .qcv-track > i,
.qcv-done .qcv-track > i {
  width: var(--w, 0);
}
.qcv-track > i.hi {
  background: #5fc98a;
}
.qcv-track > i.ok {
  background: var(--accent);
}
.qcv-track > i.mid {
  background: #e0b44c;
}
.qcv-track > i.low {
  background: #e26060;
}
.qcv-pts {
  text-align: right;
  color: var(--text-primary);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.qcv-pts small {
  color: var(--text-muted);
  font-weight: 500;
}
.qcv-penalty {
  margin-top: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 12px;
  background: rgba(226, 96, 96, 0.12);
  border: 1px solid rgba(226, 96, 96, 0.3);
  color: var(--text-primary);
}
.qcv-block {
  margin-top: 14px;
}
.qcv-block h4 {
  margin: 0 0 5px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
.qcv-block ul {
  margin: 0;
  padding-left: 17px;
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.qcv-block.bad li {
  color: #e26060;
}
.qcv-block.good li {
  color: #5fc98a;
}
@media (prefers-reduced-motion: reduce) {
  .qcv-track > i {
    transition: none;
  }
  .qcv-sheet {
    transition: none;
  }
}

/* ═══ ОКНО ОСМОТРА «УЛУЧШИТЬ КОЛОДУ» (п. 4.5) ═════════════════════════════════════════════
   Цвета — только токенами: хардкод фона ломает светлую тему (правило проекта). */
.imp-overlay {
  position: fixed;
  inset: 0;
  z-index: 10060;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--bg-primary) 74%, transparent);
  backdrop-filter: blur(3px);
}
.imp-sheet {
  position: relative;
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  padding: 20px 22px 18px;
  /* Тот же материал, что у окна диалога и окна студии (волна 3): рельеф — из чего сделано,
     отброшенная тень — что поверх всего. Акцентная кайма снята: её роль (это важное окно)
     теперь выполняет глубина, а кайма спорила с рельефом за одну и ту же границу. */
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out), var(--shadow-lg);
}
.imp-close {
  position: absolute;
  top: 10px;
  right: 12px;
  background: none;
  border: 0;
  color: var(--text-muted);
  font-size: 15px;
  cursor: pointer;
  padding: 4px;
}
.imp-close:hover {
  color: var(--text-primary);
  box-shadow: var(--nm-out-xs);
  border-radius: var(--nm-radius);
}
.imp-close:active {
  box-shadow: var(--nm-in-sm);
}
.imp-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 14px;
  font-size: var(--fs-md);
  color: var(--text-primary);
}
.imp-sub {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.imp-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Строка находки — УТОПЛЕННАЯ ячейка списка: в ней галочка, и перечень читается как список
   отмеченного, а не как ряд кнопок. Под курсором подсвечивается кольцом акцента. */
.imp-item {
  display: flex;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: box-shadow var(--nm-ease);
}
.imp-item:hover {
  border-color: transparent;
  box-shadow:
    var(--nm-in-sm),
    0 0 0 1px var(--accent-dim);
}
.imp-check {
  margin-top: 3px;
  accent-color: var(--accent);
  flex: none;
}
.imp-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.imp-title {
  font-size: var(--fs-sm);
  color: var(--text-primary);
  font-weight: var(--fw-semibold, 600);
}
.imp-why {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  line-height: 1.45;
}
.imp-num {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.imp-partial {
  margin-left: 8px;
  font-size: 10px;
  font-weight: 500;
  color: #e0b44c;
  white-space: nowrap;
}
.imp-frames {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
}
.imp-frames figure {
  margin: 0;
  text-align: center;
}
.imp-frames img {
  display: block;
  width: 74px;
  border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--text-muted) 30%, transparent);
}
.imp-frames figcaption {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 3px;
}
.imp-arrow {
  color: var(--text-muted);
}
.imp-foot {
  margin-top: 14px;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.imp-empty {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  text-align: center;
  padding: 18px 8px 10px;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}
.imp-empty b {
  color: var(--text-primary);
}
.imp-ok {
  font-size: 26px;
  color: #5fc98a;
}
.imp-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
/* «Применить» — выдавленная кнопка с акцентной заливкой: она главное действие окна, и
   заливку у неё не отнимаем, а рельеф добавляет ей осязаемость нажатия. */
.imp-apply {
  padding: 8px 16px;
  border-radius: var(--nm-radius);
  border: 1px solid transparent;
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold, 600);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
.imp-apply:active {
  box-shadow: var(--nm-in-sm);
}
.imp-apply:hover {
  background: color-mix(in srgb, var(--accent) 34%, transparent);
}
.imp-note,
.imp-result {
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.imp-result {
  color: var(--text-secondary);
}

/* ═══ ДВЕ ОСИ ОХВАТА — ДВА РЯДА (концепция «Приборная доска», шаг 1) ══════════════════════
   Подпись слева говорит, ЧТО выбирает ряд: раньше семь одинаковых пилюль стояли вместе и
   делали три разные вещи. */
.scope-axis {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.scope-axis-label {
  flex: none;
  width: 58px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  user-select: none;
}
.scope-axis .scope-seg {
  flex: 1;
  min-width: 0;
}

/* ═══ СТРОКА СЛОЯ — ПРИБОР СО ЗНАЧЕНИЕМ (шаг 3) ══════════════════════════════════════════
   Панель была плотной, но немой: «Узор» не говорил, какой узор. Значение занимает правый
   край строки и НЕ отнимает место у имени — оно сжимается первым. */
/* ЗНАЧЕНИЕ УСТУПАЕТ МЕСТО НАЗВАНИЮ (жалоба заказчика 2026-08-21: «слой центр карты слева не
   прочитать — только „Центр к" и дальше продолжение»).
   Замер: обрезаны 5 имён из 11 — «Центр карты» (нужно 88 px, дано 76), «Рамка лица» (80/62),
   «Значки масти (пипсы) / Фигура» (217/96), «Индексы / уголки» (121/117), «Угловые орнаменты»
   (140/121). Причина — flex:none у значения: оно забирало до 46 % строки и не ужималось вовсе,
   а имя доедало остаток.
   Правило то же, что у бейджа охвата в заголовке секции (E-339): ради НАЗВАНИЯ строку и читают,
   служебное значение вторично — ему и уступать. Значение не исчезает: ужимается многоточием,
   полный текст остаётся в подсказке строки. */
.layer-value {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 46%;
  font-size: 10px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* На ВЫБРАННОЙ строке подложка светлее (--accent-dim), и тот же тихий токен проваливается:
   замер жалобы 2026-08-13 дал «classic» 3.85:1 в тёмной теме и 4.05:1 в светлой при норме 4.5
   (шрифт 10px — послаблением для крупного текста не прикрыться). Токен цвета зависит не только
   от себя, но и от того, на чём лежит. */
.layer-item.active .layer-value {
  color: var(--text-secondary);
}
.layer-swatch {
  width: 11px;
  height: 11px;
  border-radius: 3px;
  flex: none;
  border: 1px solid color-mix(in srgb, var(--text-muted) 45%, transparent);
}
.layer-item .layer-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Сторона в заголовке списка слоёв (шаг 4): списки рубашки и лица разные и подменялись молча. */
.region-header-sub {
  margin-left: 6px;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-muted);
}

/* ═══ ПОДПИСЬ КОРОТКОГО ПУТИ ПОД ЛИСТОМ (шаг 6) ══════════════════════════════════════════
   Бросок фото на плитку существовал давно, но узнать о нём было неоткуда. Подпись стоит В
   ПОТОКЕ под сеткой: накладкой она перекрывала бы карты — ровно та ошибка, из-за которой
   плашка «Колода готова» закрывала первый ряд. Кликов не ловит: иначе съедала бы бросок
   файла у карты под собой. Видна только в обзоре колоды — на одиночной карте бросать некуда. */
/* Постоянной строки-подсказки над листом больше нет: знание живёт в «Советах» (js/49). */

/* ═══ КАТАЛОГ НАБОРОВ ЗНАЧКОВ МАСТИ (волна 4) ═══
   Карточка показывает ВСЕ ЧЕТЫРЕ значка набора: в этом и смысл набора — четыре масти одного
   стиля. Показывать один значок значило бы скрыть главное. Цвета — только токенами, иначе
   светлая тема ломается. */
.pip-set-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin: 6px 0 10px;
}
.pip-set-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 4px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  cursor: pointer;
  transition: border-color 0.15s;
}
.pip-set-card:hover {
  border-color: var(--accent);
}
.pip-set-card.active {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent) inset;
}
.pip-set-row {
  display: flex;
  gap: 3px;
  align-items: center;
  justify-content: center;
}
.pip-set-row img {
  width: 22px;
  height: 22px;
  object-fit: contain;
}
.pip-set-name {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  text-align: center;
  line-height: 1.2;
}

/* Меню «Вид» → выбор простоя перед автозапуском показа колоды. */
.view-menu .view-idle-row {
  display: flex;
  gap: 4px;
  padding: 2px 10px 8px;
}
.view-menu .view-idle {
  flex: 1;
  padding: 5px 0;
  font-size: 11px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.view-menu .view-idle:hover {
  border-color: var(--accent, #4a9eff);
  color: var(--text-primary);
}
.view-menu .view-idle.active {
  background: var(--accent, #4a9eff);
  border-color: var(--accent, #4a9eff);
  /* Было `#fff`, и на светло-голубом акценте тёмной темы это давало 2.16:1 — надпись «1 мин»
     сливалась с подложкой. Цвет текста поверх акцента решает тема, а не это правило. */
  color: var(--on-accent, #0e1c26);
}

/* Меню «Лицо» → показать одну масть (13 карт). */
.face-quick-suitgroups {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  padding: 2px 10px 8px;
}
.face-quick-suit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 7px 2px 6px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  color: var(--text-primary);
  cursor: pointer;
}
.face-quick-suit:hover {
  border-color: var(--accent, #4a9eff);
}
.face-quick-suit .fqs-sym {
  font-size: 18px;
  line-height: 1;
}
.face-quick-suit.red .fqs-sym {
  color: #d8384a;
}
.face-quick-suit .fqs-lb {
  font-size: 10px;
  color: var(--text-secondary);
}

/* ═══ СОВЕТЫ (js/49) ═══
   Дом для подсказок: кнопка в верхней панели, панель со списком, микро-иллюстрация и прицел.
   ВСЕ анимации — transform/opacity: главный поток при сборке листа занят задачами по 708 мс,
   и всё, что считается в нём, замирает (урок оплачен дважды — полоса прогресса и заставка). */
#btn-tips {
  position: relative;
}
#btn-tips.has-unread::after {
  content: '';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--bg-secondary);
}
/* ═══ ПАНЕЛЬ СОВЕТОВ — НЕОМОРФИЗМ (просьба заказчика 2026-08-19) ═══════════════════════════
   «Панель нужно подвинуть редизайну и сделать наш новый неоморфизм, вместе с анимацией,
   которая тоже должна поддерживать этот дизайн».

   МАТЕРИАЛ ТОТ ЖЕ, ЧТО У МЕНЮ ТУЛБАРА (.nm-dropdown) и поповера полки: ниша, а в ней выпуклые
   плашки. Своими правилами, а не общим классом: у карточки совета своя раскладка (сцена над
   текстом, кнопка снизу), общий класс пришлось бы тут же переопределять — а это худший вид
   переиспользования, когда правка одного места чинит и ломает одновременно.

   ТРИ СОСТОЯНИЯ КАРТОЧКИ. Покой ≠ наведение ≠ нажатие — то же требование, что заказчик
   предъявил меню «Создать» («не происходит ни вдавливания, ни анимации»). Карточка совета
   нажимается не как кнопка, поэтому «нажатие» здесь — у её собственной кнопки «Показать».

   ДВИЖЕНИЕ — ТОЛЬКО transform И opacity. Панель открывают во время сборки листа, а та занимает
   главный поток задачами по 700 мс: всё, что считает раскладку, замрёт и прочтётся как
   «подвисло». Этот урок оплачен дважды за один день (полоса прогресса и кольцо заставки). */
.tips-panel {
  position: fixed;
  z-index: 4000;
  width: min(380px, calc(100vw - 24px));
  padding: 10px;
  /* ПРОКРУТКА, КОГДА СОВЕТОВ БОЛЬШЕ, ЧЕМ ВЛЕЗАЕТ. Предел высоты ставит js/49 по факту (панель
     стоит под своей кнопкой, а высота тулбара меняется) — здесь только правило прокрутки.
     Без него нижние советы просто уезжали за край экрана и были недостижимы. */
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid transparent; /* место линии держит тень — габарит не прыгает между темами */
  border-radius: var(--nm-radius-lg);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-out), var(--shadow-lg);
  opacity: 0;
  /* Панель ВЫХОДИТ ИЗ СВОЕЙ КНОПКИ: чуть уменьшенная и приподнятая, разворачивается к месту.
     Это то же «движение несёт смысл», что у строк списка слоёв, — видно, откуда взялось окно. */
  transform: translateY(-8px) scale(0.98);
  transform-origin: top right;
  transition:
    opacity var(--nm-ease),
    transform var(--nm-ease);
}
.tips-panel.open {
  opacity: 1;
  transform: translateY(0) scale(1);
}
.tips-head {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  color: var(--text-muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 2px 6px 8px;
}
/* Карточка — выпуклая плашка в нише. */
.tip-item {
  display: flex;
  /* Сцена «фото на карту» занимает всю ширину карточки и стоит НАД текстом: истории с четырьмя
     участниками (папка, снимок, курсор, карта) в узкой колонке слева не разыграть. Остальные
     советы, у которых иллюстрации нет, раскладку не замечают. */
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px;
  margin-bottom: 8px;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease);
}
.tip-item:last-child {
  margin-bottom: 0;
}
/* Наведение — карточка ПОДНИМАЕТСЯ навстречу курсору: рельеф глубже, сдвиг на пиксель вверх. */
.tip-item:hover {
  box-shadow:
    var(--nm-out),
    0 0 0 1px color-mix(in srgb, var(--accent) 26%, transparent);
  transform: translateY(-1px);
}
.tip-title {
  font-weight: 700;
  margin-bottom: 3px;
  color: var(--text-primary);
}
.tip-text {
  font-size: var(--fs-sm);
  line-height: 1.45;
  color: var(--text-secondary);
}
/* Кнопка «Показать» — та же клавиша, что во всём продукте: выпуклая в покое, вдавленная при
   нажатии. Прежде она была контурной с акцентной заливкой на наведении — язык прошлого
   оформления, спорящий с соседями по экрану. */
.tip-show {
  margin-top: 10px;
  padding: 6px 14px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.tip-show:hover {
  color: var(--accent);
  box-shadow:
    var(--nm-out),
    0 0 0 1px color-mix(in srgb, var(--accent) 34%, transparent);
  transform: translateY(-1px);
}
.tip-show:active {
  box-shadow: var(--nm-in);
  transform: translateY(1px);
}
.tip-show:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Сцена лежит в НИШЕ — она показывает происходящее «внутри» продукта, и утопленная площадка
   отделяет показ от плашки совета, не заводя ни линий, ни рамок. */
.tips-panel .tip-scene {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  border-radius: var(--nm-radius);
  padding: 6px 0;
  box-sizing: border-box;
}
@media (prefers-reduced-motion: reduce) {
  .tips-panel,
  .tip-item,
  .tip-show {
    transition: none;
  }
  .tip-item:hover,
  .tip-show:hover,
  .tip-show:active {
    transform: none;
  }
}
/* Микро-иллюстрация: фотография падает на карту и «ложится» в неё. */
/* ═══ СЦЕНА «ФОТО НА КАРТУ» в панели советов (2026-08-17) ═══════════════════════════════
   Просьба заказчика: показать, как из папки вытаскивается фотография мышкой и переносится на
   туза, масть сменяется фотографией, и всё пропадает.

   ГЛАВНОЕ ПРАВИЛО ЗДЕСЬ — ТОЛЬКО transform И opacity. Оплачено заставкой (см.
   test/busy-overlay-smooth.js): сборка колоды занимает главный поток задачами по 700 мс, и
   анимация координат или размеров встаёт вместе с рендером, потому что пересчитывает раскладку
   каждый кадр. Композитор считает transform/opacity отдельно и не замирает.

   ОДИН РИТМ НА ВСЮ СЦЕНУ: 6 с, одинаковая длительность у всех участников, разные фазы внутри.
   Так «взял» и «понёс» совпадают по времени без единой строки JS — расхождение возможно только
   если кто-то поменяет длительность в одном месте из пяти, поэтому она задана переменной.

   Фазы: 0–10 покой · 10–22 фото выезжает из папки · 22–30 курсор подходит и берёт ·
   30–55 несёт к карте · 55–62 бросок, пик сменяется фотографией · 62–86 держим результат ·
   86–100 гаснет и возврат к началу. */
/* ШИРОКАЯ СЦЕНА — ТОЛЬКО В ПАНЕЛИ СОВЕТОВ (правило .tips-panel ниже). В ТОСТЕ она обязана быть
   узкой: тост стоит в углу экрана и не может занимать пол-окна. Первая редакция ставила 100 %
   всем, и в тосте текст выдавило в колонку по два слова в строке — поймано глазами на снимке
   живого показа, замеры при этом были зелёными. */
.tip-scene {
  --ритм: 6s;
  position: relative;
  flex: 0 0 64px;
  /* ШИРИНА ЗАКРЕПЛЕНА, И ЭТО НЕ ПРИДИРКА. Путь снимка задан в пикселях (иначе его не совместить
     с положением карты), а панель советов ужимается на узких экранах: min(380px, 100vw - 24px).
     На телефоне снимок улетал бы мимо карты за край сцены. Фиксируем внутреннюю ширину и
     центрируем — тогда координаты участников постоянны на любом экране. */
  width: 64px;
  height: 78px;
  overflow: hidden;
  margin: 0 0 8px;
  color: var(--text-secondary);
}
.tip-scene > * {
  position: absolute;
  will-change: transform, opacity;
}

/* В панели советов места достаточно — там сцена разворачивается во всю ширину карточки. */
.tips-panel .tip-scene {
  flex: 0 0 100%;
  width: 100%;
  max-width: 320px;
  margin-inline: auto;
  height: 92px;
  overflow: visible;
}

/* Папка — источник, стоит слева и чуть «дышит» в момент выдачи фото. */
.ts-folder {
  left: 6px;
  top: 34px;
  width: 34px;
  height: 26px;
  color: color-mix(in srgb, var(--text-secondary) 75%, transparent);
  /* ПАПКА ЛЕЖИТ ПОВЕРХ СНИМКА. Иначе фотография не «выезжает из папки», а накрывает её собой:
     на первом же кадре сцены вместо папки был виден тёмный прямоугольник, и начало истории
     читалось неверно. Порядок в разметке даёт обратное, поэтому глубину задаём явно. */
  z-index: 2;
  animation: ts-folder var(--ритм) ease-in-out infinite;
}
.ts-folder svg {
  width: 100%;
  height: 100%;
}

/* Фотография: маленький кадр с небом и холмом — чтобы читалась как снимок, а не как плашка. */
.ts-photo {
  left: 14px;
  top: 40px;
  width: 30px;
  height: 22px;
  border-radius: 3px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--text-primary) 25%, transparent);
  opacity: 0;
  z-index: 1;
  animation: ts-photo var(--ритм) cubic-bezier(0.33, 0, 0.2, 1) infinite;
}
.ts-photo-sky,
.ts-fill-sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #7fb7e8, #d9ecfb);
}
.ts-photo-hill,
.ts-fill-hill {
  position: absolute;
  left: -10%;
  bottom: -40%;
  width: 120%;
  height: 80%;
  border-radius: 50% 50% 0 0;
  background: linear-gradient(180deg, #4f9d6b, #2f6b48);
}

/* Карта-туз справа: цель переноса. */
.ts-card {
  right: 16px;
  top: 12px;
  width: 50px;
  height: 70px;
  border-radius: 6px;
  overflow: hidden;
  border: 1.5px solid color-mix(in srgb, var(--text-secondary) 55%, transparent);
  background: color-mix(in srgb, var(--text-primary) 8%, transparent);
  animation: ts-card var(--ритм) ease-out infinite;
}
.ts-rank {
  position: absolute;
  left: 4px;
  top: 2px;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: var(--text-primary);
  animation: ts-rank var(--ритм) ease-in-out infinite;
}
.ts-pip {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  color: var(--text-primary);
  animation: ts-pip var(--ритм) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.ts-pip svg {
  width: 100%;
  height: 100%;
}
/* Фотография, легшая на карту: тот же кадр, что летел, — так виден результат переноса.
   ЛЕЖИТ НА МЕСТЕ МАСТИ, а не поверх всей карты: заказчик просил, чтобы «масть туза менялась на
   фотографию». Залив карту целиком, сцена теряла главное — что это по-прежнему КАРТА: пропадали
   и рамка, и ранг, и человек видел просто прямоугольник с картинкой. */
.ts-fill {
  position: absolute;
  left: 6px;
  right: 6px;
  top: 16px;
  bottom: 8px;
  border-radius: 3px;
  overflow: hidden;
  opacity: 0;
  transform: scale(0.9);
  animation: ts-fill var(--ритм) cubic-bezier(0.2, 0, 0.2, 1) infinite;
}

/* Курсор: подходит, «нажимает», ведёт фото и отпускает. */
.ts-cursor {
  left: 30px;
  top: 52px;
  width: 13px;
  height: 16px;
  color: var(--text-primary);
  opacity: 0;
  animation: ts-cursor var(--ритм) cubic-bezier(0.33, 0, 0.2, 1) infinite;
}
.ts-cursor svg {
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.45));
}

@keyframes ts-folder {
  0%,
  8% {
    transform: translateY(0) scale(1);
  }
  14% {
    transform: translateY(-1px) scale(1.05);
  }
  24%,
  100% {
    transform: translateY(0) scale(1);
  }
}
@keyframes ts-photo {
  /* Старт — ВНУТРИ папки (снимок ниже её кромки и скрыт за ней), затем подъём выше верхнего
     края: только так движение читается как «достали из папки», а не «появилось рядом». */
  0%,
  9% {
    transform: translate(0, 6px) scale(0.8) rotate(-6deg);
    opacity: 0;
  }
  16% {
    opacity: 1;
  }
  22% {
    transform: translate(2px, -20px) scale(1) rotate(-3deg);
    opacity: 1;
  }
  30% {
    transform: translate(4px, -22px) scale(0.96) rotate(-2deg);
    opacity: 1;
  }
  /* Несём к карте: 148 px вправо и 16 вверх — карта стоит справа и выше папки. */
  55% {
    transform: translate(250px, -34px) scale(0.94) rotate(2deg);
    opacity: 1;
  }
  /* Бросок: снимок «уходит внутрь» карты — уменьшается и гаснет ровно там, где ляжет. */
  62% {
    transform: translate(250px, -34px) scale(0.6) rotate(0deg);
    opacity: 0;
  }
  100% {
    transform: translate(250px, -34px) scale(0.6);
    opacity: 0;
  }
}
@keyframes ts-cursor {
  0%,
  16% {
    transform: translate(-14px, 10px) scale(1);
    opacity: 0;
  }
  24% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
  }
  /* Короткое «нажатие» — 0.88: жест взятия должен читаться, но не прыгать. */
  30% {
    transform: translate(2px, -12px) scale(0.88);
    opacity: 1;
  }
  55% {
    transform: translate(240px, -24px) scale(0.88);
    opacity: 1;
  }
  /* Отпустил. */
  62% {
    transform: translate(240px, -24px) scale(1);
    opacity: 1;
  }
  74% {
    transform: translate(256px, -16px) scale(1);
    opacity: 0;
  }
  100% {
    transform: translate(256px, -16px) scale(1);
    opacity: 0;
  }
}
@keyframes ts-pip {
  0%,
  55% {
    transform: scale(1);
    opacity: 1;
  }
  /* Масть уступает место фотографии — не мигает, а уходит вглубь. */
  62% {
    transform: scale(0.7);
    opacity: 0;
  }
  86% {
    transform: scale(0.7);
    opacity: 0;
  }
  96%,
  100% {
    transform: scale(1);
    opacity: 1;
  }
}
@keyframes ts-fill {
  0%,
  57% {
    transform: scale(0.86);
    opacity: 0;
  }
  64% {
    transform: scale(1);
    opacity: 1;
  }
  86% {
    transform: scale(1);
    opacity: 1;
  }
  /* Выход быстрее входа (правило дизайн-скилла): 7 % против 14 % на вход. */
  93%,
  100% {
    transform: scale(1);
    opacity: 0;
  }
}
@keyframes ts-card {
  0%,
  57% {
    transform: scale(1);
  }
  /* Карта принимает фото — короткий отклик, как нажатие: сцена подтверждает, что попало. */
  64% {
    transform: scale(1.06);
  }
  72%,
  100% {
    transform: scale(1);
  }
}
@keyframes ts-rank {
  0%,
  57% {
    opacity: 1;
  }
  64%,
  86% {
    opacity: 0.85;
  }
  96%,
  100% {
    opacity: 1;
  }
}

/* ДВИЖЕНИЕ ВЫКЛЮЧЕНО СИСТЕМОЙ — показываем ИТОГ, а не пустую сцену: карта уже с фотографией,
   курсор и летящий снимок убраны. Человек видит, чем дело кончится, без единого кадра движения. */
@media (prefers-reduced-motion: reduce) {
  .ts-folder,
  .ts-photo,
  .ts-cursor,
  .ts-pip,
  .ts-fill,
  .ts-card,
  .ts-rank {
    animation: none;
  }
  .ts-photo,
  .ts-cursor,
  .ts-pip {
    opacity: 0;
  }
  .ts-fill {
    opacity: 1;
    transform: scale(1);
  }
}

/* Одноразовый тост «Советов» — левый низ (правый занят плашкой масштаба, E-285).
   Кликов не ловит корпусом: иначе съел бы бросок файла на карту под собой. */
.tips-toast {
  position: fixed;
  left: 18px;
  bottom: 18px;
  z-index: 3800;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  max-width: min(560px, calc(100vw - 36px));
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg-secondary);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
  pointer-events: none;
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.22s ease,
    transform 0.22s cubic-bezier(0.2, 0.8, 0.3, 1);
}
.tips-toast.open {
  opacity: 1;
  transform: translateY(0);
}
.tips-toast-x {
  pointer-events: auto;
  align-self: center;
  padding: 5px 12px;
  border-radius: 7px;
  border: 1px solid var(--accent);
  background: transparent;
  color: var(--accent);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
}
.tips-toast-x:hover {
  background: var(--accent);
  color: #fff;
  box-shadow: var(--nm-out-xs);
}
.tips-toast-x:active {
  box-shadow: var(--nm-in-sm);
}
@media (prefers-reduced-motion: reduce) {
  .tips-toast {
    transition: none;
  }
}

/* Состав колоды в меню «Настройки»: пресеты + живая подпись «сколько карт». */
.view-menu .deck-comp-row {
  display: flex;
  gap: 5px;
  padding: 2px 10px 4px;
}
/* ТОКЕНЫ --text-dim И --text В ПРОЕКТЕ НЕ СУЩЕСТВУЮТ (замер 2026-08-21: определений ноль).
   13 правил семейства «Вид»/«Настройки» были написаны с этими именами и всё время жили на
   хардкод-фолбэках #93a1b5 / #e6edf6 — то есть на цвете ТЁМНОЙ темы. В светлой это давало
   контраст 2.40:1 у пресетов состава при 6.93:1 у соседних карточек того же меню.
   Настоящие имена — --text-secondary / --text-primary; они переопределяются в theme-light.css. */
.view-menu .deck-comp-pill {
  flex: 1;
  padding: 6px 4px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.view-menu .deck-comp-pill:hover {
  border-color: var(--accent, #4a9eff);
  color: var(--text-primary);
}
.view-menu .deck-comp-pill.active {
  background: var(--accent, #4a9eff);
  border-color: var(--accent, #4a9eff);
  color: #fff;
}
.view-menu .deck-comp-label {
  padding: 0 10px 8px;
  font-size: 11px;
  color: var(--text-secondary);
}

/* Свой состав колоды — раскрывающийся блок под пресетами (меню «Настройки»). */
.view-menu .deck-custom {
  padding: 0 10px 8px;
}
.view-menu .deck-custom-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 6px 8px;
  border-radius: 7px;
  border: 1px dashed var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
}
.view-menu .deck-custom-head:hover {
  border-color: var(--accent, #4a9eff);
  color: var(--text-primary);
}
.view-menu .deck-custom .dc-caret {
  transition: transform 0.15s ease;
}
.view-menu .deck-custom.open .dc-caret {
  transform: rotate(180deg);
}
.view-menu .deck-custom-body {
  display: none;
  padding-top: 6px;
}
.view-menu .deck-custom.open .deck-custom-body {
  display: block;
}
.view-menu .dc-title {
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin: 6px 0 3px;
}
.view-menu .dc-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.view-menu .dc-chip {
  min-width: 30px;
  padding: 4px 6px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
}
.view-menu .dc-chip:hover {
  border-color: var(--accent, #4a9eff);
  color: var(--text-primary);
}
.view-menu .dc-chip.active {
  background: var(--accent, #4a9eff);
  border-color: var(--accent, #4a9eff);
  color: #fff;
}
.view-menu .dc-chip.dc-suit {
  font-size: 14px;
  line-height: 1;
}
.view-menu .dc-chip.dc-suit.red:not(.active) {
  color: #d8384a;
}
.view-menu .dc-chip.dc-wide {
  flex: 1;
}

/* Переключатель «Скруглённые углы»: состояние названо словом, а не только цветом рамки. */
.view-menu .view-format-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
}
.view-menu .view-format-toggle .vft-box {
  font-size: 14px;
  line-height: 1;
}
.view-menu .view-format-toggle .vft-lb {
  flex: 1;
}
.view-menu .view-format-toggle .vft-state {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.view-menu .view-format-toggle.active .vft-state {
  background: var(--accent);
  /* Тот же случай, что у `.view-idle.active`: белое «вкл» на светлом акценте давало 2.16:1.
     Цвет текста поверх акцента решает тема — токен `--on-accent`. */
  color: var(--on-accent, #0e1c26);
}

/* Заголовки групп в окне «Версии» (2026-08-17): ручные версии и автоматические снимки —
   разные по происхождению, и человек должен различать их с одного взгляда. Заголовок занимает
   всю строку сетки, поэтому grid-column: 1 / -1. */
.versions-group-head {
  grid-column: 1 / -1;
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 6px 0 -2px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
}
.versions-group-head small {
  font-weight: 400;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* ═══ ЖИВОЙ ПОКАЗ НА НАСТОЯЩЕЙ КАРТЕ (просьба заказчика 2026-08-17) ══════════════════════════
   Кнопка «Показать» у совета доводит до обзора колоды и разыгрывает перенос фото прямо на
   плитке туза: снимок прилетает с курсором, ложится на карту и гаснет вместе с подсветкой.

   Размеры плитки приходят переменными --ш/--в: лист меняет масштаб под число карт, и снимок
   обязан лечь ПО КАРТЕ, а не по числу, угаданному в стилях.

   Как и в меню — только transform/opacity: лист из 55 карт пересобирается на главном потоке,
   и анимация раскладки замерла бы вместе с ним. Оверлей не ловит нажатий: показ, съедающий
   клик, хуже отсутствия показа. */
.tip-live {
  position: fixed;
  z-index: 4200;
  width: var(--ш);
  height: var(--в);
  pointer-events: none;
}
.tip-live > * {
  position: absolute;
  will-change: transform, opacity;
}
/* РАЗМЕР — ПО ЦЕНТРАЛЬНОЙ МАСТИ, А НЕ ПО ВСЕЙ КАРТЕ (поправка заказчика 2026-08-17:
   «перетаскивается слишком большая иконка, она закрывает практически весь туз, а должна
   перекрыть только центральную масть»). Снимок в 84 % ширины прятал и угловые индексы, и
   рамку — карта переставала быть узнаваемой, а показ обещал не то, что делает продукт.
   Доли, а не пиксели: плитка листа меняет размер под число карт и масштаб. */
.tl-photo {
  /* РАЗМЕР ВЗЯТ ЗАМЕРОМ САМОЙ МАСТИ, А НЕ НА ГЛАЗ: тёмное пятно в центре плитки занимает
     29.8 % ширины и 28.4 % высоты и стоит ровно посередине. Берём с запасом (по 4 % с каждой
     стороны), иначе острый верх пики торчит над снимком — заказчик увидел это первым же
     взглядом. Запас небольшой: снимок должен закрыть масть, а не пол-карты. */
  left: 30%;
  top: 30%;
  width: 40%;
  height: 40%;
  border-radius: 2px;
  overflow: hidden;
  /* Тонкая светлая кромка + мягкая тень: снимок должен читаться как ФОТОГРАФИЯ, положенная на
     карту, а не как кнопка. Толстая белая окантовка со скруглением давала именно кнопку. */
  border: 1px solid rgba(255, 255, 255, 0.9);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
  opacity: 0;
  /* 6.5 с: полёт ≈2.6 с, затем снимок ДЕРЖИТСЯ ровно три секунды и гаснет — так просил
     заказчик. Раньше он лежал до первого действия человека, и это было прошлой поправкой; та
     решала другую беду («картинка сразу исчезает»), а теперь названо точное время. */
  animation: tl-photo 6.5s cubic-bezier(0.33, 0, 0.2, 1) 1 both;
}
.tl-sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #7fb7e8, #d9ecfb);
}
.tl-hill {
  position: absolute;
  left: -10%;
  bottom: -40%;
  width: 120%;
  height: 80%;
  border-radius: 50% 50% 0 0;
  background: linear-gradient(180deg, #4f9d6b, #2f6b48);
}
.tl-cursor {
  left: 50%;
  top: 55%;
  width: 15px;
  height: 19px;
  color: #fff;
  opacity: 0;
  animation: tl-cursor 6.5s cubic-bezier(0.33, 0, 0.2, 1) 1 both;
}
.tl-cursor svg {
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8));
}

/* Снимок приходит СЛЕВА-СВЕРХУ, «из папки за краем экрана», и садится на карту. Смещение в
   процентах от собственного размера — путь остаётся соразмерным плитке на любом масштабе. */
@keyframes tl-photo {
  0% {
    transform: translate(-420%, -260%) scale(0.7) rotate(-8deg);
    opacity: 0;
  }
  8% {
    opacity: 1;
  }
  /* Лёг на место центральной масти. */
  40% {
    transform: translate(0, 0) scale(1) rotate(0deg);
    opacity: 1;
  }
  /* Короткий отклик — «прижался» к карте. */
  46% {
    transform: translate(0, 0) scale(0.94) rotate(0deg);
    opacity: 1;
  }
  /* ТРИ СЕКУНДЫ ПОКОЯ: с 3.25 с (50 %) до 6.0 с (92 %) при длительности 6.5 с. */
  50%,
  92% {
    transform: translate(0, 0) scale(1) rotate(0deg);
    opacity: 1;
  }
  100% {
    transform: translate(0, 0) scale(1) rotate(0deg);
    opacity: 0;
  }
}
@keyframes tl-cursor {
  0% {
    transform: translate(-320%, -180%) scale(1);
    opacity: 0;
  }
  8% {
    opacity: 1;
  }
  40% {
    transform: translate(-30%, 30%) scale(0.86);
    opacity: 1;
  }
  /* Отпустил. */
  47% {
    transform: translate(-30%, 30%) scale(1);
    opacity: 1;
  }
  /* Уходит, чтобы не заслонять результат те самые три секунды. */
  58%,
  100% {
    transform: translate(60%, 90%) scale(1);
    opacity: 0;
  }
}

/* Движение запрещено системой — показываем итог: снимок сразу лежит на карте и так же гаснет
   вместе с подсветкой. Ни одного кадра движения, но смысл («фото окажется здесь») сохранён. */
@media (prefers-reduced-motion: reduce) {
  .tl-photo {
    animation: none;
    opacity: 1;
  }
  .tl-cursor {
    animation: none;
    opacity: 0;
  }
}

/* В ТОСТЕ — ТОЛЬКО КАРТА С ФОТОГРАФИЕЙ. Папка, курсор и летящий снимок в 64 пикселя не
   помещаются и превращаются в кашу; итоговый кадр объясняет суть за один взгляд, а «как это
   делается» показывает кнопка «Показать» на живой колоде. */
.tips-toast .ts-folder,
.tips-toast .ts-photo,
.tips-toast .ts-cursor {
  display: none;
}
.tips-toast .ts-card {
  right: auto;
  left: 7px;
  top: 4px;
}
/* В ТОСТЕ КАРТА НЕ МИГАЕТ. Участников переноса здесь нет (не помещаются), и одна анимированная
   карта без них читается как сбой: масть то пропадает, то возвращается без причины. Показываем
   итог — карту с фотографией. Полная сцена живёт в панели советов, где есть место всем. */
.tips-toast .ts-card,
.tips-toast .ts-pip,
.tips-toast .ts-fill,
.tips-toast .ts-rank {
  animation: none;
}
.tips-toast .ts-pip {
  opacity: 0;
}
.tips-toast .ts-fill {
  opacity: 1;
  transform: scale(1);
}

/* СЦЕНА В МЕНЮ ОСТАЁТСЯ ЖИВОЙ. Здесь недолго стоял блок, гасивший её ради «одного движения на
   экран», — заказчик поправил: убирать её никто не просил. Показ на живой колоде отвечает на
   вопрос «как это делается прямо сейчас», а сцена в меню — на «что это вообще за приём», и
   мешать друг другу они не могут: панель открыта в одном углу, колода в другом. */

/* ═══ СЦЕНЫ ОСТАЛЬНЫХ СОВЕТОВ (2026-08-17) ══════════════════════════════════════════════════
   Тот же закон, что у сцены с фотографией: ТОЛЬКО transform и opacity. Панель советов может
   открыться в любой момент, в том числе пока собирается лист из 55 карт, и анимация раскладки
   замерла бы вместе с ним.

   Все сцены aria-hidden: они иллюстрируют текст рядом, который полон сам по себе. При
   prefers-reduced-motion движение выключается и остаётся понятный статичный кадр. */

/* ── 1. ОХВАТ: подсветка идёт по одной карте → набору → всей колоде ───────────────────────── */
.sc-scope {
  --ритм: 7s;
}
.sc-pill {
  position: absolute;
  left: 50%;
  top: 4px;
  transform: translateX(-50%);
  display: grid;
  place-items: center;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
  color: var(--text-primary);
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
}
.sc-pill i {
  font-style: normal;
  grid-area: 1 / 1;
  opacity: 0;
}
.sc-pill-1 {
  animation: sc-p1 var(--ритм) steps(1, end) infinite;
}
.sc-pill-2 {
  animation: sc-p2 var(--ритм) steps(1, end) infinite;
}
.sc-pill-3 {
  animation: sc-p3 var(--ритм) steps(1, end) infinite;
}
.sc-row {
  position: absolute;
  left: 50%;
  bottom: 8px;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
}
.sc-card {
  position: relative;
  width: 34px;
  height: 48px;
  border-radius: 4px;
  border: 1.5px solid color-mix(in srgb, var(--text-secondary) 45%, transparent);
  background: color-mix(in srgb, var(--text-primary) 7%, transparent);
}
/* Подсветку рисует псевдоэлемент — так «выделение» не двигает раскладку ряда. */
.sc-card::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 6px;
  border: 2px solid var(--accent);
  opacity: 0;
  will-change: opacity, transform;
}
/* Одна карта — вторая в ряду; набор — первая, третья и пятая; вся колода — все пять. */
.sc-c2::after {
  animation: sc-one var(--ритм) ease-in-out infinite;
}
.sc-c1::after,
.sc-c3::after,
.sc-c5::after {
  animation: sc-set var(--ритм) ease-in-out infinite;
}
.sc-c4::after {
  animation: sc-all var(--ритм) ease-in-out infinite;
}
@keyframes sc-p1 {
  0%,
  30% {
    opacity: 1;
  }
  31%,
  100% {
    opacity: 0;
  }
}
@keyframes sc-p2 {
  0%,
  32% {
    opacity: 0;
  }
  33%,
  63% {
    opacity: 1;
  }
  64%,
  100% {
    opacity: 0;
  }
}
@keyframes sc-p3 {
  0%,
  65% {
    opacity: 0;
  }
  66%,
  96% {
    opacity: 1;
  }
  97%,
  100% {
    opacity: 0;
  }
}
@keyframes sc-one {
  0%,
  4% {
    opacity: 0;
    transform: scale(0.94);
  }
  10%,
  28% {
    opacity: 1;
    transform: scale(1);
  }
  32%,
  100% {
    opacity: 0;
    transform: scale(1);
  }
}
@keyframes sc-set {
  0%,
  36% {
    opacity: 0;
    transform: scale(0.94);
  }
  42%,
  61% {
    opacity: 1;
    transform: scale(1);
  }
  64% {
    opacity: 0;
  }
  /* В финале, когда охват «вся колода», эти карты подсвечены вместе со всеми. */
  74%,
  94% {
    opacity: 1;
    transform: scale(1);
  }
  98%,
  100% {
    opacity: 0;
  }
}
@keyframes sc-all {
  0%,
  68% {
    opacity: 0;
    transform: scale(0.94);
  }
  74%,
  94% {
    opacity: 1;
    transform: scale(1);
  }
  98%,
  100% {
    opacity: 0;
  }
}

/* ── 2. ВЕРСИИ: дизайн меняется, слепки копятся, стрелка возвращает прежний ──────────────── */
.sc-ver {
  --ритм: 6.5s;
}
.sv-stack {
  position: absolute;
  left: 22px;
  top: 26px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sv-stack i {
  display: block;
  width: 26px;
  height: 12px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--text-primary) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--text-secondary) 35%, transparent);
  opacity: 0;
  transform: translateX(-8px);
  will-change: transform, opacity;
  animation: sv-slice var(--ритм) ease-out infinite;
}
.sv-stack i:nth-child(2) {
  animation-delay: calc(var(--ритм) * -0.72);
}
.sv-stack i:nth-child(3) {
  animation-delay: calc(var(--ритм) * -0.44);
}
.sv-card {
  position: absolute;
  left: 50%;
  top: 14px;
  margin-left: -25px;
  width: 50px;
  height: 68px;
  border-radius: 6px;
  overflow: hidden;
  border: 1.5px solid color-mix(in srgb, var(--text-secondary) 50%, transparent);
}
.sv-face {
  position: absolute;
  inset: 0;
  will-change: opacity;
}
.sv-a {
  background: repeating-linear-gradient(45deg, #6aa9d8 0 6px, #cfe6f7 6px 12px);
  animation: sv-a var(--ритм) ease-in-out infinite;
}
.sv-b {
  background: repeating-linear-gradient(-45deg, #d88a6a 0 6px, #f7ddcf 6px 12px);
  opacity: 0;
  animation: sv-b var(--ритм) ease-in-out infinite;
}
.sv-back {
  position: absolute;
  right: 26px;
  top: 40px;
  width: 20px;
  height: 20px;
  color: var(--accent);
  opacity: 0;
  will-change: transform, opacity;
  animation: sv-back var(--ритм) cubic-bezier(0.34, 1.3, 0.5, 1) infinite;
}
.sv-back svg {
  width: 100%;
  height: 100%;
}
@keyframes sv-slice {
  0%,
  6% {
    opacity: 0;
    transform: translateX(-8px);
  }
  16%,
  92% {
    opacity: 1;
    transform: translateX(0);
  }
  100% {
    opacity: 0;
    transform: translateX(0);
  }
}
/* Дизайн сменился на другой — и вернулся, когда сработала стрелка. */
@keyframes sv-a {
  0%,
  26% {
    opacity: 1;
  }
  34%,
  72% {
    opacity: 0;
  }
  80%,
  100% {
    opacity: 1;
  }
}
@keyframes sv-b {
  0%,
  26% {
    opacity: 0;
  }
  34%,
  72% {
    opacity: 1;
  }
  80%,
  100% {
    opacity: 0;
  }
}
@keyframes sv-back {
  0%,
  58% {
    opacity: 0;
    transform: scale(0.7) rotate(0deg);
  }
  66% {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
  74% {
    opacity: 1;
    transform: scale(0.92) rotate(-25deg);
  }
  86%,
  100% {
    opacity: 0;
    transform: scale(1) rotate(-25deg);
  }
}

/* ── 3. КОМПЛЕКТ: страницы и паспорт складываются в архив ────────────────────────────────── */
.sc-kit {
  --ритм: 6s;
}
.sk-page {
  position: absolute;
  width: 30px;
  height: 42px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--text-primary) 9%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--text-secondary) 45%, transparent);
  will-change: transform, opacity;
}
.sk-p1 {
  left: 26px;
  top: 12px;
  animation: sk-p1 var(--ритм) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.sk-p2 {
  left: 62px;
  top: 12px;
  animation: sk-p2 var(--ритм) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
/* Паспорт печати — лист с тремя строками текста. */
.sk-doc {
  position: absolute;
  left: 98px;
  top: 12px;
  width: 30px;
  height: 42px;
  padding: 7px 5px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--text-primary) 5%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--accent) 55%, transparent);
  display: flex;
  flex-direction: column;
  gap: 4px;
  will-change: transform, opacity;
  animation: sk-doc var(--ритм) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.sk-doc i {
  display: block;
  height: 2px;
  border-radius: 1px;
  background: color-mix(in srgb, var(--text-secondary) 60%, transparent);
}
.sk-doc i:nth-child(2) {
  width: 70%;
}
.sk-doc i:nth-child(3) {
  width: 45%;
}
.sk-box {
  position: absolute;
  left: 50%;
  margin-left: -18px;
  bottom: 10px;
  width: 36px;
  height: 30px;
  color: var(--accent);
  opacity: 0;
  will-change: transform, opacity;
  animation: sk-box var(--ритм) cubic-bezier(0.34, 1.25, 0.5, 1) infinite;
}
.sk-box svg {
  width: 100%;
  height: 100%;
}
/* Всё съезжается к центру и «падает» в архив. */
@keyframes sk-p1 {
  0%,
  18% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
  }
  52% {
    transform: translate(38px, 30px) scale(0.45);
    opacity: 0.9;
  }
  58%,
  100% {
    transform: translate(38px, 34px) scale(0.3);
    opacity: 0;
  }
}
@keyframes sk-p2 {
  0%,
  22% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
  }
  56% {
    transform: translate(2px, 30px) scale(0.45);
    opacity: 0.9;
  }
  62%,
  100% {
    transform: translate(2px, 34px) scale(0.3);
    opacity: 0;
  }
}
@keyframes sk-doc {
  0%,
  26% {
    transform: translate(0, 0) scale(1);
    opacity: 1;
  }
  60% {
    transform: translate(-34px, 30px) scale(0.45);
    opacity: 0.9;
  }
  66%,
  100% {
    transform: translate(-34px, 34px) scale(0.3);
    opacity: 0;
  }
}
@keyframes sk-box {
  0%,
  40% {
    opacity: 0;
    transform: scale(0.8);
  }
  52% {
    opacity: 1;
    transform: scale(1);
  }
  /* Архив принял содержимое — короткий отклик. */
  68% {
    transform: scale(1.08);
  }
  76%,
  92% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

/* ДВИЖЕНИЕ ЗАПРЕЩЕНО СИСТЕМОЙ — оставляем понятный статичный кадр каждой сцены. */
@media (prefers-reduced-motion: reduce) {
  .sc-scope *,
  .sc-ver *,
  .sc-kit * {
    animation: none !important;
  }
  .sc-pill-1,
  .sc-pill-2 {
    opacity: 0;
  }
  .sc-pill-3 {
    opacity: 1;
  }
  .sc-card::after {
    opacity: 1;
  }
  .sv-stack i {
    opacity: 1;
    transform: none;
  }
  .sv-b {
    opacity: 0;
  }
  .sv-back {
    opacity: 1;
  }
  .sk-box {
    opacity: 1;
    transform: none;
  }
}

/* ═══ СЦЕНА «ЛИСТАТЬ КАРТЫ РУКОЙ» (просьба заказчика 2026-08-19) ═══════════════════════════
   Три такта одной сцены: вбок — приходит соседняя карта; вверх — карта поворачивается рубашкой;
   вниз — рассыпается сеткой колоды. Подпись такта приходит вместе с движением: иначе зритель
   видит красивое и не знает, что оно значит.

   Только transform и opacity — правило проекта, оплаченное дважды за один день (полоса
   прогресса и кольцо заставки). Сцена живёт в панели, которую человек открывает во время
   сборки листа, а та занимает главный поток задачами по 700 мс: всё, что считает раскладку,
   встанет и прочтётся как «подвисло».

   ЕДИНЫЙ РИТМ: такт = --ритм/3, и все участники живут по одному таймеру. Разные длительности
   у карты, курсора и подписи дали бы расползание — подпись про «вверх» поверх движения вбок. */
.sc-swipe {
  --ритм: 9s;
  perspective: 520px;
}
.sc-swipe .sw-card {
  left: 50%;
  top: 6px;
  width: 46px;
  height: 64px;
  margin-left: -23px;
  /* Скругление как у соседних сцен (6px). Заказчик 2026-08-19: «при демонстрации совета карта
     показывается без скругления углов» — на 46 px пятипиксельный радиус читался прямым углом,
     и мини-карта выглядела коробкой рядом со скруглёнными картами других советов. */
  border-radius: 6px;
  transform-style: preserve-3d;
  animation: sw-card var(--ритм) cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
/* Лицо и рубашка — две грани одной карты: поворот обязан ПОКАЗЫВАТЬ рубашку, а не зеркалить
   лицо. Зеркальная «A» читалась бы как сбой отрисовки. */
.sc-swipe .sw-face,
.sc-swipe .sw-back {
  position: absolute;
  inset: 0;
  border-radius: 6px;
  backface-visibility: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  font-weight: 700;
  font-style: normal;
}
.sc-swipe .sw-face {
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  color: var(--text-primary);
}
.sc-swipe .sw-back {
  transform: rotateY(180deg);
  background: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--accent) 45%, transparent) 0 4px,
    transparent 4px 8px
  );
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent);
}
/* Соседняя карта: приходит справа в первом такте и уходит с глаз. */
.sc-swipe .sw-next {
  left: 50%;
  top: 6px;
  width: 46px;
  height: 64px;
  margin-left: -23px;
  border-radius: 6px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  font-size: 18px;
  font-weight: 700;
  opacity: 0;
  animation: sw-next var(--ритм) cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
.sc-swipe .sw-next i {
  font-style: normal;
}
/* Сетка колоды третьего такта. Она НЕ повторяет лист по-настоящему — это символ, и шести
   плиток хватает: задача сцены объяснить исход жеста, а не показать 55 карт. */
.sc-swipe .sw-grid {
  left: 50%;
  top: 14px;
  width: 76px;
  margin-left: -38px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  opacity: 0;
  animation: sw-grid var(--ритм) ease-out infinite;
}
.sc-swipe .sw-grid i {
  display: block;
  height: 22px;
  border-radius: 3px;
  background: var(--bg-secondary);
  border: 1px solid var(--border);
}
/* Курсор ведёт руку: без него сцена читается как «карта сама ездит», а совет ровно о том, что
   её ТЯНУТ. */
.sc-swipe .sw-cursor {
  left: 50%;
  top: 34px;
  width: 13px;
  height: 16px;
  margin-left: -6px;
  color: var(--text-primary);
  animation: sw-cursor var(--ритм) cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
.sc-swipe .sw-cursor svg {
  width: 100%;
  height: 100%;
}
.sc-swipe .sw-tag {
  left: 0;
  right: 0;
  bottom: -2px;
  text-align: center;
  font-size: var(--fs-3xs);
  color: var(--text-muted);
  opacity: 0;
  animation: sw-tag var(--ритм) linear infinite;
}
.sc-swipe .sw-t2 {
  animation-delay: calc(var(--ритм) / 3);
}
.sc-swipe .sw-t3 {
  animation-delay: calc(var(--ритм) / 3 * 2);
}
@keyframes sw-card {
  /* Такт 1 — вбок и обратно в центр (пришла соседняя). */
  0%,
  6% {
    transform: translateX(0) rotateY(0deg) scale(1);
    opacity: 1;
  }
  20% {
    transform: translateX(-46px) rotateY(0deg) scale(1);
    opacity: 0;
  }
  21% {
    transform: translateX(0) rotateY(0deg) scale(1);
    opacity: 0;
  }
  32%,
  38% {
    transform: translateX(0) rotateY(0deg) scale(1);
    opacity: 1;
  }
  /* Такт 2 — поворот лицом к рубашке. */
  52%,
  62% {
    transform: translateX(0) rotateY(180deg) scale(1);
    opacity: 1;
  }
  68% {
    transform: translateX(0) rotateY(0deg) scale(1);
    opacity: 1;
  }
  /* Такт 3 — уходит вниз и уменьшается: место занимает колода. */
  84%,
  94% {
    transform: translateY(26px) rotateY(0deg) scale(0.34);
    opacity: 0;
  }
  100% {
    transform: translateX(0) rotateY(0deg) scale(1);
    opacity: 1;
  }
}
@keyframes sw-next {
  0%,
  6% {
    transform: translateX(46px);
    opacity: 0;
  }
  20% {
    transform: translateX(0);
    opacity: 1;
  }
  30% {
    transform: translateX(0);
    opacity: 1;
  }
  33%,
  100% {
    transform: translateX(46px);
    opacity: 0;
  }
}
@keyframes sw-grid {
  0%,
  72% {
    transform: scale(0.7);
    opacity: 0;
  }
  84%,
  94% {
    transform: scale(1);
    opacity: 1;
  }
  100% {
    transform: scale(0.7);
    opacity: 0;
  }
}
@keyframes sw-cursor {
  0%,
  6% {
    transform: translate(0, 0);
    opacity: 1;
  }
  20% {
    transform: translate(-30px, 0);
  }
  33% {
    transform: translate(0, 0);
  }
  /* вверх */
  52% {
    transform: translate(0, -26px);
  }
  66% {
    transform: translate(0, 0);
  }
  /* вниз */
  84% {
    transform: translate(0, 28px);
  }
  100% {
    transform: translate(0, 0);
    opacity: 1;
  }
}
@keyframes sw-tag {
  0% {
    opacity: 0;
  }
  6%,
  27% {
    opacity: 1;
  }
  33%,
  100% {
    opacity: 0;
  }
}
/* Запрет движения: остаётся ИТОГОВЫЙ смысл — карта и подпись первого такта, а не пустая
   сцена. Человек видит, о чём совет, просто без движения. */
@media (prefers-reduced-motion: reduce) {
  .sc-swipe .sw-card,
  .sc-swipe .sw-next,
  .sc-swipe .sw-grid,
  .sc-swipe .sw-cursor,
  .sc-swipe .sw-tag {
    animation: none;
  }
  .sc-swipe .sw-card {
    transform: none;
    opacity: 1;
  }
  .sc-swipe .sw-next {
    transform: translateX(46px);
    opacity: 0.5;
  }
  .sc-swipe .sw-t1 {
    opacity: 1;
  }
}

/* ═══ ПРИЦЕЛ «ПОКАЗАТЬ»: КОЛЬЦО И СТРЕЛКА (2026-08-17) ══════════════════════════════════════
   Заказчик: «если ты показываешь местонахождение, добавь анимированные стрелки или какие-то
   элементы, чтобы было понятно, что ты это выделил».

   Просьба вскрыла настоящий дефект: класса .tip-target-ring НЕ БЫЛО В СТИЛЯХ ВООБЩЕ. Элемент
   создавался, получал координаты и оставался невидимым — «Показать» доводил до места и не
   показывал ничего. Проба была зелёной, потому что спрашивала НАЛИЧИЕ элемента, а не видит ли
   его человек.

   Как всегда в этом проекте — только transform и opacity: подсветка часто всплывает поверх
   собирающегося листа, и анимация раскладки замерла бы вместе с ним. */
.tip-target-ring {
  position: fixed;
  z-index: 4300;
  pointer-events: none; /* подсветка, съедающая нажатие, хуже отсутствия подсветки */
  border-radius: 10px;
  border: 2px solid var(--accent);
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent),
    0 6px 22px rgba(0, 0, 0, 0.35);
  animation: tip-ring-in 0.24s cubic-bezier(0.34, 1.4, 0.5, 1) both;
}
/* Пульсирующий ореол — отдельным слоем, чтобы не трогать саму рамку и не гонять её толщину
   (толщина — это раскладка). */
.tip-target-ring::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 14px;
  border: 2px solid color-mix(in srgb, var(--accent) 65%, transparent);
  opacity: 0;
  animation: tip-ring-pulse 1.6s ease-out infinite;
}
@keyframes tip-ring-in {
  from {
    opacity: 0;
    transform: scale(0.94);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}
@keyframes tip-ring-pulse {
  0% {
    opacity: 0.85;
    transform: scale(1);
  }
  70% {
    opacity: 0;
    transform: scale(1.14);
  }
  100% {
    opacity: 0;
    transform: scale(1.14);
  }
}

/* СТРЕЛКА-УКАЗАТЕЛЬ. Стоит над целью и покачивается к ней: движение сверху вниз читается как
   «вот сюда смотри». Если цель у верхней кромки экрана, стрелка переносится под неё и
   переворачивается — указатель, уехавший за край, не указывает ни на что. */
.tip-target-arrow {
  position: absolute;
  left: 50%;
  bottom: 100%;
  margin: 0 0 6px -11px;
  width: 22px;
  height: 28px;
  color: var(--accent);
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5));
  animation: tip-arrow 1.2s cubic-bezier(0.45, 0, 0.35, 1) infinite;
}
.tip-target-arrow svg {
  width: 100%;
  height: 100%;
  display: block;
}
.tip-target-arrow.is-below {
  bottom: auto;
  top: 100%;
  margin: 6px 0 0 -11px;
  transform: rotate(180deg);
  animation-name: tip-arrow-below;
}
@keyframes tip-arrow {
  0%,
  100% {
    transform: translateY(-5px);
    opacity: 0.85;
  }
  50% {
    transform: translateY(1px);
    opacity: 1;
  }
}
@keyframes tip-arrow-below {
  0%,
  100% {
    transform: rotate(180deg) translateY(-5px);
    opacity: 0.85;
  }
  50% {
    transform: rotate(180deg) translateY(1px);
    opacity: 1;
  }
}

/* Движение запрещено системой — прицел остаётся ВИДИМЫМ и статичным: он несёт смысл («вот это
   место»), а не украшение, и гасить его вместе с анимацией значило бы отнять сам ответ. */
@media (prefers-reduced-motion: reduce) {
  .tip-target-ring,
  .tip-target-ring::after,
  .tip-target-arrow {
    animation: none;
  }
  .tip-target-ring::after {
    opacity: 0.5;
  }
  .tip-target-arrow {
    opacity: 1;
  }
}

/* ═══ ЦВЕТА МАСТЕЙ — ЕДИНЫЙ БЛОК (2026-08-17) ═══════════════════════════════════════════════
   Было две отдельные плашки («Цвет ♠ ♣ / текста» и «Цвет ♥ ♦»). Заказчик: «интуитивно не
   понятно, мало того — разделено на две части». Стало: четыре масти своими настоящими цветами,
   клик выбирает, чей цвет менять, и один пикер под ними.

   Пар по-прежнему две — это устройство колоды, а не UI: одним цветом красятся обе чёрные и обе
   красные. Поэтому клик по ♠ подсвечивает и ♣: связь показана, а не подразумевается. */
.suit-colors {
  margin-bottom: 14px;
}
.suit-colors-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 8px;
}
.suit-chip {
  position: relative;
  display: grid;
  place-items: center;
  /* 48 px — выше минимума в 44: масть должна быть КРУПНОЙ, её цвет и есть главная информация. */
  min-height: 48px;
  padding: 8px 4px;
  border-radius: 10px;
  cursor: pointer;
  background: var(--bg-tertiary);
  border: 1.5px solid var(--border);
  transition:
    border-color 0.16s ease,
    background 0.16s ease,
    transform 0.12s ease;
}
.suit-chip svg {
  width: 26px;
  height: 26px;
  fill: var(--suit-color, currentColor);
  /* Тонкая тёмная кромка вокруг глифа: светлые цвета мастей (жёлтый, белый) иначе пропадают на
     светлой подложке, и человек не видит, что вообще выбрал. */
  filter: drop-shadow(0 0 0.5px rgba(0, 0, 0, 0.55));
}
.suit-chip:hover {
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
  transform: translateY(-1px);
}
.suit-chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* ВЫБРАННАЯ ПАРА — не только цветом рамки: галочка в углу говорит то же самое формой, и это
   единственный способ остаться понятным при дальтонизме и в высококонтрастном режиме. */
.suit-chip.is-active {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-tertiary));
}
.suit-chip-check {
  position: absolute;
  top: 3px;
  right: 5px;
  font-size: 11px;
  line-height: 1;
  font-weight: 700;
  color: var(--accent);
  opacity: 0;
  transform: scale(0.7);
  transition:
    opacity 0.14s ease,
    transform 0.14s cubic-bezier(0.34, 1.4, 0.5, 1);
}
.suit-chip.is-active .suit-chip-check {
  opacity: 1;
  transform: scale(1);
}
.suit-colors-note {
  margin-bottom: 8px;
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--text-muted);
}
@media (prefers-reduced-motion: reduce) {
  .suit-chip,
  .suit-chip-check {
    transition: none;
  }
}

/* Кнопка отмены на плашке занятости (просьба заказчика 2026-08-17). Появляется только у
   работ, которые умеют прерываться, — см. пояснение в js/31. Скромная: она нужна редко,
   и не должна спорить с кольцом прогресса за внимание. */
.busy-cancel {
  margin-top: 14px;
  padding: 7px 20px;
  font-size: var(--fs-sm, 13px);
  color: var(--text-secondary, #b9b9c2);
  background: transparent;
  border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
  border-radius: 999px;
  cursor: pointer;
  transition:
    color 0.15s,
    border-color 0.15s;
}
.busy-cancel:hover {
  color: var(--text-primary, #fff);
  border-color: currentColor;
}

/* ═══ КНОПКА-ЗНАЧЕНИЕ ПОКАЗА (просьба заказчика 2026-08-18) ═══
   Ряд вкладок «Вся колода / Рубашка / Лицо ▾» заменён одной кнопкой, на которой написано, что
   показано сейчас. Она читается как ЗНАЧЕНИЕ, а не как действие: чуть плотнее фон и обычная
   рамка вместо акцентной — подсвеченной «активной вкладки» здесь больше нет, потому что
   выбирать не из чего, выбор живёт в списке за кареткой. */
.card-tab--show {
  gap: 7px;
  padding-left: 10px;
}
.card-tab--show .show-value-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  opacity: 0.85;
}
.card-tab--show .show-value-ic svg {
  width: 16px;
  height: 16px;
}
.card-tab--show .show-value-lab {
  font-weight: 600;
  /* Имя показа бывает длинным («Вся колода») и коротким («A♠») — фиксируем минимум, чтобы
     кнопка не прыгала по ширине при каждом переключении: скачущий контрол читается как сбой. */
  min-width: 74px;
  text-align: left;
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   МЯГКИЙ РЕЛЬЕФ — СЕМЕЙСТВО «ПРАВКА» (редизайн 2026-08-18, шаг 1)
   Пример заказчика — неоморфизм: плашки не обведены линией, а выдавлены из поверхности парой
   теней; выбранное — вдавлено. Здесь одета кнопка охвата и её пилюли; строки слоёв и остальное
   одеваются следующими шагами, чтобы каждый шаг оставлял продукт рабочим.

   ГРАНИЦА, КОТОРУЮ НЕ ПЕРЕХОДИМ: рельеф добавляет ФОРМУ, но не отнимает КОНТРАСТ. Цвет текста
   и признак «выключено» остаются прежними — на них стоит left-panel-contrast (жалоба «левое
   меню почти не читается»). Неоморфизм, построенный на одном рельефе, эту пробу валит.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
/* ПОДЛОЖКА УТОПЛЕНА, ЭЛЕМЕНТЫ ВЫПУКЛЫЕ — так устроен материал на примере заказчика: ниша в
   поверхности, из которой выдавлены кнопки. Первая редакция сделала выпуклыми ОБА уровня, и
   вышла «коробка в коробке» — ровно то, от чего панель избавляли 17 августа (кадр
   neo-open-dark.png это и показал). */
.edit-scope.scope-unified {
  border: 1px solid transparent; /* место линии занимает тень: габариты не прыгают при теме */
  border-radius: var(--nm-radius-lg);
  background: transparent;
  box-shadow: none;
  padding: 6px 8px;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
/* Раскрытая плашка — ниша: видно, что выбор сейчас развёрнут, и выпуклые пилюли внутри лежат
   «в углублении», а не парят над плоскостью. */
.edit-scope.scope-unified.is-open {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.scope-head {
  border-radius: var(--nm-radius);
  padding: 4px 2px;
  /* ПО ЦЕНТРУ, А НЕ ПО БАЗОВОЙ ЛИНИИ. С картинкой в строке baseline означает «низ картинки на
     уровне низа букв» — карта повисала, а ярлык со значением расходились по вертикали на 3 px
     (замер до правки). Всем трём блокам нужна одна ось. */
  align-items: center;
  gap: 10px;
}
/* Ярлык над значением: в строку они съедали 165 px из 229 и обрезали длинные подписи вроде
   «Числовые — 36 карт». */
.scope-head-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 0; /* иначе длинное значение распирает шапку и выдавливает шеврон */
  flex: 1 1 auto;
}
.scope-head-text .scope-head-val {
  font-size: var(--fs-md, 15px);
  line-height: 1.2;
  /* Длинное значение переносится многоточием, а не ломает раскладку: полный текст живёт в
     подсказке шапки (решение 2026-08-17 про обрезанные пояснения). */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.edit-scope-pill {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease),
    transform var(--nm-ease);
}
.edit-scope-pill:hover {
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
/* Нажатая пилюля ВДАВЛЕНА — это и есть «выбрано» на языке материала. Цвет акцента остаётся:
   различать выбор одним рельефом нельзя (правило «не только цветом» работает и наоборот —
   не только формой). */
.edit-scope-pill.active {
  box-shadow: var(--nm-in);
}
.edit-scope-pill:active {
  transform: translateY(0.5px);
  box-shadow: var(--nm-in);
}
.edit-scope-pick {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  border-radius: var(--nm-radius);
  transition: box-shadow var(--nm-ease);
}
.edit-scope-pick:hover {
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.edit-scope-pick:active {
  box-shadow: var(--nm-in);
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   МЯГКИЙ РЕЛЬЕФ — СТРОКИ СЛОЁВ (редизайн 2026-08-18, шаг 2)
   Продолжение шага 1 на самом крупном семействе панели. Правило то же: форму держит тень, а не
   линия; выбранное вдавлено. И то же ограничение: РАЗЛИЧИМОСТЬ ВЫКЛЮЧЕННОГО СЛОЯ остаётся за
   цветом и значком глаза, а не за рельефом — на ней стоит left-panel-contrast (жалоба «левое
   меню почти не читается»), и подменять контраст рельефом здесь нельзя.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
.layer-item {
  border-radius: var(--nm-radius);
  transition:
    background var(--nm-ease),
    box-shadow var(--nm-ease);
}
/* Строка в покое — ровная поверхность: восемь выпуклых плашек подряд превращают список в
   стиральную доску, читать её невозможно. Рельеф появляется при наведении и выборе — там, где
   он что-то сообщает. */
.layer-item:hover {
  box-shadow: var(--nm-out-sm);
  background: var(--nm-surface);
}
/* ВЫБРАННЫЙ слой вдавлен — тот же язык, что у выбранной пилюли охвата. Акцентную полоску слева
   оставляем: она отвечает на вопрос «который из них» с одного взгляда, а рельеф на тёмном фоне
   читается слабее, чем цвет. */
.layer-item.active {
  border-color: transparent;
  background: var(--nm-surface-in);
  box-shadow:
    var(--nm-in),
    inset 2px 0 0 var(--accent);
}
/* Кнопки внутри строки — глаз, замок, чип охвата. Мелкие цели, поэтому рельеф тоже мелкий:
   держим их узнаваемыми, но не превращаем строку в россыпь пуговиц. */
.layer-visibility,
.layer-lock,
.layer-scope-chip {
  border-radius: var(--nm-radius);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    opacity var(--nm-ease);
}
.layer-visibility:hover,
.layer-lock:hover,
.layer-scope-chip:hover {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.layer-visibility:active,
.layer-lock:active,
.layer-scope-chip:active {
  box-shadow: var(--nm-in);
}
/* Строка-переход «Значки масти (пипсы)» — не слой, а дверь в другой список. Материал общий,
   иначе она читалась бы чужеродной. */
.layer-item.is-jump.is-anchor:hover {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
/* Шапка аккордеона недоступных слоёв — та же ниша, что у раскрытого охвата. */
.layers-unavail > summary:hover,
.layers-unavail-head:hover {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  border-radius: var(--nm-radius);
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   КНОПКА-КАРТА В ШАПКЕ «ПРАВКА» (идея заказчика 2026-08-18, шаг 3)
   Она отвечает на вопрос «какую сторону я правлю» ФОРМОЙ, а не текстом: видно рубашку —
   правится рубашка, видно лицо — лицо. Щелчок переворачивает; переворот показывает, что это
   одна карта с двух сторон, а не два разных места.

   Переворот сделан transform'ом (композиторное свойство): панель пересобирается часто, а
   анимация ширины/высоты в этом месте дала бы дрожь всего списка. Урок busy-overlay-smooth.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
.scope-card {
  position: relative;
  flex: 0 0 auto;
  /* Пропорция настоящей карты (63×88 мм ≈ 1:1.4). Размер поднимался дважды по кадрам: 26×36
     читалось «серым прямоугольником», 32×45 — уже картой, но мелкой для главного контрола
     панели. 44×62 — та же пропорция, и мотив рубашки на ней различим. */
  width: 44px;
  height: 62px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  perspective: 480px; /* глубина сцены: без неё поворот выглядит плоским сжатием */
  align-self: center;
  transition: transform var(--nm-ease);
}
/* КНОПКА ОБЯЗАНА ВЫГЛЯДЕТЬ КНОПКОЙ. Под курсором карта чуть подаётся вверх и её край
   подсвечивается акцентом — вместе со значком переворота это отвечает на вопрос «а её вообще
   можно нажать?», который заказчик задал прямым текстом. */
.scope-card:hover {
  transform: translateY(-1px);
}
.scope-card-inner {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 460ms cubic-bezier(0.2, 0.75, 0.3, 1);
}
.scope-card.is-face .scope-card-inner {
  transform: rotateY(180deg);
}
.scope-card-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1px;
  border-radius: 6px;
  overflow: hidden;
  backface-visibility: hidden;
  box-shadow: var(--nm-out-sm);
  transition: box-shadow var(--nm-ease);
}
.scope-card:hover .scope-card-face {
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1.5px var(--accent);
}
/* Рубашка — цветами ЖИВОЙ колоды: фон и мотив приходят из состояния (см. js/10k). */
.scope-card-back {
  background: var(--sc-bg, var(--bg-tertiary));
}
.scope-card-back svg {
  width: 100%;
  height: 100%;
  display: block;
}
.scope-card-back .sc-bg {
  fill: var(--sc-bg, var(--bg-tertiary));
}
/* Содержимое <pattern> НЕ наследует стиль от элемента, который им залит: цвет надо задать
   самим линиям внутри паттерна, иначе они рисуются «ничем» и миниатюра выходит пустой (так и
   было — карта показывала одну рамку). */
.scope-card-back pattern path {
  stroke: var(--sc-ink, var(--accent));
}
.scope-card-back .sc-net {
  opacity: 0.5;
}
.scope-card-back .sc-frame {
  stroke: var(--sc-edge, var(--sc-ink, var(--accent)));
  stroke-width: 1.2;
  opacity: 0.85;
}
/* Лицо — белая карта: ранг сверху, масть под ним. Белый здесь НЕ тема интерфейса, а сама
   игральная карта: она белая в любой теме, и подменять её фоном панели значило бы соврать. */
.scope-card-front {
  transform: rotateY(180deg);
  flex-direction: column;
  background: #f7f5f0;
}
.scope-card-rank,
.scope-card-suit {
  font-style: normal;
  font-weight: var(--fw-bold);
  color: #1d2026;
  line-height: 1;
}
.scope-card-rank {
  font-size: 17px;
  letter-spacing: -0.4px;
}
.scope-card-suit {
  font-size: 14px;
}
.scope-card-rank.is-red,
.scope-card-suit.is-red {
  color: #c8323f;
}
/* Значок переворота поверх карты — он и говорит «меня можно нажать». */
.scope-card-flip-hint {
  position: absolute;
  /* ВНУТРИ карты, а не свисая с угла: при отрицательных отступах значок вылезал за шапку на
     3 px (замер: низ значка 158 при нижней границе шапки 155) — то есть мог обрезаться или
     наехать на соседний блок. Угол самой карты — место надёжное и читается как «уголок». */
  right: 3px;
  bottom: 3px;
  width: 18px;
  height: 18px;
  /* Поверх 3D-слоя карты: грани лежат в preserve-3d контексте и без явного z-index накрывают
     значок собой (замер: элемент есть, 20×20, opacity 1 — а на кадре его нет). */
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Подложка полупрозрачная: значок лежит на рисунке карты и не должен его закрывать. */
  background: rgba(20, 22, 28, 0.55);
  color: #ffffff;
  backdrop-filter: blur(2px);
  opacity: 0.85;
  transition:
    color var(--nm-ease),
    opacity var(--nm-ease),
    transform var(--nm-ease);
  pointer-events: none; /* подсказка, а не вторая цель нажатия */
}
.scope-card-flip-hint svg {
  width: 13px;
  height: 13px;
}
.scope-card:hover .scope-card-flip-hint {
  background: var(--accent);
  color: #0d1013;
  opacity: 1;
  transform: rotate(-30deg);
}
/* Нажатие — карта уходит вглубь: то же «вдавливание», что у пилюль и строк слоя. */
.scope-card:active {
  transform: translateY(0.5px);
}
.scope-card:active .scope-card-face {
  box-shadow: var(--nm-in);
}
.scope-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 8px;
}
/* Запрет движения уважаем: переворот — смысловая анимация, но человеку, попросившему покой,
   достаточно смены грани без вращения. */
@media (prefers-reduced-motion: reduce) {
  .scope-card-inner {
    transition: none;
  }
}

/* ═══ ПОЛКА СЛОЁВ (редизайн 2026-08-18, шаг 4) ═══
   Убранная строка ПРЯЧЕТСЯ, а не удаляется: порядок наложения читается из DOM полной
   перестановкой (readLayerOrderFromDOM → setGlobalLayerOrder), и удалённая строка сорвала бы
   первое же перетаскивание. display:none — а не opacity/height — чтобы строка не участвовала
   ни в раскладке, ни в подборе места при перетаскивании (getDragAfterElement меряет
   прямоугольники). */
.layer-item.is-shelved {
  display: none !important;
}
/* Вход «+ Слой…». Отделён чертой, как якорь пипсов: он тоже не слой и не перетаскивается. */
.layers-shelf {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border);
}
/* Правила .layer-item.is-jump.is-shelf удалены 2026-08-19: вход в полку перестал быть строкой
   слоя (заказчик: «добавить слой сейчас выглядит сам как слой») и оформляется своим классом
   .layers-shelf-add. Мёртвый селектор оставлять нельзя — он бы обещал, что вещь ещё такая. */
.layer-shelf-count {
  margin-left: auto;
  padding-left: 6px;
  font-size: var(--fs-3xs);
  color: var(--text-muted);
  white-space: nowrap;
}
/* Поповер «Слои в списке» — в fixed-слое (позицию считает js/10k).
   МАТЕРИАЛ ТОТ ЖЕ, ЧТО У МЕНЮ ТУЛБАРА (.nm-dropdown): ниша, а в ней выпуклые клавиши.
   Заказчик 2026-08-19: «само меню не поддерживает наш новый стиль дизайна неоморфизма» — оно
   наследовало плоский .theme-menu, и рядом с переделанной панелью читалось как чужое.
   Своими правилами, а не общим классом: у него сетка «галочка + имя», а у пунктов тулбара —
   «значок + заголовок + пояснение»; общий класс пришлось бы тут же переопределять. */
.shelf-picker {
  z-index: 9000;
  min-width: 232px;
  padding: 8px;
  border: 1px solid transparent; /* место линии держит тень — габарит не прыгает между темами */
  border-radius: var(--nm-radius-lg);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-out), var(--shadow-lg);
}
.shelf-picker-head {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 2px 6px;
}
.shelf-picker-sub {
  font-size: var(--fs-3xs);
  color: var(--text-muted);
  padding: 0 6px 8px;
  line-height: 1.35;
}
/* Клавиша в покое. Каждая строка — самостоятельная плашка: список из галочек на общем фоне
   читался бы как текст, а здесь каждая строка нажимается. */
.shelf-picker-item {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 5px;
  padding: 8px 10px;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.shelf-picker-item:last-child {
  margin-bottom: 0;
}
/* Наведение — ПОДЪЁМ навстречу курсору, нажатие — обратное движение. Те же три состояния
   материала, что у меню «Создать»: покой ≠ наведение ≠ нажатие, и разница видна без цвета. */
.shelf-picker-item:hover {
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out),
    0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  transform: translateY(-1px);
  color: var(--text-primary);
}
.shelf-picker-item:active {
  box-shadow: var(--nm-in);
  transform: translateY(1px);
}
.shelf-picker-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  transform: translateY(-1px);
}
/* УБРАННЫЙ СЛОЙ — ВДАВЛЕННАЯ КЛАВИША. Состояние читается рельефом, а не одной галочкой:
   выключённая клавиша утоплена и приглушена, включённая выступает. */
.shelf-picker-item:not(.active) {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  color: var(--text-muted);
}
.shelf-picker-item.active {
  background: var(--nm-surface);
}
/* Галочка держит СВОЮ ширину и в снятом состоянии — иначе имена прыгают по горизонтали при
   каждом переключении, и список читается как дёргающийся. */
.shelf-tick {
  display: inline-block;
  width: 14px;
  flex: 0 0 auto;
  text-align: center;
  color: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
  .shelf-picker-item {
    transition: none;
  }
  .shelf-picker-item:hover,
  .shelf-picker-item:active,
  .shelf-picker-item:focus-visible {
    transform: none;
  }
}

/* ═══ ПОЯВЛЕНИЕ И УХОД СТРОКИ СЛОЯ ═══════════════════════════════════════════════════════
   Просьба заказчика 2026-08-19: «пусть произойдёт какая-нибудь анимация, он подсветится на
   несколько секунд, чтобы было понятно, что он добавился… то же самое и при удалении».

   ДВИЖЕНИЕ ЗДЕСЬ НЕСЁТ СМЫСЛ, А НЕ НАСТРОЕНИЕ. Кнопка «Добавить слой» стоит ВНИЗУ списка, а
   вернувшийся слой встаёт на СВОЁ место в порядке наложения — бывает, что выше видимой части.
   Подсветка отвечает на «что изменилось и где»: строка въезжает сверху и две секунды держит
   акцентный контур, который сам угасает. Уходящая, наоборот, схлопывается и уезжает вправо —
   соседи занимают её место на глазах, и пустота не выглядит сбоем.

   ЦЕНА ЧЕСТНО. Появление и подсветка идут только через transform/opacity — их считает
   композитор. Схлопывание высоты композитору не отдать, и это осознанная плата: это ОДНА
   строка на 260 мс, а альтернатива — дыра в списке, которая читается как поломка. */
@keyframes layerRowIn {
  from {
    opacity: 0;
    transform: translateY(-8px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* Контур зажигается быстро, держится и УГАСАЕТ САМ — человеку не нужно его закрывать. */
@keyframes layerRowGlow {
  0% {
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  62% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes layerRowOut {
  0% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
    transform: translateX(16px);
    height: 0;
    margin-bottom: 0;
    padding-top: 0;
    padding-bottom: 0;
  }
}
.layer-item.layer-just-added {
  position: relative;
  animation: layerRowIn 320ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Подсветка — отдельным слоем поверх строки: рельеф самой строки трогать нельзя, иначе
   вернувшийся слой две секунды выглядел бы «нажатым». Слой не ловит указатель. */
.layer-item.layer-just-added::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--accent) 16%, transparent),
    transparent
  );
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
  animation: layerRowGlow 2000ms ease-out both;
}
.layer-item.layer-leaving {
  overflow: hidden;
  pointer-events: none;
  animation: layerRowOut 260ms cubic-bezier(0.4, 0, 1, 1) both;
}
/* Системный запрет движения уважаем в ОБЕ стороны: сами классы в этом режиме не вешаются
   (js/10k), но правило оставляем — иначе всё держалось бы на одной стороне договора. */
@media (prefers-reduced-motion: reduce) {
  .layer-item.layer-just-added,
  .layer-item.layer-just-added::after,
  .layer-item.layer-leaving {
    animation: none;
  }
}

/* Кнопка «Убрать слой» в строке (2026-08-18). ВИДНА ВСЕГДА — невидимого контрола для человека
   не существует, ровно эта жалоба и прозвучала. Приглушена, чтобы не спорить с глазом и
   замком, и оживает под курсором. */
.layer-shelf-remove {
  flex: 0 0 auto;
  /* Ширина выбрана по замеру, а не на глаз: при 24 px «Медальон» ужимался до «Медаль…».
     Имя слоя важнее крестика — он опознаётся и в 18 px, а обрезанное имя читать нечем. */
  width: 18px;
  height: 24px;
  margin-left: 0;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-muted);
  opacity: 0.5;
  font-size: var(--fs-2xs);
  line-height: 1;
  cursor: pointer;
  border-radius: var(--nm-radius);
  transition:
    opacity var(--nm-ease),
    color var(--nm-ease),
    background var(--nm-ease);
}
.layer-item:hover .layer-shelf-remove {
  opacity: 0.85;
}
.layer-shelf-remove:hover {
  opacity: 1;
  color: var(--text-primary);
  background: color-mix(in srgb, var(--text-muted) 16%, transparent);
}
.layer-shelf-remove:focus-visible {
  opacity: 1;
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Строка «Значки масти» — теперь обычная строка слоя с настоящим глазом (жалоба 2026-08-18).
   Имя стало кнопкой-переходом, поэтому обнуляем кнопочные умолчания. */
.layer-name-jump {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.layer-item.is-anchor .layer-jump-hint {
  margin-left: auto;
  padding-left: 6px;
  color: var(--accent);
  opacity: 0;
  transition: opacity 0.16s ease;
}
.layer-item.is-anchor:hover .layer-jump-hint,
.layer-name-jump:focus-visible .layer-jump-hint {
  opacity: 1;
}
.layer-name-jump:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--nm-radius);
}

/* ПОРЯДОК ПЕРЕВЕРНУЛСЯ — И ПРАВИЛО ВМЕСТЕ С НИМ (2026-08-23).
   18 августа плашку «Правка» просили поставить СРАЗУ под список: тогда она стояла НИЖЕ него,
   список был `flex: 1`, растягивался на весь регион и уносил ответ «у кого правим» к нижнему
   краю — между ними зияла пустота в пол-экрана. Лечение было верным: список перестал расти.
   19 августа строка «Правка: …» переехала НАВЕРХ, под вкладки стороны (единый код на обеих
   сторонах). Порядок стал «шапка → вкладки → Правка → список», и прежнее лечение начало
   давать ровно ту болезнь, от которой спасало: список замер на 249 px, а под ним осталось
   403 px пустоты — измерено на окне 1050 px, видно 4 строки из 8 при высоте строки 46.
   Список снова растёт: он главное содержимое панели, и место под ним принадлежит ему.
   Плашке это ничем не грозит — она выше и не сдвинется. */
#panel-layers-region #tab-layers,
#panel-layers-region #tab-face-layers {
  flex: 1 1 auto;
  min-height: 0;
}
#panel-layers-region #scope-bar {
  flex: 0 0 auto;
}

/* Миниатюра карты — ИНДИКАТОР, а не кнопка: у рубашки заливка узором, у лица чистое поле со
   знаком. Он повторяет то, что человек уже узнал по кнопке-карте, и связывает два места. */
.layers-surface-mini {
  width: 9px;
  height: 13px;
  flex: 0 0 auto;
  border-radius: 2px;
  border: 1px solid currentColor;
  opacity: 0.75;
}
.layers-surface-zone[data-side='back'] .layers-surface-mini {
  background: repeating-linear-gradient(45deg, currentColor 0 1px, transparent 1px 3px);
}
.layers-surface-zone[data-side='face'] .layers-surface-mini {
  background: transparent;
  position: relative;
}
.layers-surface-zone[data-side='face'] .layers-surface-mini::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3px;
  height: 3px;
  margin: -1.5px 0 0 -1.5px;
  border-radius: 50%;
  background: currentColor;
}

/* ═══ ВКЛАДКИ СТОРОНЫ: «Рубашка | Лицо» ═══════════════════════════════════════════════════
   Заказчик о первой редакции: «совсем не понравилось, как ты вставил рубашку/лицо рядом с
   названием слоёв… непрофессионально». Он прав: пилюля 87 px, втиснутая в 264-px строку рядом
   с названием и шевроном, читалась как тулбар в заголовке, а подписи 11 px капсом и значки
   9×13 не читались вовсе.

   Вкладки решают ту же задачу НАТИВНО: они не украшают заголовок, а ВЛАДЕЮТ списком под собой.
   Активная вкладка срастается со списком (общий материал, нижняя граница снята), неактивная
   утоплена и отделена чертой. Это тот же приём, которым сделан весь редизайн: рельеф говорит
   «этот слой ближе», а не линия объясняет словами. */
.layers-side-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin: 0 var(--sp-2);
  border-bottom: 1px solid var(--border);
}
.layers-side-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 6px 8px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.02em;
  cursor: pointer;
  border-radius: var(--nm-radius) var(--nm-radius) 0 0;
  /* Место под будущую подчёркивающую линию резервируем ВСЕГДА: иначе активная вкладка выше
     неактивной на 2 px, и ряд дёргается при каждом переключении. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition:
    color var(--nm-ease),
    background var(--nm-ease),
    box-shadow var(--nm-ease);
}
/* НЕАКТИВНАЯ ВКЛАДКА — УТОПЛЕНА, активная (ниже) выдавлена: пара «лист впереди / лист
   позади» — это и есть неоморфная метафора вкладок. Прежде неактивная была прозрачной, и ряд
   читался как две надписи, а не как две вкладки. */
.layers-side-tab:not(.is-on) {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.layers-side-tab:hover:not(.is-on) {
  color: var(--text-secondary);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.layers-side-tab:active:not(.is-on) {
  transform: translateY(1px);
}
.layers-side-tab.is-on {
  color: var(--text-primary);
  background: var(--nm-surface);
  border-bottom-color: var(--accent);
  box-shadow:
    -2px -2px 6px var(--nm-hi),
    2px 0 6px var(--nm-lo);
  cursor: default;
}
.layers-side-tab:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -3px;
}
/* Миниатюра стороны — рисунком, а не словом: рубашка с узором, лицо с точкой-знаком.
   Размер выбран читаемым (14×20), а не декоративным: в первой редакции значок 9×13 не
   опознавался вовсе и работал как грязь. */
.layers-side-mini {
  width: 14px;
  height: 20px;
  flex: 0 0 auto;
  border-radius: 3px;
  border: 1px solid currentColor;
  opacity: 0.7;
}
.layers-side-tab.is-on .layers-side-mini {
  opacity: 1;
}
.layers-side-tab[data-side='back'] .layers-side-mini {
  background: repeating-linear-gradient(45deg, currentColor 0 1px, transparent 1px 4px);
}
.layers-side-tab[data-side='face'] .layers-side-mini {
  position: relative;
}
.layers-side-tab[data-side='face'] .layers-side-mini::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: currentColor;
}

/* Карта перестала быть кнопкой 2026-08-19 (см. js/10k): сторону выбирают вкладки, а карта
   показывает, КАКАЯ карта правится. Значок переворота и курсор-рука убраны — они обещали
   действие, которого больше нет: показанная ручка обязана работать (E-357). */
.scope-card {
  cursor: default;
}
.scope-card .scope-card-flip-hint {
  display: none;
}

/* ═══ СТРОКА «ПРАВКА» — ОДНА СТРОКА, ОДИНАКОВАЯ НА ОБЕИХ СТОРОНАХ (2026-08-19) ═══
   Заказчик: «не нравится, что у рубашки просто открываются слои, а у лица открывается ещё
   целое меню, целый блок… хотелось бы, чтобы всё было в едином дизайн-коде и никто никому не
   мешал». Блок был 99 px из-за миниатюры 44×62 и стоял только на лице. Миниатюра убрана
   (сторону показывают вкладки, карту — подпись), ярлык и значение встали В СТРОКУ, и строка
   есть на обеих сторонах. Наборы карт по-прежнему живут ВНУТРИ раскрытия — свёрнутая строка
   ничего не отодвигает. */
#scope-bar .scope-head {
  padding: 6px 8px;
}
#scope-bar .scope-head-text {
  /* В СТРОКУ, а не в колонку. Колонка была нужна, пока слева стояла карта 44×62 и текст надо
     было выровнять по её центру; карты нет — и два уровня текста только тянут блок вверх. */
  flex-direction: row;
  align-items: baseline;
  gap: 6px;
}
#scope-bar .scope-head-text .scope-head-val {
  font-size: var(--fs-xs);
  line-height: 1.2;
}
#scope-bar .scope-head-lab {
  flex: 0 0 auto;
}
#scope-bar .scope-head-val {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
}

/* ═══ ОДНО МЕНЮ ВЫБОРА КАРТ: ПРЕСЕТЫ + ТАБЛИЦА (2026-08-19) ═══
   Заказчик: «пусть останется только одно меню того же размера — Выбрать карты, в котором уже
   будут пресеты… и такая же таблица для выбора отдельных особенных карт». Прежде на один
   вопрос «какие карты правим» отвечали два контрола в разных местах: ряд пилюль в панели и
   окно с таблицей. Теперь вход один. */
/* Ширину меню задаёт ТАБЛИЦА карт, а не ряд пресетов: заказчик просил «одно меню ТОГО ЖЕ
   размера». Без потолка пять пресетов в строку растягивали окно с 315 до 394 px — меню начинало
   расти от того, сколько наборов у колоды. Потолок заставляет их переноситься. */
.scope-picker {
  max-width: 330px;
}
.scope-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 0 8px 6px;
  max-width: 100%;
}
.scope-presets .scope-seg {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
/* Пресет держит ширину по своей подписи: без этого «Джокер», оставшись один во второй строке,
   растягивался во всю ширину меню и читался как заголовок, а не как кнопка в ряду. */
.scope-presets .edit-scope-pill {
  flex: 0 0 auto;
}
.scope-picker-head {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 6px 8px 4px;
}
.scope-picker-sep {
  height: 1px;
  margin: 2px 8px 0;
  background: var(--border);
}

/* Строка «Правка» стала КНОПКОЙ-ВХОДОМ в меню (2026-08-19): прежде она разворачивала блок, и
   материал жил на раскрытом состоянии (.is-open) — с уходом раскрытия блок остался плоским и
   перестал читаться как контрол. Материал переезжает на саму строку: в покое лёгкий рельеф,
   под курсором ярче, при нажатии вдавливается. */
#scope-bar .edit-scope.scope-unified {
  padding: 4px 6px;
}
#scope-bar .scope-head {
  width: 100%;
  padding: 6px 8px;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
#scope-bar .scope-head:hover {
  background: var(--nm-surface);
  box-shadow: var(--nm-out);
}
#scope-bar .scope-head:active {
  box-shadow: var(--nm-in);
}
#scope-bar .scope-head:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ═══ МЕНЮ ВЫБОРА КАРТ — ПРЕМИАЛЬНАЯ ОТДЕЛКА В ТОМ ЖЕ МАТЕРИАЛЕ (2026-08-19) ═══
   Просьба заказчика: «доработай само открывающееся меню до премиального уровня в рамках нашей
   концепции неоморфизма».

   ЯЗЫК УЖЕ ЗАДАН ШАГОМ 1 РЕДИЗАЙНА, и мы его не изобретаем заново, а договариваем:
   поверхность выдавлена парой теней, ВЫБРАННОЕ — ВДАВЛЕНО (inset). Меню читается как
   физическая панель: приподнятое окно, внутри утопленная доска, на доске клавиши.

   Прежде клетки были обведены тонкой линией и выглядели полями ввода — то есть «сюда пишут»,
   хотя по ним нажимают. Линия здесь спорит с материалом: во всей панели форму держит тень. */
.scope-picker {
  padding: 10px;
  background: var(--nm-surface);
  border: none;
  border-radius: var(--nm-radius-lg);
  /* Пара теней + внутренний блик по верхней кромке: край окна ловит свет, как настоящая
     деталь. Без блика окно на тёмной теме сливается с панелью под ним. */
  box-shadow:
    var(--nm-out),
    var(--shadow-lg),
    inset 0 1px 0 rgba(255, 255, 255, 0.07);
}
/* Доска с картами — НИША: клавиши лежат в ней, а не парят над окном. */
.scope-picker .scope-grid {
  gap: 4px;
  padding: 8px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
/* Заголовки мастей: до правки чёрные ♠♣ красились тем же тихим токеном, что и подписи, и на
   тёмном фоне почти не читались — масть приходилось угадывать по позиции. */
.scope-picker .scope-head {
  font-size: var(--fs-md);
  color: var(--text-primary);
  opacity: 0.9;
  border-radius: 6px;
  transition:
    color var(--nm-ease),
    opacity var(--nm-ease);
}
.scope-picker .scope-head.red {
  color: var(--error);
  opacity: 1;
}
.scope-picker .scope-rank {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  border-radius: 6px;
  transition: color var(--nm-ease);
}
.scope-picker .scope-head:hover,
.scope-picker .scope-rank:hover {
  color: var(--accent);
  opacity: 1;
}
/* КЛАВИША. В покое — выпуклая, под курсором ярче, выбранная ВДАВЛЕНА и залита цветом масти.
   Так «выбрано» сказано материалом, а не только цветом: тот же приём, что у пилюль охвата. */
.scope-picker .scope-cell {
  height: 26px;
  border: none;
  border-radius: 7px;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    transform var(--nm-ease);
}
.scope-picker .scope-cell:hover {
  background: var(--bg-hover);
}
.scope-picker .scope-cell:active {
  transform: translateY(1px);
}
.scope-picker .scope-cell.on {
  background: color-mix(in srgb, var(--accent) 62%, var(--bg-tertiary));
  box-shadow:
    var(--nm-in),
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}
.scope-picker .scope-cell.on.red {
  background: color-mix(in srgb, var(--error) 58%, var(--bg-tertiary));
  box-shadow:
    var(--nm-in),
    inset 0 0 0 1px color-mix(in srgb, var(--error) 45%, transparent);
}
.scope-picker .scope-cell:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
/* Подвал: «Готово» — главная клавиша, остальные тихие. Все три в одном материале, разница
   только в весе цвета: иерархия сказана цветом и весом, а не размером (правило шага 1). */
.scope-picker .scope-foot {
  margin-top: 10px;
  gap: 6px;
}
.scope-picker .scope-btn {
  min-height: 34px;
  border: none;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-secondary);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease),
    background var(--nm-ease);
}
.scope-picker .scope-btn:hover {
  color: var(--text-primary);
  box-shadow: var(--nm-out);
}
.scope-picker .scope-btn:active {
  box-shadow: var(--nm-in);
}
.scope-picker .scope-btn.scope-done {
  color: var(--accent);
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 38%, transparent);
}
.scope-picker .scope-btn.scope-done:hover {
  box-shadow:
    var(--nm-out),
    inset 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
}
html[data-theme='light'] .scope-picker .scope-btn.scope-done {
  color: var(--accent);
}
.scope-picker .scope-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
/* Разделитель между наборами и таблицей — не линия во всю ширину, а дышащая черта: линия здесь
   сказала бы «две разные вещи», а это два ответа на ОДИН вопрос. */
.scope-picker-sep {
  height: 1px;
  margin: 4px 10px 2px;
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in srgb, var(--border) 90%, transparent) 18%,
    color-mix(in srgb, var(--border) 90%, transparent) 82%,
    transparent
  );
}

/* ═══ ВХОД «ДОБАВИТЬ СЛОЙ» — НЕ СТРОКА СЛОЯ (2026-08-19) ═══
   Заказчик: «добавить слой сейчас выглядит сам как слой». Он наследовал класс строки слоя и
   получал вместе с ним высоту, отступ под глаз и вес подписи — в списке читался как ещё одна
   строка, только без глаза.

   Форма говорит о роли: строка слоя — плотная плашка с рельефом под курсором; вход — ПУНКТИРНАЯ
   рамка (общепринятый знак «здесь можно добавить»), уже, тише, по центру. Рельеф ему не нужен:
   он не объект списка, а действие над списком. */
.layers-shelf-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 100%;
  min-height: 30px;
  padding: 5px 8px;
  background: transparent;
  border: 1px dashed color-mix(in srgb, var(--border) 90%, transparent);
  border-radius: var(--nm-radius);
  color: var(--text-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  cursor: pointer;
  transition:
    color var(--nm-ease),
    border-color var(--nm-ease),
    background var(--nm-ease);
}
.layers-shelf-add:hover {
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.layers-shelf-add:active {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.layers-shelf-add:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.layers-shelf-add-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid currentColor;
  font-size: 12px;
  line-height: 1;
}
.layers-shelf-add-name {
  white-space: nowrap;
}
/* Счётчик убранных остаётся, но становится тише подписи — он справка, а не действие. */
.layers-shelf-add .layer-shelf-count {
  margin-left: 2px;
  opacity: 0.85;
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   МЕНЮ «СОЗДАТЬ» — МЯГКИЙ РЕЛЬЕФ (просьба заказчика 2026-08-19)
   «Сейчас просто иконка стоит, аишная, а нужно такую же кнопку, как „Скачать“ — но всё в нашей
   новой концепции неоморфизма».

   ПОЧЕМУ НЕ .btn-primary, КАК У «СКАЧАТЬ». Две залитые акцентом кнопки рядом спорят за главную
   роль, и человек перестаёт видеть обе. «Скачать» — конец работы, «Создать» — её начало;
   одинаковыми они должны быть по ФОРМЕ (подпись рядом с иконкой, шеврон, та же высота), а не
   по цвету. Материал здесь — рельеф: плашка выдавлена парой теней, раскрытая вдавлена внутрь.

   Цвета — только токены --nm-*: светлая тема переопределяет их у себя, и хардкод увёл бы
   подложку тёмной темы в светлую (правило проекта).
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
.tool-btn.nm-btn {
  border: 1px solid transparent; /* место линии держит тень: габарит не прыгает между темами */
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font-weight: 600;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
.tool-btn.nm-btn:hover {
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
/* Раскрытое меню — кнопка ВДАВЛЕНА: состояние «сейчас открыто» видно без подсветки цветом. */
.tool-btn.nm-btn[aria-expanded='true'] {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.tool-btn.nm-btn .btn-label {
  font-size: var(--fs-sm);
}

/* МАТЕРИАЛ ВЫПАДАЮЩИХ МЕНЮ ТУЛБАРА — ОДИН НА ВСЕ (класс .nm-dropdown).
   Прежде эти правила были написаны на #create-dropdown, и меню «Скачать» осталось в старом
   плоском виде: два меню в одном ряду тулбара выглядели из разных продуктов (заказчик
   2026-08-19: «меню Скачать также нужно переделать в новом дизайне»). Селектор по id и был бы
   вторым ответом на вопрос «как выглядит меню тулбара» — оформление разъезжается ровно так.
   Кто добавляет третье меню, вешает класс и получает тот же материал.

   Само выпадающее. Обводки линией нет — её работу делает пара теней (--nm-out).
   --shadow-lg оставлен рядом: он отрывает меню от холста, чего рельеф в тёмной теме не даёт. */
.nm-dropdown.dropdown {
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-out), var(--shadow-lg);
  min-width: 322px;
  max-height: min(72vh, 720px);
  overflow-y: auto;
  padding: 8px;
}
/* Пункт — выпуклая плашка в нише, а не строка с разделителем. Разделительные линии сняты:
   в этом материале границу рисует рельеф, а линия поверх него читается как шов. */
.nm-dropdown .dropdown-item {
  border-bottom: none;
  border-radius: var(--nm-radius);
  margin-bottom: 6px;
  padding: 11px 13px;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease);
}
.nm-dropdown .dropdown-item:last-child {
  margin-bottom: 0;
}
/* ЖИВОЙ ОТКЛИК НА ПЕРЕХОД МЕЖДУ СТРОКАМИ (заказчик 2026-08-19: «при переходе от одной строчки
   меню к другой не происходит ни вдавливания, ни анимации»).
   Прежнее наведение добавляло только кольцо в 1 px и оставляло ту же тень — на глаз строка не
   менялась вовсе, и меню казалось мёртвым. Теперь она ПОДНИМАЕТСЯ навстречу курсору: тень
   глубже, сдвиг на пиксель вверх, текст и значок ярче. Нажатие — обратное движение: вдавливание
   и сдвиг вниз. Разница между покоем, наведением и нажатием читается тремя разными состояниями
   материала, а не одним оттенком. */
.nm-dropdown .dropdown-item:hover {
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out),
    0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  transform: translateY(-1px);
}
.nm-dropdown .dropdown-item:hover strong {
  color: var(--text-primary);
}
/* Значок в нише — под курсором ниша светлеет и глиф берёт акцент: движение поддержано цветом,
   но цвет не единственный признак (правило «не сообщать состояние одним цветом»). */
.nm-dropdown .dropdown-item:hover .dropdown-icon {
  color: var(--accent);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.nm-dropdown .dropdown-item:active {
  box-shadow: var(--nm-in);
  transform: translateY(1px);
}
.nm-dropdown .dropdown-item:active .dropdown-icon {
  box-shadow: var(--nm-in);
}
.nm-dropdown .dropdown-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  box-shadow: var(--nm-out);
  transform: translateY(-1px);
}
/* Движение — только transform и box-shadow: композиторные свойства, 55 строк меню не заставят
   пересчитывать раскладку. И оно уважает системный запрет движения. */
@media (prefers-reduced-motion: reduce) {
  .nm-dropdown .dropdown-item,
  .nm-dropdown .dropdown-icon {
    transition: none;
  }
  .nm-dropdown .dropdown-item:hover,
  .nm-dropdown .dropdown-item:focus-visible,
  .nm-dropdown .dropdown-item:active {
    transform: none;
  }
}
.nm-dropdown .dropdown-group-header {
  margin: 10px 6px 6px;
  padding: 0;
  background: transparent;
  border: none;
}
.nm-dropdown .dropdown-group-header:first-child {
  margin-top: 2px;
}
/* Иконка пункта — вдавленный кружок: тот же приём, что у пилюль охвата (шаг 1 редизайна). */
.nm-dropdown .dropdown-icon {
  border-radius: 50%;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  padding: 6px;
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease),
    color var(--nm-ease);
  flex-shrink: 0;
}
/* «Обновить только …» — шесть коротких действий одного рода. Столбиком они растянули бы меню
   вдвое, поэтому идут сеткой: ряд читается как одно семейство. */
.nm-dropdown .cm-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}
.nm-dropdown .cm-grid .dropdown-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-bottom: 0;
  padding: 9px 4px;
  text-align: center;
}
.nm-dropdown .cm-grid .dropdown-icon {
  padding: 5px;
}
.nm-dropdown .cm-grid .dropdown-item strong {
  font-size: var(--fs-xs);
  font-weight: 600;
}
@media (prefers-reduced-motion: reduce) {
  .tool-btn.nm-btn,
  .nm-dropdown .dropdown-item {
    transition: none;
  }
}

/* ═══ ПРЕВЬЮ ШРИФТА ИНДЕКСА НА КНОПКЕ ══════════════════════════════════════════════════════
   Просьба заказчика 2026-08-19: «чтобы можно было получать вау-эффект после каждой замены».
   Эффект живёт в ВЫБОРЕ: на кнопке нарисован сам глиф тем шрифтом, который она включает —
   список имён этого не даёт, по названиям шрифт подбирают вслепую.

   Глиф «A 10» выбран не случайно: двузначная «10» — самое узкое место индекса, и на кнопке
   сразу видно, как шрифт с ней справляется. */
.idx-font-preview {
  display: block;
  font-size: 19px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: 0.02em;
  color: var(--text-primary);
}
/* Фирменный вектор рисуется НЕ шрифтом, и его превью честно об этом говорит: приглушённый
   служебный глиф вместо обещания «вот так будет выглядеть». */
.idx-font-deck {
  font-family: Georgia, 'Times New Roman', serif;
  color: var(--text-muted);
}
.seg-chip.active .idx-font-preview {
  color: var(--accent);
}

/* ═══ ПРЕДУПРЕЖДЕНИЕ В ИНСПЕКТОРЕ ══════════════════════════════════════════════════════════
   Не запрет, а голос продукта: сочетание законно, но у него есть цена, о которой человек
   узнает иначе только получив тираж из типографии. Цвет — токеном, иначе светлая тема
   получит нечитаемый текст. */
.insp-hint {
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--text-muted);
  margin: 8px 0 4px;
}
.insp-hint--warn {
  padding: 8px 10px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  color: var(--text-secondary);
  border-left: 3px solid var(--warn, #d9822b);
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   МЯГКИЙ РЕЛЬЕФ — ИНСПЕКТОР (редизайн 2026-08-20, шаг 4)
   Просьба заказчика: «правое меню нужно переделывать в новый дизайн-код неоморфизм».

   ПРОДОЛЖЕНИЕ, А НЕ НОВЫЙ ЯЗЫК. Левая панель одета 18 августа теми же токенами; здесь ни одной
   собственной тени — только --nm-out-sm / --nm-in / --nm-surface. Своя тень «на глаз» разошлась
   бы с левой панелью при первой правке палитры: видно глазом, не поймано ничем. На этом стоит
   первая проверка пробы inspector-neomorphism (рельеф слева и справа сверяется строкой).

   ГРАНИЦА, КОТОРУЮ НЕ ПЕРЕХОДИМ — та же: рельеф добавляет ФОРМУ, но не отнимает КОНТРАСТ.
   Цвета текста не трогаем ни одного; порог 4.5:1 в обеих темах стережёт пятая проверка пробы.

   ТРИ СОСТОЯНИЯ ОБЯЗАТЕЛЬНЫ. Покой выпуклый, наведение — выпуклое с акцентной каймой, нажатие
   ВДАВЛЕНО. Ровно этого заказчик не нашёл в меню «Создать» («не происходит ни вдавливания, ни
   анимации»), и до этой правки кнопка выбора в инспекторе тоже не отличала нажатие от
   наведения — замер показал разницу кадров 0.

   ЛИНИЮ ЗАМЕНЯЕТ ТЕНЬ, А ГАБАРИТ ОСТАЁТСЯ. Везде border: 1px solid transparent, а не border:
   none — иначе контрол под курсором меняет размер и соседи разъезжаются.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── КНОПКИ ВЫБОРА (.seg-chip) — самое крупное семейство панели ─────────────────────────── */
:is(#panel-right, .resource-flyout) .seg-chip {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease),
    transform var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .seg-chip:hover {
  transform: none;
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
/* ВЫБРАННАЯ КНОПКА ВДАВЛЕНА — это «выбрано» на языке материала. Цвет акцента остаётся:
   различать выбор одним рельефом нельзя (правило «не только цветом» работает и наоборот). */
:is(#panel-right, .resource-flyout) .seg-chip.active {
  transform: none;
  border-color: transparent;
  background: var(--nm-surface-in);
  box-shadow:
    var(--nm-in),
    inset 0 0 0 1px var(--accent);
}
:is(#panel-right, .resource-flyout) .seg-chip:active {
  transform: none;
  box-shadow: var(--nm-in);
}

/* ── МЯГКИЕ КНОПКИ ДЕЙСТВИЯ ────────────────────────────────────────────────────────────── */
/* МЯГКИЕ КНОПКИ ДЕЙСТВИЯ — правило ОБЩЕЕ (волна 5). Было ,
   и кнопка «Показать ещё» в пикере иконок — тот же .btn-soft — оставалась плоской: она живёт
   во всплывающем окне, а не в панели. Третий случай одной болезни за три волны (до неё так же
   лечили тумблер и поля ввода), поэтому область действия снята совсем, а не расширена ещё на
   один контейнер. */
.btn-soft,
.ai-gen-btn,
.variation-btn,
.inline-icon-more-btn,
.cmyk2-btn,
.acc-tool {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease),
    transform var(--nm-ease);
}
.btn-soft:hover,
.ai-gen-btn:hover,
.variation-btn:hover,
.inline-icon-more-btn:hover,
.cmyk2-btn:hover,
.acc-tool:hover {
  transform: none;
  border-color: transparent;
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.btn-soft:active,
.ai-gen-btn:active,
.variation-btn:active,
.inline-icon-more-btn:active,
.cmyk2-btn:active,
.acc-tool:active {
  transform: none;
  box-shadow: var(--nm-in);
}

/* ── ЧИПЫ ПРЕСЕТОВ ползунка ────────────────────────────────────────────────────────────── */
:is(#panel-right, .resource-flyout) .slider-preset-chip {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .slider-preset-chip:hover {
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
:is(#panel-right, .resource-flyout) .slider-preset-chip:active,
:is(#panel-right, .resource-flyout) .slider-preset-chip.active {
  box-shadow: var(--nm-in);
}

/* ── СТЕПЕРЫ −/+ ───────────────────────────────────────────────────────────────────────── */
:is(#panel-right, .resource-flyout) .slider-step {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .slider-step:hover {
  border-color: transparent;
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
:is(#panel-right, .resource-flyout) .slider-step:active {
  box-shadow: var(--nm-in);
}

/* ── ПОЛЯ ВВОДА — НИША. Место, куда пишут, утоплено; это же отличает его от кнопки.
      ОБЛАСТЬ ДЕЙСТВИЯ ОБЩАЯ (волна 2), а была `#panel-right …` — и поиск по иконкам во
      флайауте ресурсов, поле цвета в палитре и поля AI-запроса оставались плоскими рамками
      из прежнего продукта. Та же болезнь, что у тумблера: правило написано от контейнера,
      а орган живёт в трёх местах. Исключены ползунки (input[type=range] — у них своя
      дорожка) и служебные скрытые поля пикеров. ─────────────────────────────────────────── */
.slider-label-value,
.type-search,
.color-hex-input,
.ai-input,
input[type='text'],
input[type='number'],
input[type='search'],
select,
textarea {
  border: 1px solid transparent;
  /* Поле ввода утоплено, но берёт СВЕТЛУЮ утопленную поверхность, а не канавку: канавка —
     это паз под чипы и ручку, а лист, на котором пишут, в светлой теме обязан остаться
     белым. Разный смысл — разные токены. */
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
.slider-label-value:focus,
.type-search:focus,
.color-hex-input:focus,
.ai-input:focus,
input[type='text']:focus,
input[type='number']:focus,
input[type='search']:focus,
select:focus,
textarea:focus {
  border-color: transparent;
  box-shadow:
    var(--nm-in),
    0 0 0 2px var(--accent-dim);
}

/* ── ТУМБЛЕР одет в БАЗОВОМ правиле (.toggle, волна 2) и потому одинаков во всех панелях.
      Здешний дубль снят: он одевал жёлоб только в правой панели, и один и тот же орган
      выглядел по-разному в инспекторе, во флайауте ресурсов и в «Настройках» — ровно та
      пестрота, против которой затевался единый материал. ─────────────────────────────── */

/* ── ОБРАЗЕЦ ЦВЕТА. Рамку заменяет рельеф, но ЦВЕТ остаётся до края — иначе образец врёт. ─ */
:is(#panel-right, .resource-flyout) .color-preview {
  border-color: transparent;
  box-shadow: var(--nm-out-sm);
  transition: box-shadow var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .color-preview:hover {
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 2px var(--accent);
}

/* ── ШАПКИ АККОРДЕОНА. Их в панели единицы, поэтому выпуклые в покое: так группа читается
      плашкой, а не строкой текста. Восемь подряд превратили бы панель в стиральную доску —
      этот урок оплачен строками слоёв в левой панели, там рельеф появляется при наведении. ─ */
:is(#panel-right, .resource-flyout) .acc-header {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    background var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .acc-header:hover {
  border-color: transparent;
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
/* Раскрытая группа — ниша: видно, что содержимое сейчас развёрнуто под ней. */
:is(#panel-right, .resource-flyout) .acc-header:not(.collapsed) {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  border-bottom-color: transparent;
}
:is(#panel-right, .resource-flyout) .acc-header.collapsed {
  background: var(--nm-surface);
}

/* ── ПОЛЗУНОК: трек — жёлоб, бегунок — выдавленная кнопка ──────────────────────────────── */
:is(#panel-right, .resource-flyout) .slider-group input[type='range'] {
  /* Трек подрос с 6 до 8 px: в жёлоб глубиной 6 px мягкая тень не помещается и съедает
     заливку — проверено кадром. */
  height: 8px;
  box-shadow: var(--nm-in);
}
:is(#panel-right, .resource-flyout) .slider-group input[type='range']::-webkit-slider-thumb {
  border: 2px solid transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent);
}
:is(#panel-right, .resource-flyout) .slider-group input[type='range']::-moz-range-thumb {
  border: 2px solid transparent;
  box-shadow: var(--nm-out-sm);
}

/* ── КНОПКИ РАССЫЛКИ «Применить так же к:» — те же пилюли, тот же материал ─────────────── */
:is(#panel-right, .resource-flyout) .insp-propagate-btn {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
:is(#panel-right, .resource-flyout) .insp-propagate-btn:hover {
  border-color: transparent;
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
:is(#panel-right, .resource-flyout) .insp-propagate-btn:active {
  box-shadow: var(--nm-in);
}

/* ── КОНТЕЙНЕРЫ-НИШИ. Раскрытая группа и служебные плашки — углубление в поверхности, из
      которого выдавлены кнопки. Это тот же приём, что у раскрытой плашки охвата слева. ──── */
:is(#panel-right, .resource-flyout) .acc-body,
:is(#panel-right, .resource-flyout) .insp-propagate {
  border: 1px solid transparent;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
:is(#panel-right, .resource-flyout) .acc-body {
  border-top: 1px solid transparent;
  border-radius: 0 0 var(--nm-radius) var(--nm-radius);
}
:is(#panel-right, .resource-flyout) .insp-propagate {
  border-radius: var(--nm-radius);
}
/* Раскрытая шапка и её тело — ОДНА ниша, поэтому у шва нет скруглений. */
:is(#panel-right, .resource-flyout) .acc-header:not(.collapsed) {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

/* ── ПОМЕТКА ОХВАТА СЕКЦИИ — вдавленный ярлык, а не кнопка: нажимать её нельзя. ────────── */
:is(#panel-right, .resource-flyout) .insp-deck-badge {
  border-color: transparent;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}

/* ── КНОПКА СВОРАЧИВАНИЯ ПАНЕЛИ ────────────────────────────────────────────────────────── */
.inspector-collapse-btn {
  border: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  border-radius: var(--nm-radius);
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.inspector-collapse-btn:hover {
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.inspector-collapse-btn:active {
  box-shadow: var(--nm-in);
}

/* ── ГРАНИЦА ПАНЕЛИ И ЕЁ ШАПКА. Линию заменяет мягкая тень, но МЕСТО линии остаётся за
      прозрачной рамкой: убери её совсем — панель станет на пиксель шире и лист пересчитает
      раскладку плиток. ──────────────────────────────────────────────────────────────────── */
#panel-right {
  border-left: 1px solid transparent;
  box-shadow: -6px 0 14px -10px var(--nm-lo);
}
#panel-right .panel-title {
  border-bottom: 1px solid transparent;
  background: var(--nm-surface);
  box-shadow: 0 6px 12px -12px var(--nm-lo);
}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   ШАПКА ИНСПЕКТОРА — КРУПНОЕ ИМЯ ТОГО, ЧТО ПРАВИМ (просьба заказчика 2026-08-20)
   «Верхняя правая часть, где пишется, какая карта редактируется, — сильно крупно. Убрав
   кнопки свернуть всё, развернуть всё, занять это пространство максимально.»

   ИМЯ — ГЛАВНОЕ, ОСТАЛЬНОЕ УСТУПАЕТ. Ярлык «Правим» мелкий и приглушённый; имя набрано
   крупно и переносится, а не обрезается: «Выбрано 12 карт» и «Карта 10♦» одинаково должны
   читаться целиком. Обрезанное имя бесполезнее отсутствующего — этот урок уже оплачен
   бейджем охвата (E-339).
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
.insp-headline {
  /* ЛИПКАЯ ШАПКА (просьба заказчика 2026-08-25: «оставить на том же месте при прокручивании,
     чтобы всегда было видно, что правим»). Прецедент липкого жильца в этом же скроллере уже
     есть — панель цвета узора; поэтому и приём тот же, без единой строки JS.
     ПОДЛОЖКА ОБЯЗАНА БЫТЬ НЕПРОЗРАЧНОЙ: рельефный градиент поверх ничего не перекрывает, и
     под шапкой поехал бы контент. */
  position: sticky;
  /* ОТРИЦАТЕЛЬНЫЙ top — НЕ ХИТРОСТЬ, А ТОЧНОЕ МЕСТО. Липкий элемент прилипает к КРАЮ ПОЛЯ
     прокрутки, а у контейнера сверху 12 px отступа: при top:0 в этом просвете видно уезжающий
     контент — узкая полоска чужой секции, читается как дефект вёрстки. Поймано скриншотом,
     замер её не показывал. */
  top: -12px;
  z-index: 7;
  /* ВОЗДУХА МЕНЬШЕ, БУКВ БОЛЬШЕ. Заказчик 2026-08-25: «много пустого места в блоке „Что
     правим", можно ещё крупнее сделать обозначение». Верхний отступ обязан покрывать зазор
     контейнера (иначе под шапкой просвечивает контент), но нижний и внутренние были щедрее
     нужного — их и срезаем. */
  --insp-head-h: 104px;
  background-color: var(--bg-secondary);
  /* ШАПКА ЗАКРЫВАЕТ И ВЕРХНИЙ ОТСТУП КОНТЕЙНЕРА. Без этого в просвете над ней видно
     уезжающий контент — узкая полоска чужой секции, которая читается как дефект вёрстки
     (поймано скриншотом, замер её не видел). Растягиваем блок отрицательным полем и
     возвращаем внутренний отступ. */
  margin: -12px -2px 10px;
  padding: 18px 12px 8px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.insp-headline-lab {
  font-size: var(--fs-3xs, 10px);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1px;
  /* В ОДНУ СТРОКУ. Перенос служебной подписи добавлял блоку 14 px и делал его высоту разной
     на разных охватах — блок «дышал» при каждом переключении. Полный текст в подсказке. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.insp-headline-name {
  /* «Сильно крупно» — прямая просьба заказчика. 24 px против 15 px прежнего заголовка: имя
     того, что правим, читается первым, не приглядываясь. */
  min-height: 34px;
  display: flex;
  align-items: center;
  /* Крупнее прежнего и у НЕ-карты: «Рубашка», «Фигуры», «Все лица» тоже читаются первыми. */
  font-size: 30px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  overflow-wrap: break-word;
  word-break: break-word;
}
/* НОМИНАЛ КАРТЫ — САМОЕ КРУПНОЕ В БЛОКЕ (просьба заказчика 2026-08-25). Бокс имени имеет
   фиксированную высоту, поэтому при «Фигурах» и «Рубашке» шапка не прыгает. */
.insp-headline-name.is-card {
  /* КРУПЕН ТОЛЬКО НОМИНАЛ, слово «Карта» остаётся служебной приставкой. Текст узла при этом
     равен тому, что отдал владелец факта, — разметка не подменяет содержание. */
  display: flex;
  align-items: baseline;
  gap: 6px;
  line-height: 1;
}
.insp-headline-pre {
  font-size: var(--fs-3xs, 10px);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.insp-headline-rank {
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -0.02em;
}
.insp-headline-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
/* Быстрый выбор «Все лица» — обычная кнопка материала, чтобы читалась нажимаемой. */
.insp-headline-all {
  flex: 1 1 auto;
  min-height: 30px;
  padding: 6px 10px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-weight: 600;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.insp-headline-all:hover {
  color: var(--text-primary);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.insp-headline-all:active {
  box-shadow: var(--nm-in);
}
/* Переключатель разделов — мелкая цель, поэтому и рельеф мелкий. */
.insp-headline-acc {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-secondary);
  font-size: var(--fs-md, 15px);
  line-height: 1;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.insp-headline-acc:hover {
  color: var(--text-primary);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.insp-headline-acc:active {
  box-shadow: var(--nm-in);
}
.insp-headline-sub {
  margin-top: 3px;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  overflow-wrap: break-word;
  word-break: break-word;
}
/* Заголовок панели гасим ТОЛЬКО когда он дословно повторяет крупное имя (см. js/08u).
   Текст остаётся в DOM — его читают пробы и программы чтения с экрана. */
/* Прежнее правило title-dup (font-size: 0 при сохранённых отступах) УДАЛЕНО: оно и оставляло
   пустую полосу в 37 px, ради которой всё и затевалось. Строка теперь скрыта sr-only всегда —
   см. блок «ВЕРХНЯЯ СТРОКА ИНСПЕКТОРА» ниже. */

/* Плитка раздела «Цвет колоды» / «Файлы колоды»: строка-кнопка во всю ширину. */
.insp-deck-tile {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  margin: 0 0 10px;
  padding: 9px 11px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  text-align: left;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.insp-deck-tile:hover {
  color: var(--text-primary);
  box-shadow:
    var(--nm-out-sm),
    0 0 0 1px var(--accent-dim);
}
.insp-deck-tile:active {
  box-shadow: var(--nm-in);
}
.insp-deck-tile b {
  color: var(--text-primary);
}
.insp-deck-tile-sw {
  flex: 0 0 auto;
  width: 34px;
  height: 16px;
  border-radius: 4px;
  box-shadow: var(--nm-in);
}
.insp-deck-tile-ic {
  flex: 0 0 auto;
  font-size: var(--fs-md, 15px);
  line-height: 1;
}
.insp-deck-tile-lab {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.35;
}

/* Превью принесённых файлов в разделе «Файлы колоды» (просьба заказчика 2026-08-21).
   Показываем ИСХОДНИК файла: обработка логотипа обратима, и узнаёт человек свой файл именно
   по исходнику, а не по обработанному образу. */
.insp-deck-tile-ic.is-thumb {
  width: 34px;
  height: 24px;
  border-radius: 4px;
  background-color: var(--bg-primary);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  box-shadow: var(--nm-in);
}
.insp-files-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 10px;
}
.insp-file-thumb {
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background-color: var(--bg-primary);
  background-size: cover;
  background-position: center;
  box-shadow: var(--nm-out-sm);
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease);
}
.insp-file-thumb:hover {
  box-shadow:
    var(--nm-out-sm),
    0 0 0 2px var(--accent);
}
.insp-file-thumb:active {
  box-shadow: var(--nm-in);
}

/* Полоса в виде «карта крупно» тянется рукой (просьба 2026-08-21) — курсор называет жест
   до того, как человек попробует. Базовое правило вида ставит cursor: default, потому
   переопределяем здесь, ПОСЛЕ него. */
#canvas-area[data-view='focus'] #allsides-sheet.deck-mode {
  cursor: grab;
}
#canvas-area[data-view='focus'] #allsides-sheet.deck-mode.deck-panning {
  cursor: grabbing;
  user-select: none;
}

/* ═══ МЯГКИЙ РЕЛЬЕФ — СЕМЕЙСТВО ВЫПАДАЮЩИХ МЕНЮ (шаг 5 плана «Неоморфизм-2», 2026-08-21) ═══
   Просьба заказчика: «переделать в новом дизайне неоморфизме верхние выпадающие меню».

   ЗАМЕР ДО: «Создать» и «Скачать» уже были в рельефе (.nm-dropdown), а «Вид», «Настройки»,
   «Показ», «История» и меню темы остались плоскими — на одном тулбаре жили два разных
   продукта.

   МАТЕРИАЛ ОДИН, И ЭТО ГЛАВНОЕ. Контейнер — ниша (утоплённая поверхность + внешняя тень),
   строки — выпуклые плашки, ВЫБРАННОЕ ВДАВЛЕНО. Вдавленность несёт смысл: в рельефном
   интерфейсе «нажато» читается физически, а не только цветом — правило «не сообщать состояние
   одним цветом» выполняется без единой подписи.

   ЦВЕТА — ТОЛЬКО ТОКЕНЫ: тем три (тёмная, noir, светлая), и светлая переопределяет --nm-*
   у себя. Любой хардкод здесь ломает её молча.

   ДВИЖЕНИЕ — только box-shadow/transform, 220 мс (--nm-ease). Ни одного свойства, вызывающего
   пересчёт раскладки. */
.theme-menu,
.hist-pop {
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-out), var(--shadow-lg);
  padding: 8px;
}
.theme-menu-item,
.face-quick-grp,
.hist-row,
.theme-menu .deck-comp-pill,
.theme-menu .view-format-pill,
.theme-menu .view-proof-pill,
.theme-menu .view-format-act,
.theme-menu .deck-custom-head {
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.theme-menu-item + .theme-menu-item,
.hist-row + .hist-row {
  margin-top: 6px;
}
.theme-menu-item:hover,
.face-quick-grp:hover,
.hist-row:hover,
.theme-menu .deck-comp-pill:hover,
.theme-menu .view-format-pill:hover,
.theme-menu .view-proof-pill:hover,
.theme-menu .view-format-act:hover,
.theme-menu .deck-custom-head:hover {
  background: var(--nm-surface);
  box-shadow:
    var(--nm-out),
    0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  transform: translateY(-1px);
  color: var(--text-primary);
}
.theme-menu-item:active,
.face-quick-grp:active,
.hist-row:active,
.theme-menu .deck-comp-pill:active,
.theme-menu .view-format-pill:active,
.theme-menu .view-proof-pill:active,
.theme-menu .view-format-act:active {
  transform: translateY(0);
  box-shadow: var(--nm-in);
}
/* ВЫБРАННОЕ — ВДАВЛЕНО. Цвет остаётся акцентным, но состояние читается и без него. */
/* ПИКЕР «ДОБАВИТЬ СЛОЙ» ИСКЛЮЧЁН НАМЕРЕННО. У него рельеф означает ДРУГОЕ: там вдавлена
   строка УБРАННОГО слоя, а включённый выступает (см. .shelf-picker-item ниже). Общее правило
   «выбранное вдавлено» перебивало этот смысл — оба состояния становились вдавленными, и проба
   shelf-picker-toggle это поймала. Специфичность у правил равная, побеждает порядок в файле,
   поэтому исключение задано явно, а не надеждой на порядок. */
.theme-menu-item.active:not(.shelf-picker-item),
.face-quick-grp.active,
.hist-row.active,
.theme-menu .deck-comp-pill.active,
.theme-menu .view-format-pill.active,
.theme-menu .view-proof-pill.active,
.theme-menu .view-format-act.active {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  color: var(--accent);
  transform: none;
}
.theme-menu-item.active:not(.shelf-picker-item):hover,
.face-quick-grp.active:hover,
.hist-row.active:hover,
.theme-menu .deck-comp-pill.active:hover,
.theme-menu .view-format-pill.active:hover,
.theme-menu .view-proof-pill.active:hover,
.theme-menu .view-format-act.active:hover {
  box-shadow: var(--nm-in);
  transform: none;
}

/* ПРАВИЛО ПЛОТНОСТИ: в плотных сетках (13 рангов, четыре масти, форматы карт) чипы НЕ делаем
   выпуклыми поштучно — полсотни плашек рядом это шум, а не рельеф. Сетка лежит в общей
   вдавленной канавке, и выпуклый в ней ровно один — активный. */
.theme-menu .dc-row,
.theme-menu .face-quick-ranks,
.theme-menu .face-quick-suits,
.theme-menu .face-quick-suitgroups,
.theme-menu .view-idle-row,
.theme-menu .seg {
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  padding: 6px;
}
/* Ряд «Запускать сам после простоя» — ровно тот же сегментированный переключатель, что и
   ранги: пять взаимоисключающих значений в тесном ряду. Он оставался в прежнем материале
   (рамка + заливка активного) просто потому, что не попал в список — на одном меню жили два
   продукта: верх в рельефе, низ из старого. */
.theme-menu .view-idle-row {
  gap: 4px;
  margin: 0 10px 8px;
  padding: 5px;
}
.theme-menu .dc-chip,
.theme-menu .view-idle,
.theme-menu .fq-chip,
.theme-menu .face-quick-suit,
.theme-menu .face-quick-ranks button {
  border: 1px solid transparent;
  background: none;
  box-shadow: none;
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.theme-menu .dc-chip:hover,
.theme-menu .view-idle:hover,
.theme-menu .fq-chip:hover,
.theme-menu .face-quick-suit:hover,
.theme-menu .face-quick-ranks button:hover {
  color: var(--text-primary);
  transform: translateY(-1px);
}
.theme-menu .dc-chip.active,
.theme-menu .view-idle.active,
.theme-menu .fq-chip.active,
.theme-menu .face-quick-suit.active,
.theme-menu .face-quick-ranks button.active {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
}
/* Активный чип показа опознаётся ещё и АКЦЕНТНЫМ ТЕКСТОМ: в меню «Показ» выпуклых чипов
   бывает несколько подряд (ранг + масть), и одного рельефа мало, чтобы прочесть «показано
   сейчас именно это». Цвет масти при этом не трогаем — червы и бубны обязаны остаться
   красными, иначе чип врёт о самой карте. */
.theme-menu .fq-chip.active {
  color: var(--accent);
}
.theme-menu .face-quick-suit.active .fqs-lb {
  color: var(--accent);
}

/* ── ОБРАЗЦЫ ЦВЕТА ТОРЦА. Тот же случай, что у образца цвета в инспекторе: рамку заменяет
      рельеф, но САМ ЦВЕТ идёт до края — обод из чужого цвета врал бы о том, каким выйдет
      торец. Активный опознаётся кольцом акцента поверх рельефа: рельеф говорит «это орган»,
      кольцо — «выбран этот». ────────────────────────────────────────────────────────────── */
.theme-menu .view-edge {
  border-color: transparent;
  box-shadow: var(--nm-out-xs);
  transition:
    transform 0.12s ease,
    box-shadow var(--nm-ease);
}
.theme-menu .view-edge.active {
  border-color: transparent;
  box-shadow:
    var(--nm-out-xs),
    0 0 0 2px var(--accent);
}
.theme-menu .view-edge:active {
  box-shadow: var(--nm-in-sm);
}

/* Кнопки-открыватели тулбара: в покое выпуклые, при открытом меню ВДАВЛЕНЫ. Габарит держит
   прозрачная рамка — иначе тулбар дёргался бы на каждое открытие (урок inspector-no-jump). */
#btn-view-menu,
#btn-settings-menu,
#show-value-btn,
#btn-undo,
#btn-redo {
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease);
}
#btn-view-menu:hover,
#btn-settings-menu:hover,
#show-value-btn:hover,
#btn-undo,
#btn-redo:hover {
  box-shadow: var(--nm-out);
  transform: translateY(-1px);
}
#btn-view-menu[aria-expanded='true'],
#btn-settings-menu[aria-expanded='true'],
#show-value-btn[aria-expanded='true'],
#btn-undo,
#btn-redo[aria-expanded='true'] {
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .theme-menu-item,
  .face-quick-grp,
  .hist-row,
  .theme-menu .dc-chip,
  #btn-view-menu,
  #btn-settings-menu,
  #show-value-btn,
  #btn-undo,
  #btn-redo {
    transition: none;
  }
}

/* ═══ «КАРТА СОСТАВА» — МАТРИЦА КОЛОДЫ (шаг 8 плана «Неоморфизм-2», 2026-08-21) ═══════════
   Просьба заказчика: выбор состава «максимально удобный, по дизайну премиум».

   ЯЧЕЙКА — ИНДИКАТОР, ЗАГОЛОВОК — ОРГАН УПРАВЛЕНИЯ. Состав в модели прямоугольный
   (ranks × suits), отдельная карта в нём не адресуется, и вёрстка обязана это показывать:
   у ячеек нет ни курсора-руки, ни рельефа, ни отклика на наведение. Обещать нажатие там,
   где его нет, — тот же класс, что «показанная ручка не работает».

   Матрица лежит в общей ВДАВЛЕННОЙ канавке (правило плотности: 52 выпуклых квадрата рядом —
   шум, а не рельеф). Выключенный ряд гаснет целиком, и это главное сообщение экрана. */
.dcm {
  display: grid;
  grid-template-columns: 24px repeat(var(--dcm-cols, 13), minmax(0, 1fr));
  gap: 2px;
  align-items: stretch;
  padding: 7px;
  border-radius: var(--nm-radius);
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.dcm-corner {
  min-height: 20px;
}
.dcm-head {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 22px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 7px;
  background: none;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: var(--fs-2xs);
  font-weight: 700;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease),
    opacity var(--nm-ease);
}
.dcm-head.on {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
}
.dcm-head:hover {
  transform: translateY(-1px);
  color: var(--accent);
}
.dcm-head:active {
  transform: translateY(0);
  box-shadow: var(--nm-in);
}
.dcm-suit {
  font-size: var(--fs-base);
  line-height: 1;
}
.dcm-suit.on {
  color: var(--text-primary);
}
.dcm-suit.red.on {
  color: #d8384a;
}
/* ПОСЛЕДНИЙ ВКЛЮЧЁННЫЙ РЯД НЕ СНИМАЕТСЯ — и говорит об этом ДО нажатия: приглушён и не
   поднимается под курсором. Подсказка объясняет причину словами (см. title в js/19). */
.dcm-head.locked {
  opacity: 0.45;
  cursor: not-allowed;
}
.dcm-head.locked:hover {
  transform: none;
  color: var(--text-secondary);
}
/* Ячейка — переключатель ОДНОЙ карты (путь Б, шаг 10): кнопка без собственного оформления. */
.dcm-cell {
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
  /* ЯЧЕЙКА ФОРМЫ КАРТЫ, а не квадрат: экран должен читаться как разложенная колода — в этом
     весь смысл замены галочек на матрицу. Пропорция взята игральной (5:7), высота следует за
     шириной колонки, поэтому сетка сама подстраивается под ширину меню. */
  aspect-ratio: 5 / 7;
  min-height: 0;
  border-radius: 3px;
  background: color-mix(in srgb, var(--text-secondary) 12%, transparent);
  opacity: 0.35;
  transition:
    opacity 180ms var(--nm-ease),
    transform 180ms var(--nm-ease),
    background 180ms var(--nm-ease);
  transform: scale(0.86);
}
/* ЯЧЕЙКА — КАРТА, А НЕ КЛЕТКА ТАБЛИЦЫ. Две редакции забракованы глазами: сплошная заливка
   акцентом читалась как диаграмма, заливка цветом масти — как тепловая карта. Карту делает
   узнаваемой не цвет прямоугольника, а ЗНАК НА СВЕТЛОМ ПОЛЕ: бумажная подложка + точка цвета
   масти. Ради этого чтения матрица и заводилась вместо ряда галочек. */
.dcm-cell {
  color: var(--text-primary);
}
.dcm-cell.red {
  color: #d8384a;
}
.dcm-cell.on {
  opacity: 1;
  transform: scale(1);
  background:
    radial-gradient(circle at 50% 50%, currentColor 0 30%, transparent 31%),
    color-mix(in srgb, var(--text-primary) 16%, transparent);
}

.dcm-cell:hover:not(.locked),
.dcm-cell:focus-visible {
  opacity: 1;
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}
.dcm-cell.locked {
  cursor: not-allowed;
}

/* Джокеры и рубашка — рядом с матрицей, а не под свёрткой. */
.dcm-extra {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 7px;
}
.dcm-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 9px;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.dcm-field-lb {
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.dcm-step {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: 9px;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
}
.dcm-step-btn {
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 7px;
  background: none;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  line-height: 1;
  cursor: pointer;
  transition:
    color var(--nm-ease),
    transform var(--nm-ease);
}
.dcm-step-btn:hover {
  color: var(--accent);
  transform: translateY(-1px);
}
.dcm-step-btn.locked {
  opacity: 0.35;
  cursor: not-allowed;
}
.dcm-step-btn.locked:hover {
  color: var(--text-secondary);
  transform: none;
}
.dcm-step-val {
  min-width: 18px;
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.dcm-toggle {
  padding: 5px 11px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: var(--nm-groove);
  box-shadow: var(--nm-in);
  color: var(--text-secondary);
  font-size: var(--fs-2xs);
  font-weight: 700;
  cursor: pointer;
  transition:
    box-shadow var(--nm-ease),
    color var(--nm-ease);
}
.dcm-toggle.on {
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .dcm-head,
  .dcm-cell,
  .dcm-step-btn,
  .dcm-toggle {
    transition: none;
  }
}

/* ═══ ВЕРХНЯЯ СТРОКА ИНСПЕКТОРА: ФАКТ ОСТАЁТСЯ, ПОЛОСА УХОДИТ ═══════════════════════════════
   Жалоба заказчика 2026-08-21: «в правом меню во всех слоях есть лишняя верхняя строка с
   названием слоя, хотя ниже идёт крупно, что правим и на каком слое».

   ЗАМЕР: на рубашке имя слоя видно на экране ТРИЖДЫ (строка левой панели, эта строка, подпись
   крупной шапки), сама строка занимает 44 px. На лице текст уже гасился признаком title-dup —
   но гасился ЧЕРЕЗ font-size: 0 при сохранённых отступах, и полоса в 37 px оставалась ПУСТОЙ.

   УЗЕЛ НЕ УДАЛЯЕМ — ОН НОСИТЕЛЬ ФАКТА. Его textContent читают подпись крупной шапки (для
   слоёв рубашки), тринадцать проб и программы чтения с экрана. Удаление означало бы завести
   второго писателя имени слоя — ровно тот класс дефектов, от которого проект лечится весь год.
   Поэтому строка скрывается ВИЗУАЛЬНО (приём sr-only): текст на месте, места не занимает.
   display: none здесь запрещён — он убирает узел и из доступности тоже. */
#panel-right .panel-title {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  background: none;
  box-shadow: none;
}
/* Признак title-dup больше не нужен: строка скрыта ВСЕГДА, а не по совпадению текстов.
   Само правило удалено выше — пустое правило только сбивало бы с толку. */
/* Крупная шапка резервирует место под кнопку сворачивания: кнопка живёт в панели (absolute),
   и без резерва она легла бы на правый край имени. */
.insp-headline {
  padding-right: 44px;
}

/* ═══ КНОПКА СВОРАЧИВАНИЯ: ВИДИМАЯ 32, ЗОНА ПОПАДАНИЯ 44 ══════════════════════════════════
   Замер до правки: 22×22 px. Это ниже порога уверенного попадания (44×44 — общий канон
   сенсорных и мышиных целей), а после ухода верхней строки кнопка встала над углом крупного
   имени, где промахнуться ещё легче.

   ВИДИМЫЙ РАЗМЕР И ЗОНА ПОПАДАНИЯ — РАЗНЫЕ ВЕЛИЧИНЫ. Раздувать саму кнопку до 44 значило бы
   отдать ей заметный кусок шапки; зона расширяется прозрачным ::before, который в раскладке
   не участвует. */
.inspector-collapse-btn {
  top: 10px;
  right: 10px;
  width: 32px;
  height: 32px;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-secondary);
  transition:
    box-shadow var(--nm-ease),
    transform var(--nm-ease),
    color var(--nm-ease);
}
.inspector-collapse-btn::before {
  content: '';
  position: absolute;
  top: -6px;
  right: -6px;
  bottom: -6px;
  left: -6px;
}
.inspector-collapse-btn:hover {
  background: var(--nm-surface);
  box-shadow: var(--nm-out);
  color: var(--accent);
  transform: translateY(-1px);
}
.inspector-collapse-btn:active {
  box-shadow: var(--nm-in);
  transform: translateY(0);
}
/* В свёрнутом виде полоса — одна большая цель: щёлкнуть можно куда угодно (js/18c). */
#panel-right.collapsed {
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .inspector-collapse-btn {
    transition: none;
  }
}

/* ═══ РОЛИК ЖЕСТА НА НАСТОЯЩЕЙ КАРТЕ (js/49, просьба заказчика 2026-08-21) ═══════════════════
   «Показать» у совета «Листать карты рукой» раньше лишь переводило в одиночный вид и обводило
   холст кольцом — заказчик описал это словами «и всё».

   ОВЕРЛЕЙ ПРОЗРАЧЕН ДЛЯ МЫШИ. Это не мелочь, а главное решение сцены: человек, взявший карту во
   время ролика, тем же движением ВЫПОЛНЯЕТ настоящий жест — показ перетекает в практику. Заодно
   исполняется правило проекта «анимация, которую нельзя перебить, читается как зависание».

   ДВИЖЕНИЕ ТОЛЬКО transform/opacity. Ни left, ни width, ни анимаций box-shadow: они считаются в
   главном потоке, а он во время сборки колоды занят на сотни миллисекунд (урок busy-overlay).
   Тень карты — псевдоэлементом через opacity. */
.tip-roll {
  position: fixed;
  z-index: 900;
  pointer-events: none;
  opacity: 1;
  transition: opacity 140ms var(--nm-ease, ease);
}
.tip-roll.is-out {
  opacity: 0;
}
.tip-roll-card,
.tip-roll-out {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.tip-roll-out {
  opacity: 0;
}
.tip-roll-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 10px;
  box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.7);
  opacity: 0;
  transition: opacity 220ms var(--nm-ease, ease);
}
.tip-roll[data-такт='press'] .tip-roll-card::after {
  opacity: 1;
}

/* ── ТАКТ 1: НАЖАЛ И КАРТА ПОШЛА ЗА РУКОЙ ───────────────────────────────────────────────────
   Именно с этого заказчик начал описание. Карта чуть приподнята и качается влево-вправо с
   лёгким креном — так видно, что её ТЯНУТ, а не что она ездит сама. */
@keyframes tip-roll-sway {
  0% {
    transform: scale(1);
  }
  12% {
    transform: scale(1.02);
  }
  35% {
    transform: scale(1.02) translateX(-12%) rotate(-4deg);
  }
  65% {
    transform: scale(1.02) translateX(12%) rotate(4deg);
  }
  90% {
    transform: scale(1.02) translateX(0) rotate(0deg);
  }
  100% {
    transform: scale(1);
  }
}
.tip-roll[data-такт='press'] .tip-roll-card {
  animation: tip-roll-sway 1900ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── ТАКТ 2: ВБОК → СОСЕДНЯЯ КАРТА ─────────────────────────────────────────────────────────
   Числа доводки те же, что у настоящего жеста (js/46): уход за край с поворотом и падением
   непрозрачности. Сцена обязана выглядеть как продукт, иначе она обещает не то. */
@keyframes tip-roll-leave {
  0% {
    transform: translateX(0) rotate(0);
    opacity: 1;
  }
  55% {
    transform: translateX(-62%) rotate(-8deg);
    opacity: 0.35;
  }
  100% {
    transform: translateX(-62%) rotate(-8deg);
    opacity: 0;
  }
}
@keyframes tip-roll-enter {
  0% {
    transform: translateX(62%) rotate(8deg);
    opacity: 0;
  }
  45% {
    transform: translateX(0) rotate(0);
    opacity: 1;
  }
  100% {
    transform: translateX(0) rotate(0);
    opacity: 1;
  }
}
.tip-roll[data-такт='side'] .tip-roll-card {
  animation: tip-roll-leave 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
.tip-roll[data-такт='side'].has-out .tip-roll-out {
  animation: tip-roll-enter 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}

/* ── ТАКТ 3: ВВЕРХ → ПЕРЕВОРОТ ─────────────────────────────────────────────────────────────
   Карта уходит вверх и поворачивается; на обороте — живой кадр рубашки. */
@keyframes tip-roll-flip-out {
  0% {
    transform: translateY(0) rotateY(0);
    opacity: 1;
  }
  40% {
    transform: translateY(-14%) rotateY(-72deg);
    opacity: 0.55;
  }
  100% {
    transform: translateY(0) rotateY(-90deg);
    opacity: 0;
  }
}
@keyframes tip-roll-flip-in {
  0% {
    transform: rotateY(90deg);
    opacity: 0;
  }
  45% {
    transform: rotateY(0);
    opacity: 1;
  }
  100% {
    transform: rotateY(0);
    opacity: 1;
  }
}
.tip-roll[data-такт='up'] .tip-roll-card {
  animation: tip-roll-flip-out 2100ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.tip-roll[data-такт='up'].has-out .tip-roll-out {
  animation: tip-roll-flip-in 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}

/* ── ТАКТ 4: ВНИЗ → ВСЯ КОЛОДА НА СТОЛЕ ────────────────────────────────────────────────────
   Карта уменьшается и «ложится», вокруг проявляется сетка из живых кадров. Шесть плиток
   читаются как колода — снимать ради этого 54 кадра было бы ценой сборки листа. */
.tip-roll-grid {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 4%;
  opacity: 0;
  transform: scale(0.9);
  transition:
    opacity 320ms var(--nm-ease, ease),
    transform 320ms var(--nm-ease, ease);
}
/* ПОДЛОЖКА ПОД СЕТКОЙ. Оверлей прозрачен, и без неё плитки «колоды на столе» висели поверх
   живой карты — читалось как наложение, а не как разложенная колода (поймано глазами на
   скриншоте, замер бы это пропустил). Подложка появляется вместе с сеткой и той же прозрачностью. */
.tip-roll-grid::before {
  content: '';
  position: absolute;
  inset: -2%;
  border-radius: 12px;
  background: var(--bg-primary);
  opacity: 0.92;
}
.tip-roll-grid canvas {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 4px;
}
@keyframes tip-roll-lay {
  0% {
    transform: scale(1) translateY(0);
    opacity: 1;
  }
  100% {
    transform: scale(0.28) translateY(24%);
    opacity: 0;
  }
}
.tip-roll[data-такт='down'] .tip-roll-card {
  animation: tip-roll-lay 800ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
.tip-roll[data-такт='down'] .tip-roll-out {
  opacity: 0;
  animation: none;
}
.tip-roll[data-такт='down'] .tip-roll-grid {
  opacity: 1;
  transform: scale(1);
}
.tip-roll[data-такт='end'] .tip-roll-grid {
  opacity: 0;
  transform: scale(0.94);
}
.tip-roll[data-такт='end'] .tip-roll-card {
  animation: none;
  opacity: 1;
}

/* ── КУРСОР С ПИКТОГРАММОЙ МЫШИ ────────────────────────────────────────────────────────────
   Без неё не видно, что кнопку надо ЗАЖАТЬ, и сцена читается как «поводил мышью». Левая
   клавиша горит ровно в фазах «нажал-тяну». */
.tip-roll-cursor {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 36px;
  margin: -18px 0 0 -13px;
  opacity: 0;
  transform: translate(0, 0);
  will-change: transform, opacity;
}
.tip-roll-cursor svg {
  width: 100%;
  height: 100%;
}
.tr-mouse {
  fill: var(--bg-secondary);
  stroke: var(--text-primary);
  stroke-width: 1.6;
}
.tr-lmb {
  fill: var(--text-secondary);
  opacity: 0.35;
  transition:
    opacity 160ms var(--nm-ease, ease),
    fill 160ms var(--nm-ease, ease);
}
.tr-arrow {
  fill: var(--text-primary);
}
.tip-roll[data-такт='press'] .tr-lmb,
.tip-roll[data-такт='side'] .tr-lmb,
.tip-roll[data-такт='up'] .tr-lmb,
.tip-roll[data-такт='down'] .tr-lmb {
  fill: var(--accent);
  opacity: 1;
}
@keyframes tip-roll-cursor-sway {
  0% {
    transform: translate(0, 0);
    opacity: 0;
  }
  12% {
    transform: translate(0, 0);
    opacity: 1;
  }
  35% {
    transform: translate(-12%, 0);
    opacity: 1;
  }
  65% {
    transform: translate(12%, 0);
    opacity: 1;
  }
  100% {
    transform: translate(0, 0);
    opacity: 1;
  }
}
.tip-roll[data-такт='press'] .tip-roll-cursor {
  animation: tip-roll-cursor-sway 1900ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes tip-roll-cursor-left {
  0% {
    transform: translate(0, 0);
    opacity: 1;
  }
  55% {
    transform: translate(-62%, 0);
    opacity: 1;
  }
  100% {
    transform: translate(-62%, 0);
    opacity: 0;
  }
}
@keyframes tip-roll-cursor-up {
  0% {
    transform: translate(0, 0);
    opacity: 1;
  }
  55% {
    transform: translate(0, -40%);
    opacity: 1;
  }
  100% {
    transform: translate(0, -40%);
    opacity: 0;
  }
}
@keyframes tip-roll-cursor-down {
  0% {
    transform: translate(0, 0);
    opacity: 1;
  }
  55% {
    transform: translate(0, 40%);
    opacity: 1;
  }
  100% {
    transform: translate(0, 40%);
    opacity: 0;
  }
}
.tip-roll[data-такт='side'] .tip-roll-cursor {
  animation: tip-roll-cursor-left 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
.tip-roll[data-такт='up'] .tip-roll-cursor {
  animation: tip-roll-cursor-up 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
.tip-roll[data-такт='down'] .tip-roll-cursor {
  animation: tip-roll-cursor-down 2100ms cubic-bezier(0.2, 0.75, 0.3, 1) forwards;
}
.tip-roll[data-такт='end'] .tip-roll-cursor {
  opacity: 0;
  animation: none;
}

/* ── ПОДПИСЬ: РЕЗУЛЬТАТ И ПОЛЬЗА ───────────────────────────────────────────────────────────
   Две строки на такт — прямая просьба заказчика: понятно, чем действие заканчивается И зачем
   оно нужно. Тексты берутся из реестра советов, второго литерала нет. */
.tip-roll-cap {
  position: absolute;
  left: 50%;
  bottom: -6px;
  transform: translate(-50%, 100%);
  max-width: 132%;
  padding: 8px 14px;
  border-radius: var(--nm-radius, 12px);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-out);
  text-align: center;
  opacity: 0;
  transition: opacity 200ms var(--nm-ease, ease);
}
.tip-roll-cap.is-on {
  opacity: 1;
}
.tip-roll-cap b {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text-primary);
  white-space: nowrap;
}
.tip-roll-cap i {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-2xs);
  font-style: normal;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* ЧЕЛОВЕК САМ НАЖАЛ «ПОКАЗАТЬ» — МОЛЧАТЬ НЕЛЬЗЯ, но и крутить нельзя. Показываем исход без
   движения: подпись на месте, карта не едет. */
@media (prefers-reduced-motion: reduce) {
  .tip-roll-card,
  .tip-roll-out,
  .tip-roll-cursor,
  .tip-roll-grid,
  .tip-roll-cap {
    animation: none !important;
    transition: none !important;
  }
  .tip-roll-cursor {
    opacity: 1;
  }
  .tip-roll[data-такт='down'] .tip-roll-card {
    opacity: 0;
  }
}

/* ПИКЕР «ДОБАВИТЬ СЛОЙ» — РЕЛЬЕФ ОСТАЁТСЯ, УЖИМАЮТСЯ ОТСТУПЫ (2026-08-21).
   Первая редакция сняла с его строк рельеф по правилу плотности — и была НЕВЕРНА: здесь
   рельеф несёт СМЫСЛ, а не украшение. Убранный слой показан ВДАВЛЕННОЙ клавишей, включённый —
   выпуклой; проба shelf-picker-toggle спрашивает именно это (жалоба заказчика 2026-08-19
   «меню не поддерживает наш новый стиль»). Сняв рельеф, я стёр состояние — и проба поймала.
   Поэтому лечим ВЫСОТУ, а не материал: двенадцать строк подряд, каждая ужата на несколько
   пикселей. Иначе меню накрывает СВОЮ ЖЕ кнопку, и «нажать ещё раз, чтобы закрыть» становится
   недостижимо мышью (замер: точка кнопки отдаёт содержимое пикера). */
.shelf-picker .theme-menu-item {
  padding: 6px 9px;
}
.shelf-picker .theme-menu-item + .theme-menu-item {
  margin-top: 3px;
}

/* ═══ СПРАВКА ПО ГОРЯЧИМ КЛАВИШАМ (волна 4) ═════════════════════════════════════════════════
   Окно было написано ИНЛАЙНОВЫМИ стилями с зашитыми цветами (#252526, #404044, #a0a0a0). В
   тёмной теме это случайно совпадало с палитрой, а в СВЕТЛОЙ давало белое окно с тёмно-серыми
   плашками клавиш, на которых текст почти не читался. Правило проекта «цвета только токенами»
   существует ровно ради таких случаев: тем три, и окно обязано следовать любой.

   КЛАВИША — единственное место продукта, где выпуклость не метафора, а прямое изображение
   вещи: физическая клавиша выступает над панелью. Поэтому здесь полный рельеф, а не мелкий. */
.help-modal {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.help-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}
.help-modal-box {
  position: relative;
  max-width: 480px;
  width: 90%;
  padding: 28px 34px;
  background: var(--nm-surface);
  border: 1px solid transparent;
  border-radius: var(--nm-radius-lg);
  box-shadow: var(--nm-out), var(--shadow-lg);
}
.help-title {
  font-size: var(--fs-md);
  color: var(--accent);
  margin-bottom: 20px;
}
.help-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 9px 16px;
  font-size: var(--fs-base);
  align-items: center;
}
.help-key {
  justify-self: start;
  padding: 4px 10px;
  border-radius: 7px;
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
  color: var(--text-primary);
  font-size: var(--fs-xs);
  font-family: inherit;
  white-space: nowrap;
}
/* Подпись действия — ПРИГЛУШЁННЫЙ цвет: иерархию задаёт он, форма её только поддерживает
   (клавиша — выпуклая плашка, действие — строка рядом). Контраст проверен по фактическим
   пикселям во всех трёх темах: 5.71 / 7.56 / 9.29 при пороге 4.5:1 — запас есть.
   ЗДЕСЬ ЖЕ ОПЛАЧЕН УРОК: первая редакция пробы брала фон из computed background-color, а под
   рельефом лежит градиент и background-color прозрачен — «rgba(0,0,0,0)» читалось как ЧЁРНЫЙ.
   Проба показала 2.78:1 на читаемом окне, и я успел «починить» то, что не сломано. Фон под
   текстом брать ТОЛЬКО доминантой кадра. */
.help-act {
  color: var(--text-secondary);
}
.help-dismiss {
  margin-top: 24px;
  width: 100%;
  padding: 10px;
  background: var(--accent);
  color: var(--on-accent, #10141c);
  font-weight: 600;
  border: 1px solid transparent;
  border-radius: var(--nm-radius);
  box-shadow: var(--nm-out-sm);
  cursor: pointer;
  transition: box-shadow var(--nm-ease);
}
.help-dismiss:active {
  box-shadow: var(--nm-in-sm);
}

/* ═══ ЗАКАЗ ПЕЧАТНОГО МАКЕТА (js/55-order.js, Б-12) ═══════════════════════════════════════
   Цвета — только токены (светлая тема). Кнопки — родные .ux-btn / .ux-primary. */
.order-modal .ux-modal-box {
  max-width: 560px;
  max-height: 86vh;
}
.order-body {
  padding: 14px 18px 4px;
  overflow: auto;
  font-size: var(--fs-sm);
  color: var(--text-primary);
}
.order-preview {
  display: flex;
  justify-content: center;
  margin: 0 0 12px;
}
.order-preview-canvas {
  max-width: 100%;
  max-height: 34vh;
  width: auto;
  height: auto;
  border-radius: var(--nm-radius);
  box-shadow: var(--nm-out-sm);
}
.order-facts {
  line-height: 1.55;
  margin: 0 0 12px;
}
.order-price {
  font-size: 1.35em;
  font-weight: 700;
}
.order-muted {
  color: var(--text-secondary);
}
.order-form {
  display: grid;
  gap: 10px;
}
.order-field {
  display: grid;
  gap: 4px;
}
.order-field span {
  font-size: var(--fs-xs, 12px);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.order-field i {
  font-style: normal;
  color: var(--accent);
  text-transform: none;
  letter-spacing: 0;
  margin-left: 6px;
}
.order-field input {
  padding: 9px 11px;
  border-radius: var(--nm-radius);
  border: 1px solid transparent;
  background: var(--bg-primary);
  box-shadow: var(--nm-in-sm);
  color: var(--text-primary);
  font: inherit;
}
.order-field input:focus {
  outline: none;
  box-shadow:
    var(--nm-in-sm),
    0 0 0 2px var(--accent-dim);
}
.order-agree {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  color: var(--text-secondary);
}
.order-agree input {
  margin-top: 3px;
}
.order-consent {
  margin: -4px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted, var(--text-secondary));
}
.order-agree a,
.order-consent a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
/* Строка продавца в углу холста: реквизиты и документы видны до договора; приглушена,
   ссылки ловят курсор, остальное — нет (не мешает жестам по холсту). */
#legal-line {
  position: absolute;
  left: 14px;
  bottom: 14px;
  z-index: 40;
  display: flex;
  gap: 12px;
  align-items: center;
  font-size: 11px;
  line-height: 1;
  color: var(--text-muted, var(--text-secondary));
  opacity: 0.75;
  pointer-events: none;
  /* справа живёт плашка масштаба (в одиночном виде ~260 px) — строка ей уступает: когда край
     последней ссылки заходит за её левый край, js/55 вешает .is-tight и остаются три ссылки на
     документы (имя и ИНН — в подсказке и на самих страницах; обрезать реквизит многоточием
     нельзя, max-width тут не годится — текст выходит за короб, а короб врёт про край) */
  white-space: nowrap;
}
#legal-line a,
#legal-line span {
  pointer-events: auto;
}
#legal-line.is-tight span,
#legal-line.is-tight a[href^='mailto'],
#legal-line.is-tight a[href='/instrukciya/'] {
  display: none;
}
#legal-line a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
#legal-line a:hover {
  color: var(--text-primary);
}
@media (max-width: 900px) {
  #legal-line span {
    display: none;
  }
}
/* Вход к описанию из панели «Советы» — не подпись, а ссылка под палец */
.tips-about {
  display: block;
  margin: 6px 4px 2px;
  padding: 12px 10px;
  min-height: 44px;
  border-radius: var(--nm-radius, 10px);
  background: var(--bg-active, rgba(255, 255, 255, 0.06));
  color: var(--text-primary);
  text-decoration: none;
  font-size: var(--fs-sm, 13px);
  line-height: 1.3;
}
.tips-about:hover {
  background: var(--bg-hover, rgba(255, 255, 255, 0.1));
}

/* Панель советов на узком экране уезжала за левый край (замер 23.09: x = −195 при ширине
   экрана 390) — она встаёт под кнопку тулбара, а места слева нет. Держим её в границах. */
@media (max-width: 700px), (pointer: coarse) {
  .tips-panel {
    left: 8px !important;
    right: 8px !important;
    width: auto !important;
    max-width: none !important;
  }
}
/* ПАЛЬЦЕМ В 11 ТОЧЕК НЕ ПОПАСТЬ (23.09.2026). На телефоне эта строка — единственный путь с
   главной к описанию сервиса, а была полупрозрачной подписью высотой 11 px, из которой
   «Инструкция» пряталась совсем. На узком сенсорном экране она перестаёт быть подписью:
   ссылки становятся крупнее нормы касания, читаемыми и переносятся на вторую строку, если не
   помещаются. Правило «уступить плашке масштаба» остаётся для мыши — там 11 px уместны. */
@media (max-width: 700px), (pointer: coarse) {
  #legal-line {
    left: 10px;
    right: 10px;
    /* НАД плашкой масштаба, а не под ней: на узком экране плашка занимает всю ширину низа и
       накрывала строку целиком — из пяти ссылок оставалась видна одна буква (замер 23.09). */
    bottom: 74px;
    flex-wrap: wrap;
    gap: 6px 14px;
    font-size: 13px;
    opacity: 1;
  }
  #legal-line a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 2px;
  }
  /* на телефоне «Инструкция» нужна не меньше прочих — прятать её нечем оправдать */
  #legal-line.is-tight a[href='/instrukciya/'] {
    display: inline-flex;
  }
}
.order-error {
  padding: 9px 12px;
  border-radius: var(--nm-radius);
  background: rgba(220, 80, 60, 0.14);
  color: var(--text-primary);
}
.order-modal .ux-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 6px 0 14px;
}
.order-modal .ux-primary {
  margin: 0;
  padding: 9px 16px;
}
.order-status {
  padding: 14px 16px;
  border-radius: var(--nm-radius);
  box-shadow: var(--nm-in-sm);
  background: var(--bg-primary);
  margin: 0 0 12px;
}
.order-status-text {
  font-size: 1.05em;
  font-weight: 600;
}
.order-status[data-state='собирается'] .order-status-text::before,
.order-status[data-state='создан'] .order-status-text::before,
.order-status[data-state='счёт'] .order-status-text::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
  background: var(--accent);
  animation: orderPulse 1.4s ease-in-out infinite;
}
/* Ожидание сборки (28.09.2026): кольцо — тот же владелец, что у заставки (BusyRing, js/31);
   пульсирующая точка при кольце прячется — два указателя одного процесса не нужны. */
.order-status[data-wait] .order-status-text::before {
  display: none;
}
.order-wait {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 12px;
}
.order-wait-ring {
  flex: 0 0 auto;
}
.order-wait-ring .busy-visual {
  margin: 0;
}
.order-wait-mail {
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
}
.order-wait-text {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 480px) {
  .order-wait {
    flex-direction: column;
    text-align: center;
  }
}
/* Карусель ожидания (28.09.2026): одна карточка за раз, проявление 0.7 с по кривой заказчика,
   без scale/пружин; «меньше движения» — без перехода (автосмену гасит js/55). */
.order-cards {
  position: relative;
  display: grid;
  margin: 0 0 12px;
  padding: 14px 16px 12px;
  border-radius: var(--nm-radius);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
}
.order-card {
  grid-area: 1 / 1;
  display: flex;
  gap: 14px;
  align-items: center;
  opacity: 0;
  transform: translateY(8px);
  visibility: hidden;
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    visibility 0s linear 0.7s;
}
.order-card.on {
  opacity: 1;
  transform: translateY(0);
  visibility: visible;
  transition:
    opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    visibility 0s;
}
.order-card-img {
  flex: 0 0 auto;
  width: 112px;
  height: 112px;
  object-fit: cover;
  border-radius: var(--radius-md);
}
.order-card-body {
  min-width: 0;
}
.order-card-title {
  font-weight: 600;
  font-size: 15px;
  color: var(--text-primary);
  margin-bottom: 4px;
}
.order-card-text {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-secondary);
}
.order-card-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}
.order-card-acts .ux-btn {
  margin: 0;
  padding: 7px 12px;
  font-size: 13px;
  text-decoration: none;
}
.order-cards-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-top: 10px;
}
.order-cards-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--text-muted);
  opacity: 0.35;
  cursor: pointer;
}
.order-cards-dot[aria-current='true'] {
  opacity: 1;
  background: var(--accent);
}
@media (max-width: 480px) {
  .order-card {
    flex-direction: column;
    text-align: center;
  }
  .order-card-acts {
    justify-content: center;
  }
}
@media (prefers-reduced-motion: reduce) {
  .order-card,
  .order-card.on {
    transition: none;
    transform: none;
  }
}
/* подсказка у оплаты: страница Битрикса сбоит (28.09.2026) */
.order-pay-help {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-secondary);
}
.order-status[data-state='оплачен'] .order-status-text,
.order-status[data-state='выдан'] .order-status-text {
  color: var(--success, #3cb371);
}
@keyframes orderPulse {
  0%,
  100% {
    opacity: 0.35;
  }
  50% {
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .order-status-text::before {
    animation: none !important;
  }
}
.order-page-actions {
  display: grid;
  gap: 8px;
  margin: 0 0 14px;
}
.order-page-actions .ux-btn {
  text-align: center;
  text-decoration: none;
  display: block;
}
.order-foot {
  border-top: 1px solid var(--border);
  padding-top: 10px;
}
.order-link-row {
  display: flex;
  gap: 8px;
  margin-top: 6px;
}
.order-link {
  flex: 1;
  min-width: 0;
  padding: 7px 10px;
  border-radius: var(--nm-radius);
  border: 1px solid transparent;
  background: var(--bg-primary);
  box-shadow: var(--nm-in-sm);
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--fs-xs, 12px);
}

/* Текст лица: подпись группы, превью шрифта, предупреждение «не влезает» (колода из текстов, шаг 3) */
.face-text-sub {
  margin: 10px 0 4px;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
}
.face-font-preview {
  font-size: 18px;
  line-height: 1;
}
.face-text-warn {
  border-left: 2px solid var(--warning);
  color: var(--text-primary);
}

/* ═══ ОКНО «КОЛОДА ИЗ ТЕКСТОВ» (шаг 6, 23.09.2026) ═════════════════════════════════════════════
   Один экран: слева — список и оформление, справа — три настоящие карты, нарисованные продуктом
   (примерка). Язык — как у окна приветствия: надзаголовок цветом акцента, заголовок антиквой,
   поверхности неоморфные, цвета только токенами (три темы). Карты в предпросмотре — бумага.
   Движение: появление окна — opacity + подъём 10 px за 0,5 с, cubic-bezier(.16,1,.3,1); смена
   кадров предпросмотра — проявление 0,35 с; под «меньше движения» всё неподвижно. */
.td-modal {
  align-items: center;
  padding: 16px 0;
}
.td-modal .ux-modal-box {
  max-width: 1040px;
  width: calc(100% - 32px);
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  padding: 26px 30px 22px;
  animation: tdUp 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes tdUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}
.td-head {
  position: relative;
  padding-right: 44px;
}
.td-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}
.td-title {
  margin: 6px 0 8px;
  font-family: 'Playfair Display', Georgia, 'Times New Roman', serif;
  font-size: 27px;
  font-weight: 700;
  line-height: 1.15;
  color: var(--text-primary);
  text-wrap: balance;
}
.td-lead {
  margin: 0;
  max-width: 68ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.td-x {
  position: absolute;
  top: -6px;
  right: -8px;
  width: 36px;
  height: 36px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition:
    color 0.3s ease,
    background 0.3s ease;
}
.td-x svg {
  width: 18px;
  height: 18px;
}
.td-x:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}
.td-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 28px;
  margin-top: 20px;
}
.td-sec + .td-sec {
  margin-top: 20px;
}
.td-h {
  margin: 0 0 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.td-sub {
  margin: 14px 0 8px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-secondary);
}
.td-hint {
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-muted);
}
.td-drop {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  gap: 14px;
  align-items: center;
  padding: 16px 16px 16px 18px;
  border-radius: var(--nm-radius);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in);
  outline: 1.5px dashed var(--border);
  outline-offset: -7px;
  color: var(--text-muted);
  transition:
    outline-color 0.3s ease,
    color 0.3s ease;
}
.td-drop svg {
  width: 40px;
  height: 40px;
}
.td-drop.over {
  outline-color: var(--accent);
  color: var(--accent);
}
.td-drop-text {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.td-drop-text strong {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
}
.td-drop-text span {
  font-size: 12.5px;
  color: var(--text-muted);
}
.td-pick,
.td-btn {
  height: 38px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition:
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.3s ease,
    background 0.3s ease,
    opacity 0.3s ease;
}
.td-pick {
  background: var(--nm-surface);
  color: var(--text-primary);
  box-shadow: var(--nm-out-sm);
}
.td-pick:hover,
.td-btn:not(:disabled):hover {
  transform: translateY(-2px);
}
.td-paste-lab {
  display: block;
  margin-top: 12px;
  font-size: 12.5px;
  color: var(--text-muted);
}
.td-paste {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 10px 12px;
  box-sizing: border-box;
  resize: vertical;
  min-height: 64px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in-sm);
  color: var(--text-primary);
  font: inherit;
  font-size: 13px;
  line-height: 1.45;
}
.td-paste:focus {
  outline: none;
  border-color: var(--accent);
}
.td-sum {
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  background: var(--bg-tertiary);
  border-left: 2px solid var(--accent);
  font-size: 13px;
  color: var(--text-secondary);
  animation: tdFade 0.35s ease both;
}
.td-sum-bad {
  border-left-color: var(--error);
  color: var(--text-primary);
}
.td-sum-n {
  font-size: 13.5px;
  color: var(--text-primary);
}
.td-sum-n b {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.td-sum-d {
  margin-top: 4px;
  line-height: 1.45;
}
.td-sum-warn,
.td-warn {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--warning);
  background: var(--bg-secondary);
  color: var(--text-primary);
  font-size: 12.5px;
  line-height: 1.45;
}
.td-cols {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}
.td-cols-l {
  font-size: 12px;
  color: var(--text-muted);
}
.td-colbtn,
.td-seg-btn,
.td-font {
  border: 0;
  font: inherit;
  cursor: pointer;
  color: var(--text-secondary);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
  transition:
    color 0.3s ease,
    box-shadow 0.3s ease,
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.td-colbtn {
  max-width: 180px;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.td-colbtn.on,
.td-font.on {
  color: var(--accent);
  box-shadow: var(--nm-in-sm);
}
.td-seg {
  display: flex;
  gap: 6px;
  padding: 4px;
  border-radius: var(--radius-pill);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in-sm);
}
.td-seg-btn {
  flex: 1 1 0;
  min-height: 34px;
  padding: 0 12px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 600;
  box-shadow: none;
  background: transparent;
}
.td-seg-btn.on {
  color: var(--accent);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-xs);
}
.td-seg-btn svg {
  width: 18px;
  height: 18px;
  vertical-align: middle;
}
.td-check {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-secondary);
  cursor: pointer;
}
.td-check input {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
}
.td-fonts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
  max-height: 176px;
  overflow-y: auto;
  padding: 4px;
  margin: -4px;
}
.td-font {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 6px 7px;
  border-radius: var(--radius-md);
}
.td-font:hover {
  transform: translateY(-2px);
}
.td-font-aa {
  font-size: 22px;
  line-height: 1.1;
  color: var(--text-primary);
}
.td-font.on .td-font-aa {
  color: var(--accent);
}
.td-font-name {
  max-width: 100%;
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.td-row2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
.td-range {
  width: 100%;
  accent-color: var(--accent);
}
.td-preview {
  position: sticky;
  top: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.td-notes {
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 8px;
}
.td-notes li {
  position: relative;
  padding-left: 16px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-muted);
}
.td-notes li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 0.6em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  opacity: 0.7;
}
.td-preview > .td-sub:first-child {
  margin-top: 0;
}
.td-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  align-items: start;
  padding: 18px 16px 12px;
  border-radius: var(--nm-radius-lg);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in);
}
.td-card {
  margin: 0;
  min-width: 0;
}
.td-card-art {
  aspect-ratio: 63 / 88;
  border-radius: 7px;
  overflow: hidden;
  background: #fbfaf6;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.35) inset,
    0 10px 20px -10px rgba(0, 0, 0, 0.45);
}
.td-cards-empty .td-card-art {
  background: repeating-linear-gradient(
    135deg,
    var(--bg-tertiary) 0 8px,
    var(--bg-secondary) 8px 16px
  );
  box-shadow: none;
  opacity: 0.6;
}
.td-card-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: tdFade 0.35s ease both;
}
@keyframes tdFade {
  from {
    opacity: 0;
  }
}
.td-card-cap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.td-card-cap b {
  min-height: 1.2em;
  font-size: 13px;
  color: var(--text-primary);
}
.td-empty {
  margin: 12px 2px 0;
  font-size: 13px;
  color: var(--text-muted);
}
.td-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.td-foot-note {
  flex: 1 1 auto;
  font-size: 12.5px;
  color: var(--text-muted);
}
.td-btn-ghost {
  background: transparent;
  color: var(--text-secondary);
}
.td-btn-ghost:hover {
  background: var(--bg-hover);
}
.td-btn-main {
  background: var(--accent-grad, var(--accent));
  color: var(--on-accent);
  box-shadow: var(--shadow-md);
}
.td-btn-main:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}
@media (max-width: 820px) {
  .td-body {
    grid-template-columns: 1fr;
  }
  .td-preview {
    position: static;
    order: -1;
  }
  .td-notes {
    display: none;
  }
  .td-modal .ux-modal-box {
    padding: 22px 18px 18px;
  }
  .td-title {
    font-size: 22px;
  }
  .td-drop {
    grid-template-columns: 32px 1fr;
  }
  .td-drop svg {
    width: 32px;
    height: 32px;
  }
  .td-pick {
    grid-column: 1 / -1;
  }
  .td-row2 {
    grid-template-columns: 1fr;
  }
  .td-foot {
    flex-wrap: wrap;
  }
  .td-foot-note {
    flex-basis: 100%;
  }
  .td-btn-main {
    flex: 1 1 100%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .td-modal .ux-modal-box,
  .td-sum,
  .td-card-img {
    animation: none;
  }
  .td-pick,
  .td-btn,
  .td-font,
  .td-seg-btn,
  .td-colbtn {
    transition: none;
  }
  .td-pick:hover,
  .td-btn:not(:disabled):hover,
  .td-font:hover {
    transform: none;
  }
}

/* Колода из текстов 2.0 (24.09.2026): сетка 3×3 «Положение на карте» и образцы цвета шрифта в окне */
.td-seg.td-grid9 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  border-radius: 12px;
  max-width: 168px;
}
.td-grid9 .td-seg-btn {
  min-height: 30px;
  padding: 0;
  border-radius: 8px;
  font-size: 15px;
}
.td-sub-gap {
  margin-top: 14px;
}
/* Колода из текстов 2.0, шаг 7: источник списка — «Свой список» или «По порядку» */
.td-sec > .td-seg {
  margin-bottom: 12px;
}
.td-src-seq {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* свой display перебивает атрибут hidden — скрытая панель источника висела под «Своим списком» */
.td-src-own[hidden],
.td-src-seq[hidden],
.td-src-sets[hidden] {
  display: none;
}
/* Шаг 8: готовые наборы — карточки с названием, числом карт и примером */
.td-sets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 10px;
  font-size: 13px;
  color: var(--text-muted);
}
.td-set {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 12px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--nm-surface);
  box-shadow: var(--nm-out-sm);
  color: var(--text-primary);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition:
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.3s;
}
.td-set:hover {
  transform: translateY(-2px);
}
.td-set.on {
  border-color: var(--accent);
}
.td-set-name {
  font-weight: 600;
  font-size: 14px;
}
.td-set-n {
  font-size: 12px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.td-set-ex {
  font-size: 12.5px;
  color: var(--text-secondary);
  font-style: italic;
}
@media (prefers-reduced-motion: reduce) {
  .td-set {
    transition: none;
  }
}
.td-seq-params {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.td-nums {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.td-num {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text-muted);
}
.td-num input {
  width: 72px;
  min-height: 34px;
  padding: 0 10px;
  box-sizing: border-box;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--nm-surface-in);
  box-shadow: var(--nm-in-sm);
  color: var(--text-primary);
  font: inherit;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.td-num input:focus {
  outline: none;
  border-color: var(--accent);
}
.td-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-secondary);
  cursor: pointer;
}
.td-swatches {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.td-swatch {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  box-shadow: var(--nm-out-xs);
  cursor: pointer;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.td-swatch:hover {
  transform: translateY(-2px);
}
.td-swatch.on {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.td-swatch-any {
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.td-warn {
  color: var(--warning, #d9902b);
  font-weight: 600;
}
