/* ═══════════════════════════════════════════════════
   ECHONAUTICS — стиль интерфейса «ГАЛЕРЕЯ»
   Принят заказчиком 29.08.2026. Спецификация переноса — docs/design-system.md,
   макеты — docs/design/*.html (обычные страницы, открываются в браузере),
   общая основа стиля — docs/design/_base.css.
═══════════════════════════════════════════════════ */
:root {
  /* ─── ПОВЕРХНОСТИ ────────────────────────────────────────────────
     Фон страницы темнее панели, а ЗАКРЫТЫЙ СЕКТОР СВЕТЛЕЕ панели. Раньше у
     панели и у сектора был общий #0d1b2a: поле сливалось со своей оправой, и
     на это указывала лаборатория эффектов ещё до выбора стиля. */
  --bg:       #04070d;   /* фон страницы */
  --panel:    #0a141f;   /* сплошная панель */
  --panel-2:  rgba(126,168,190,0.030);  /* полупрозрачная панель поверх фона */
  --surface:  #101f30;   /* закрытый сектор — светлее панели */
  --surface-line: #1b3350;  /* его рамка */

  /* ─── ЛИНИИ ──────────────────────────────────────────────────────
     Волосяные вместо сплошной синей #1a3a5c: рамка перестаёт спорить с
     содержимым панели. Две ступени — обычная и заметная. */
  --border:   rgba(126,168,190,0.16);
  --border-2: rgba(126,168,190,0.24);

  /* ─── ТЕКСТ, ТРИ СТУПЕНИ ─────────────────────────────────────────
     Ни одна не ниже 4.5:1 к --bg. До этого приглушённый текст шёл 3.4–4.1:1:
     иерархию держим кеглем и насыщенностью, а не выцветанием. */
  --text:     #dff0f8;   /* основной */
  --dim:      #9FBACA;   /* второй ступени */
  --dim-2:    #8FA9B8;   /* третьей ступени, метки-капсы */
  --head:     #eaf6fb;   /* заголовки */

  /* ─── АКЦЕНТЫ ────────────────────────────────────────────────────
     Те же, что были в игре: бирюза и золото стиль не менял. Цвета цифр 1–8 и
     цвета эфемеров НЕ ТРОГАЮТСЯ вовсе — это игровой язык (цифра связана с
     высотой звука SFX.number, цвет — с ключом карточки Атласа). */
  --teal:     #4ecdc4;
  --teal-2:   #6fded5;
  --green:    #2ecc71;
  --yellow:   #f39c12;
  --red:      #e74c3c;
  --gold:     #f0d060;
  --purple:   #9b59b6;

  /* ─── ШРИФТЫ ─────────────────────────────────────────────────────
     Oswald на метки-капсы и заголовки, JetBrains Mono на числа и текст. Оба с
     кириллицей, оба лежат в web/fonts/ — Steam-сборка и мобильные работают без
     сети, и подключение с Google Fonts (как в макетах) там не годится.
     Уходит системный 'Courier New': на Маке и на Windows он разный, это
     показывала лаборатория. Он остаётся последним запасным. */
  /* Списка запасных здесь НЕ сокращать до самой переменной: замена
     «'Courier New', monospace» на var(--font-mono) прошла по всему файлу и
     задела это же объявление — вышло --font-mono: 'JetBrains Mono',
     var(--font-mono). Переменная, ссылающаяся на себя, недействительна, и
     body оставался на шрифте браузера по умолчанию, то есть на засечках.
     Отказ был полностью тихий: ни ошибки в консоли, ни сорванной раскладки. */
  --font-mono: 'JetBrains Mono', 'Courier New', monospace;
  --font-head: 'Oswald', 'Tahoma', sans-serif;

  /* ─── РАДИУС ─────────────────────────────────────────────────────
     2–3 px, не 6: в макетах «Галереи» углы почти прямые. */
  --r:   3px;
  --r-s: 2px;

  /* ─── ДЛИТЕЛЬНОСТИ ───────────────────────────────────────────────
     Три ступени вместо двух десятков. Та же болезнь, что была у кеглей:
     девять десятых интерфейса набрано пятью из тридцати. */
  --t-tap:  120ms;  /* отклик интерфейса: наведение, нажатие */
  --t-in:   300ms;  /* появление и раскрытие: подсказка, сообщение, вскрытие */
  --t-slow: 900ms;  /* фоновое дыхание: пульс Глаза, сонарные кольца */

  /* Android demo: tunable sizes via vars. JS may override --cell-size at runtime. */
  --cell-size: 46px;
  --btn-min-h: 32px;
  /* Edge-to-edge (Android immersive): отступы под системные панели. На десктопе/в
     обычном браузере env() = 0 → не влияет. На Android status bar виден (контент под
     ним → компенсируем сверху), nav bar скрыта (снизу остаётся лишь жестовый inset). */
  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left:   env(safe-area-inset-left, 0px);
  --safe-right:  env(safe-area-inset-right, 0px);
}
* { box-sizing: border-box; margin: 0; padding: 0; caret-color: transparent; }
.hidden { display: none !important; }
/* Tach-устройства: убираем 300ms задержку перед click для всех интерактивных элементов. */
button, .cell, .card-slot, .org-tab, .shop-org-tab, .sp-tab, .archive-tab,
.ach-item, .inv-slot, .btn-shop, #btn-archive, #btn-help,
#btn-sidepanel, #sp-close, .btn-equip-buy, .btn-overlay-action {
  touch-action: manipulation;
}
/* Grid целиком — без жестов, чтобы pinch-zoom не мешал. */
#grid, #grid-wrap { touch-action: manipulation; }
/* Горизонтальный свайп — наш жест (СИГНАТУРЫ), а не «назад/вперёд» браузера. */
html, body { overscroll-behavior-x: none; }
/* ═══ ФОН ПОГРУЖЕНИЯ (30.08.2026) ══════════════════════════════════
   Сплошная заливка ушла с body на html, а место за интерфейсом занял холст
   #bg-layer: по нему медленно проплывают широкие пятна света своего цвета у
   каждого слоя (js/background.js, вариант «Дыхание»).

   ПОЧЕМУ ЗАЛИВКА ПЕРЕЕХАЛА НА html. Холст под непрозрачным body не виден
   вовсе, а прозрачный body без заливки на html оставил бы белую страницу
   там, куда холст не достаёт (полосы прокрутки, резина на мобильных). Цвет
   тот же --bg, поэтому без движка игра выглядит ровно как до правки. */
html { background: var(--bg); }
#bg-layer {
  position: fixed; inset: 0; z-index: -1;
  width: 100%; height: 100%;
  display: block; pointer-events: none;
}
body {
  background: transparent;
  color: var(--text);
  font-family: var(--font-mono);
  min-height: 100vh;
  display: flex;
  justify-content: center;
  /* Колонка кончается ТАМ, ГДЕ КОНЧАЕТСЯ ИГРА, а не тянется до низа окна
     (заказчик, 30.08.2026): под журналом и слотами оборудования дальше идёт
     фон погружения. По умолчанию флекс растягивает ребёнка на всю высоту, и
     чёрная плита уходила до самого низа высокого экрана. */
  align-items: flex-start;
  padding: 14px 16px;
  user-select: none;
}
input, textarea { user-select: text; caret-color: auto; }

/* ═══ СТИЛЬ «ГАЛЕРЕЯ»: ШРИФТ ПО НАЗНАЧЕНИЮ ═══════════════════════
   Правило простое: Oswald там, где НАДПИСЬ (заголовок панели, вкладка,
   метка-капс, кнопка), JetBrains Mono там, где ЧИСЛО или текст. Поэтому
   моноширинный стоит на body и достаётся всему по наследству, а этот слой
   лежит СРАЗУ ПОСЛЕ сброса — любое более частное правило ниже его перебьёт.
   Кегли и межбуквенное здесь не трогаются: их правят экранами, а разом это
   сдвинуло бы всю раскладку. */
.panel-title,
.help-section-title, .archive-item-title, .decipher-header,
.equip-type-badge, #ebm-type-badge, #hint-label, #mem-label,
.shop-confirm-label,
.org-tab, .shop-org-tab, .sp-tab, .archive-tab,
button, .btn-shop, .btn-equip-buy, .btn-equip-access,
.btn-overlay-action {
  font-family: var(--font-head);
}
/* Числа внутри кнопок и вкладок остаются моноширинными: цена, срок, остаток
   выравниваются в столбец только так. */
button .gal-num, .btn-shop .gal-num, .gal-num { font-family: var(--font-mono); }

/* ═══ УГОЛКИ-ЗАСЕЧКИ — подпись стиля ══════════════════════════════
   Четыре уголка по углам панели. Рисуются ОДНИМ псевдоэлементом из восьми
   градиентных штрихов, а не четырьмя узлами разметки, как в макетах: узлы
   пришлось бы дописывать в каждую панель игры руками, и в отрисованных из JS
   списках их не было бы вовсе. Градиенты тянутся за любым размером панели.
   Родителю нужен position: relative — у .panel он уже есть. */
.gal-ticks { position: relative; }
.gal-ticks::before {
  content: ""; position: absolute; inset: -4px; pointer-events: none; z-index: 1;
  --tick: rgba(78,205,196,0.45);
  background:
    linear-gradient(var(--tick), var(--tick)) 0    0    / 11px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 0    / 11px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    100% / 11px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 100% / 11px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    0    / 1px 11px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 0    / 1px 11px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    100% / 1px 11px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 100% / 1px 11px no-repeat;
}
.gal-ticks-gold::before { --tick: rgba(240,208,96,0.45); }

/* ─── КНОПКА ЗАКРЫТИЯ ОКНА ────────────────────────────────────────
   В макете это не голый знак у заголовка, а кнопка 30×30 в волосяной рамке в
   правом верхнем углу панели. Один класс на все окна: раньше у каждого был
   свой ×, и они разъезжались по размеру и цвету. */
.gal-x {
  width: 30px; height: 30px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: none;
  border: 1px solid var(--border-2); border-radius: 2px;
  color: var(--dim); cursor: pointer; padding: 0;
  transition: border-color var(--t-tap), color var(--t-tap);
}
.gal-x .gi { height: 14px; }
.gal-x:hover { border-color: rgba(78,205,196,.55); color: var(--teal-2); }


/* ═══ ЗНАКИ ИГРЫ ══════════════════════════════════════════════════
   Значок — контурный SVG в <i class="gi">, набор лежит в game.js (ICONS).
   Ростом СО СТРОКУ и цветом ОКРУЖАЮЩЕГО ТЕКСТА: высота в em, ширина по
   пропорции значка, заливка через currentColor. Поэтому один и тот же знак
   годится и в шапке 20 px, и в записи журнала 13 px, и красится тоном строки —
   отдельного правила на каждое место не нужно.
   Ширину задаём auto, а не 1em: у кардиограммы Связности пропорции 26×20, и в
   квадрате она сжалась бы до нечитаемой загогулины. */
.gi { display: inline-block; height: 1em; width: auto; line-height: 0; vertical-align: -0.14em; flex: 0 0 auto; }
.gi > svg { height: 100%; width: auto; display: block; }
.gi-gold   { color: var(--gold); }
.gi-teal   { color: var(--teal); }
.gi-purple { color: var(--purple); }
.gi-red    { color: var(--red); }
/* Значок ВНУТРИ текста (журнал, подсказки, карточка): чуть меньше строки и с
   воздухом по бокам — вплотную к букве он читается как опечатка. */
.txt-ic { height: 1.05em; margin: 0 .12em; vertical-align: -0.16em; }
.txt-ic-gold   { color: var(--gold); }
.txt-ic-teal   { color: var(--teal); }
.txt-ic-green  { color: var(--green); }
.txt-ic-yellow { color: var(--yellow); }
.txt-ic-red    { color: var(--red); }
.txt-ic-purple { color: var(--purple); }
.txt-ic-blue   { color: #3b82f6; }
.txt-ic-warp   { color: var(--purple); }
.txt-ic-data   { color: #7fd8ff; }
.txt-ic-energy { color: var(--gold); }
.txt-ic-hp     { color: var(--teal); }


/* Колонка игры ЗАЛИТА СПЛОШЬ, и фон погружения виден только по её краям
   (заказчик, 30.08.2026). Панели внутри остались полупрозрачными, как были:
   под ними снова сплошной --bg, поэтому все их оттенки и вложенность
   совпадают с тем, что было до появления фона, до значения. Гасить каждую
   панель по отдельности значило бы перебрать полсотни правил и всё равно
   промахнуться мимо какой-нибудь одной. */
#app {
  width: 1060px; max-width: 100%;
  background: var(--bg);
  /* Колонка КОНЧАЕТСЯ, а не обрывается: под последним блоком остаётся полоска
     фона, а углы скруглены той же величиной, что у панелей внутри. Ровный срез
     по нижней кромке слотов читался как обрезанная картинка, а не как конец
     раздела (заказчик, 30.08.2026). */
  padding-bottom: 14px;
  /* 8 px, а не общие 3: это кромка ВСЕЙ колонки, и на такой длине трёхпиксельный
     радиус не читается вовсе — срез снова выглядит обрубленным. */
  border-radius: 8px;
}

/* ─── ПОЛОСЫ ПРОКРУТКИ ───────────────────────────────────────────
   Chrome и Windows по умолчанию рисуют светло-серую полосу: на почти чёрном
   фоне это яркая лента вдоль журнала, СИГНАТУР и всей страницы, которая спорит
   с содержимым и первой ловит взгляд. Красим в цвета панелей — чуть светлее
   фона, так что прокрутка читается, но перестаёт быть контрастной полосой.
   Правило глобальное (без селектора), поэтому накрывает и журнал, и Атлас,
   и магазин — везде, где что-то прокручивается.
   scrollbar-color/scrollbar-width — для Firefox, ::-webkit-* — для Chrome и
   Safari; обе записи нужны, одна другую не заменяет. */
html { scrollbar-color: #16273a transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
/* Кнопки-стрелки на концах: к кастомной полосе Chrome дорисовывает их сам, и
   они остаются светлыми — теми самыми контрастными точками, ради которых всё
   и затевалось. Убираем совсем. */
::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
::-webkit-scrollbar-thumb {
  background: #16273a;
  border: 2px solid transparent;
  background-clip: content-box;   /* прозрачная рамка вокруг ползунка — воздух, а не толстая полоса */
  border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover { background: #23405f; background-clip: content-box; }
::-webkit-scrollbar-corner { background: transparent; }

/* ─── RESOURCES BAR ─────────────────────────────── */
#res-bar {
  display: flex;
  align-items: center;
  /* 5 px — тот же зазор, что между колонками у #game-area: ряды шапки стоят
     ровно над ними (см. syncHeaderColumns). */
  gap: 5px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 8px 16px;
  margin-bottom: 10px;
  font-size: 20px;
  /* #219: левый край плашки и левый край рамки контура должны совпадать. Раньше
     это делалось сдвигом плашки ВЛЕВО на RIG_FRAME_PAD — рамка выступала за
     #game-area. При ширине окна около 1060 px (ровно ширина #app) те пять
     пикселей оказывались ЗА краем экрана, и у рамки пропадала левая стенка:
     батарея выглядела съехавшей вправо, с обрезанными скруглениями.
     Теперь навстречу двигается колонка контура (margin-left у #battery-col),
     а плашка стоит на месте — края сходятся там же, но внутри окна. */
  box-sizing: border-box;
}
/* ДВА РЯДА — ДВА ФЛЕКС-БЛОКА, А НЕ `display: contents`.
   Задумка была такая: на десктопе обёртки «исчезают», и их дети становятся
   прямыми flex-детьми #res-bar, как было до разделения на два ряда. В Chrome
   это работает, а WEBKIT (Safari) на `display: contents` внутри flex с `gap`
   раскладывает ВНУКОВ неправильно: у каждого ресурса число уезжало на 305 px
   от своего значка и прилипало к следующему, а разделители схлопывались в
   ноль. Замерено в Playwright/webkit: `.res-item` шириной 67 px, а его второй
   ребёнок — на x = +305 от первого.

   Поэтому ряды остаются НАСТОЯЩИМИ флекс-блоками: первый — запасы эхонавта,
   он тянется и толкает второй вправо; второй — Связность, подсказки и кнопки.
   На экране порядок тот же, что был задуман, а «исчезающих» контейнеров, на
   которых спотыкается один из двух движков, больше нет.
   На мобильном оба ряда переносятся — см. @media ниже. */
.res-bar-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Ширину обоих рядов ставит syncHeaderColumns() по фактическим колонкам под
   шапкой (#302, #303); flex-основа нулевая, чтобы заданная ширина не спорила
   с содержимым. Без замера — прежнее поведение: первый ряд тянется. */
#res-bar-row-1 { flex: 1 1 auto; }
#res-bar-row-2 { flex: 0 0 auto; }
.res-item {
  display: flex;
  align-items: center;
  /* Внутри пары «значок + число» зазор ДОЛЖЕН быть заметно меньше, чем между
     соседними ресурсами. Было 6 внутри против 8 снаружи — почти поровну, и
     глаз собирал пару неправильно: число прилипало к СЛЕДУЮЩЕМУ значку.
     Заказчик 30.08.2026: «расстояние между ресурсами большое, они наезжают
     друг на друга». На широком экране это пряталось за распорками, на окне
     около 1000 px вылезало во весь рост. */
  gap: 5px;
  cursor: default;
  position: relative;
  white-space: nowrap;
}
/* Ресурсы отделены друг от друга втрое сильнее, чем значок от своего числа. */
.res-item + .res-item { margin-left: 13px; }
.res-item svg { flex-shrink: 0; width: 27px; height: 27px; }
.res-item[data-tip]:hover::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: #0a1520;
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 3px 8px;
  font-size: 15px;
  color: var(--text);
  white-space: nowrap;
  pointer-events: none;
  z-index: 50;
}
/* flex: 0 0 1px обязателен: волосок шириной 1 px флекс с радостью сжимает в
   ноль, и в WebKit он именно так и пропадал — группы ресурсов теряли границы. */
.res-divider { flex: 0 0 1px; width: 1px; height: 26px; background: var(--border); margin: 0 4px; }
/* Распорка сжимается до нуля, когда места мало, и тогда соседние блоки
   слипаются: у заказчика счётчик кредитов налезал на слово «ПОДСКАЗКИ», а
   первое число — на кардиограмму Связности. Минимум держит их порознь на
   любой ширине. */
.res-divider.flex-grow { flex: 1 0 auto; width: auto; min-width: 14px; background: none; }
/* Плашка кредитов в шапке слоя: содержимое к правому краю. Остальные .res-item
   остаются прижатыми влево — по этому различию кредиты и читаются как отдельная
   величина, а не как последний ресурс добычи. */
.res-item.res-money { justify-content: flex-end; text-align: right; }
#turn-label { font-size: 17px; color: var(--dim); letter-spacing: 1px; }
/* Счётчик на время «набегания» суммы: подсвечен, чтобы прирост было видно. */
.counting {
  color: var(--gold) !important;
  text-shadow: 0 0 8px rgba(240,208,96,.85);
  animation: counting-pulse var(--t-in) ease-in-out infinite alternate;
}
@keyframes counting-pulse {
  from { transform: scale(1); }
  to   { transform: scale(1.16); }
}

/* ─── GAME AREA ──────────────────────────────────── */
#game-area {
  display: flex;
  /* 5 px, а не 10: столько же добавлено колонке контура слева (margin-left у
     #battery-col), и без этой компенсации сетка стала бы уже на 5 px. */
  gap: 5px;
  align-items: flex-start;
  position: relative;   /* система координат для #power-rig */
}

/* ─── ЭНЕРГОСХЕМА: рамка контура + кабели к инструментам ──────────
   Показывает, куда сейчас уходит заряд: рамка вокруг контура горит цветом
   активного инструмента, а два кабеля идут вниз к Зонду (бирюзовый) и
   Эхолучу (золотой).

   Кабели НЕ перекрашиваются — это схема питания, а не индикатор: перекрашивай
   мы их, игрок каждый раз перечитывал бы, куда какой идёт. Активный кабель
   ярче и светится, спящий приглушён — и рамка называет активный цветом.

   Слой прозрачный для мыши: он лежит поверх колонок и не должен перехватывать
   клики по сетке и карточкам.

   z-index 0 (а НЕ 1) — принципиально: карточки слотов позиционированы
   (position:relative) и стоят в разметке ПОЗЖЕ, поэтому рисуются поверх этого
   слоя. Именно так «верстак» уходит под слоты, а наружу торчит только его край.
   С z-index:1 планка легла бы поверх карточек и закрыла их. */
#power-rig {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: 0;
  overflow: visible;
}
.rig-frame {
  fill: none;
  stroke-width: 2;
  transition: stroke var(--t-in), filter var(--t-in);
}
.rig-cable {
  fill: none;
  /* #298: шнуры в полтора раза толще — 3 → 4.5. Тонкая линия на поле, где всё
     остальное крупное, читалась как царапина, а не как питание прибора. */
  stroke-width: 4.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity var(--t-in), filter var(--t-in);
}
/* #298: после переключения шнур взятого инструмента мигает четыре раза. Это
   ответ прибора на команду: «питание ушло сюда». Длительность и число повторов
   те же, что в RIG_BLINK_MS у game.js, — расходиться им нельзя, иначе класс
   снимут посреди мигания. */
.rig-cable.rig-blink { animation: rig-blink var(--t-in) steps(1) 4; }
@keyframes rig-blink {   /* мигание шнура после переключения инструмента */
  0%, 49%  { opacity: .95; }
  50%, 99% { opacity: .18; }
  100%     { opacity: .95; }
}
/* Спящий кабель виден, но не спорит с активным. */
.rig-cable.rig-idle   { opacity: .22; }
.rig-cable.rig-active { opacity: .95; }
/* Наконечники-стрелки удалены вместе с узлами: кабель просто заходит в
   торчащий край верстака и там кончается (см. buildPowerRig). */
/* Искра: бежит по кабелю (animateMotion), удаляется по завершении из JS. */
.rig-spark { pointer-events: none; }

/* #299: метка «этого вы ещё не видели» на карточке витрины. Звезда живёт в
   правом верхнем углу карточки и мигает, пока в карточку не ткнули. Мигание
   медленное (1.1 с): рядом идёт список покупок, и быстрая пульсация читалась бы
   как ошибка, а не как новинка. */
.shop-item-star {
  position: absolute; top: 6px; right: 8px;
  color: var(--gold); font-size: 17px; line-height: 1;
  opacity: 0; pointer-events: none; text-shadow: 0 0 8px rgba(240,208,96,.7);
}
.shop-item-new { position: relative; }
.shop-item-new .shop-item-star { animation: shop-star-blink 1.1s ease-in-out infinite; }
@keyframes shop-star-blink {   /* звезда «новинка» на карточке витрины */
  0%, 100% { opacity: .25; }
  50%      { opacity: 1; }
}

/* ─── BATTERY (left vertical) ───────────────────── */
#battery-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  width: 40px;
  flex-shrink: 0;
  /* #219: рамку схемы питания рисует buildPowerRig с отступом в 5 px вокруг этой
     колонки, и без сдвига она вылезала выше плашки слоя. Опускаем колонку ровно
     на толщину отступа — верх РАМКИ встаёт на верх плашки. Значение продублировано
     в game.js (RIG_FRAME_PAD) — менять только вместе.

     margin-left — та же величина и та же причина по горизонтали: рамка рисуется
     на RIG_FRAME_PAD левее колонки, и без сдвига её левая стенка уходила за
     левый край #game-area, а с ним и за край окна. Зазор #game-area уменьшен
     на те же 5 px, поэтому сетка ничего не теряет. */
  margin-top: 5px;
  margin-left: 5px;
}
/* Значение контура («8/10») шире колонки в 40 px и торчало из рамки в обе
   стороны. Кегль на знак меньше — надпись умещается внутри. */
#bat-val { font-size: 13px; letter-spacing: -0.5px; }
#bat-label { font-size: 14px; color: var(--dim); letter-spacing: 1px; }
#bat-pips {
  display: flex;
  flex-direction: column-reverse; /* bottom fills first */
  gap: 2px;
}
.bat-pip {
  width: 28px;
  height: 44px;
  border-radius: 3px;
  transition: background var(--t-tap), box-shadow var(--t-tap);
}
.bat-pip.empty   { background: #0c1e2e; border: 1px solid #14293d; }
.bat-pip.full    { background: var(--teal); box-shadow: 0 0 5px rgba(78,205,196,0.5); }
.bat-pip.warn    { background: var(--red) !important; box-shadow: 0 0 8px rgba(231,76,60,0.7) !important; }
/* #197: предпоследнее деление — оранжевое. Красный оставлен последнему: он
   означает «следующий Зонд по пустом секторе уйдёт в перезаряд», а
   предпоследнее — только предупреждение. */
.bat-pip.warn-mid { background: var(--yellow) !important; box-shadow: 0 0 8px rgba(243,156,18,0.7) !important; }
#bat-val { font-size: 14px; color: var(--dim); }

/* ─── CENTER COLUMN ─────────────────────────────── */
#center-col { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; }

/* ─── ЗАГОЛОВОК СЛОЯ ────────────────────────────
   Плашка «Сейчас: ЗОНД» заменена на заголовок: слева «Слой 7 (Слепая
   борозда)», справа «Рекорд: 1240». Активный инструмент и так виден по
   подсветке карточки, а место над сеткой ценнее занять тем, где игрок
   находится и что здесь можно побить.

   ГЛАВНОЕ ТРЕБОВАНИЕ: строка всегда одна, за рамку не выходит.
   Держится на трёх вещах — nowrap запрещает перенос, min-width:0 разрешает
   flex-элементу сжиматься ниже своего текста (без него ellipsis не сработает
   никогда), а ellipsis обрезает название, если места совсем нет. Рекорд
   не сжимается (flex-shrink:0): цифру нельзя показать «наполовину». */
#layer-title, #layer-title-mobile {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 6px 10px;
  border-radius: 3px;
  background: var(--panel);
  border: 1px solid var(--border);
  font-size: 14px;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
}
#layer-title .lt-name, #layer-title-mobile .lt-name {
  font-weight: bold;
  color: var(--teal);
  text-shadow: 0 0 8px rgba(78,205,196,.35);
  min-width: 0;                /* без этого flex не даст тексту сжаться, и ellipsis не сработает */
  overflow: hidden;
  text-overflow: ellipsis;
}
#layer-title .lt-rec, #layer-title-mobile .lt-rec {
  color: var(--gold);
  font-size: 12px;
  flex: 0 0 auto;              /* цифры не сжимаются и не обрезаются */
  /* #200: моноширинные цифры — иначе счёт «дёргает» дробь на каждом ходу, когда
     единица сменяется восьмёркой. tabular-nums держит ширину знака постоянной. */
  font-variant-numeric: tabular-nums;
}
/* #200: слева — очки, набранные в этом прохождении слоя, справа — рекорд. */
.lt-cur   { color: var(--teal); }
.lt-cur.lt-neg { color: var(--red); }   /* слой в минусе — видно сразу */
.lt-slash { color: var(--dim); margin: 0 3px; }
.lt-best  { color: var(--gold); }
/* Рекорд перекрыт: гасим до тёмного золота — цель достигнута, число осталось
   для сравнения, но внимание на себя больше не тянет. */
.lt-best.lt-beaten { color: #6b5a2a; text-shadow: none; }
/* ═══ ПЕРЕХВАТ ТАБЛО (#223) ═══════════════════════════════════════
   Два рейтинга лежат в разметке рядом (см. hijackHTML в game.js), а виден
   ровно один — тот, что назван в data-board на <html>. Разметка одна и та же
   и в заголовке над сеткой, и в строках экрана итогов, поэтому оба
   переключаются в такт от одного таймера.

   Мигание — .board-glitch на <html>: вспышки идут всё чаще, и под последней,
   самой быстрой, значения меняются местами. Как будто табло перехватили. */
/* Оба значения лежат В ОДНОЙ ячейке грида и потому занимают одно место —
   ширина блока равна ШИРОКОМУ из двух и при перехвате не меняется. Скрываем
   через visibility, а не display: display:none выключил бы элемент из
   раскладки, и окно вердикта дышало бы на каждой подмене (описание одного
   рекорда длиннее другого). */
.hj { display: inline-grid; grid-template-areas: "hj"; vertical-align: baseline; }
.hj-i, .hj-o { grid-area: hj; visibility: hidden; }
html[data-board="orden"] .hj-o,
html:not([data-board="orden"]) .hj-i { visibility: visible; }
/* Там, где числа прижаты к правому краю (табло над сеткой, правая колонка
   отчёта), короткое из двух значений обязано прижиматься туда же — иначе
   при подмене цифра прыгает внутри своего же, теперь фиксированного, места. */
.lt-rec .hj-i, .lt-rec .hj-o,
#overlay-stats .report-val .hj-i, #overlay-stats .report-val .hj-o { text-align: right; }

/* Ярко-синий Ордена — свой цвет, ни с чем в интерфейсе не спорит:
   Институт золотой, текущий счёт бирюзовый, опасность красная. */
.orden-num {
  color: #4fb0ff;
  text-shadow: 0 0 8px rgba(79,176,255,.45);
}
.lt-cur.orden-num, .lt-best.orden-num, .lt-slash.orden-num { color: #4fb0ff; }

@keyframes board-hijack {
  0%,  100% { opacity: 1; }
  /* редкие вспышки… */
  22%, 27%  { opacity: .12; }
  24%       { opacity: 1; }
  46%, 50%  { opacity: .12; }
  48%       { opacity: 1; }
  /* …и всё чаще к концу */
  66%, 69%  { opacity: .12; }
  67%       { opacity: 1; }
  80%, 82%  { opacity: .12; }
  81%       { opacity: 1; }
  90%, 92%  { opacity: .12; }
  91%       { opacity: 1; }
  96%, 97%  { opacity: .12; }
}
html.board-glitch .hj-i, html.board-glitch .hj-o {
  animation: board-hijack 1.15s linear;
}
/* Кому мигание мешает — системная настройка это выключает: обмен значениями
   остаётся, пропадают только вспышки. */
@media (prefers-reduced-motion: reduce) {
  html.board-glitch .hj-i, html.board-glitch .hj-o { animation: none; }
}

/* Слой массива — золотая рамка: она же цвет опасности в остальном интерфейсе. */
#layer-title.lt-boss, #layer-title-mobile.lt-boss { border-color: var(--gold); }
#layer-title.lt-boss .lt-name, #layer-title-mobile.lt-boss .lt-name {
  color: var(--gold); text-shadow: 0 0 8px rgba(240,208,96,.4);
}
/* Мобильный дубль внутри #tool-section — виден только через @media,
   на десктопе работает верхний. */
#layer-title-mobile { display: none; }

/* ─── GRID ───────────────────────────────────────── */
#grid-wrap { position: relative; border-radius: 3px; }
@keyframes freeze-snow {
  0%   { box-shadow: 0 0 0 3px rgba(160,220,255,.35), 0 0 18px 4px rgba(100,180,255,.15); border-color: rgba(140,210,255,.4); }
  50%  { box-shadow: 0 0 0 4px rgba(200,240,255,.7),  0 0 28px 8px rgba(140,210,255,.3);  border-color: rgba(200,240,255,.85); }
  100% { box-shadow: 0 0 0 3px rgba(160,220,255,.35), 0 0 18px 4px rgba(100,180,255,.15); border-color: rgba(140,210,255,.4); }
}
#grid-wrap.freeze-active {
  border: 2px solid rgba(140,210,255,.5);
  animation: freeze-snow 1.8s ease-in-out infinite;
  border-radius: 3px;
}
@keyframes contrascan-pulse {
  0%   { box-shadow: 0 0 0 3px rgba(240,208,96,.35), 0 0 18px 4px rgba(240,176,32,.18); border-color: rgba(240,208,96,.5); }
  50%  { box-shadow: 0 0 0 4px rgba(255,228,140,.75), 0 0 28px 8px rgba(240,200,80,.35); border-color: rgba(255,228,140,.95); }
  100% { box-shadow: 0 0 0 3px rgba(240,208,96,.35), 0 0 18px 4px rgba(240,176,32,.18); border-color: rgba(240,208,96,.5); }
}
#grid-wrap.contrascan-active {
  border: 2px solid rgba(240,208,96,.7);
  animation: contrascan-pulse var(--t-in) ease-in-out infinite;
  border-radius: 3px;
}

/* ─── ПОМЕХА ПРИ ПОТЕРЕ СВЯЗНОСТИ (заказчик, 06.09.2026) ───
   «Небольшое помутнение рассудка»: поле на мгновение теряет резкость и
   цветовые каналы расходятся, потом всё собирается обратно. Эффект стоит
   ИМЕННО НА ПОЛЕ — удар случился здесь, и смотреть игрок должен сюда, а не
   в шапку. Значок Связности улетает к счётчику уже ПОСЛЕ помехи.

   Класс висит на #grid, а не на #grid-wrap: className обёртки renderGrid
   переписывает целиком (game.js), и таймерный класс слетал бы молча.
   Длительность продублирована в JS (FIELD_GLITCH_MS) — менять парой. */
/* «НЕБОЛЬШОЕ помутнение» — мера здесь важнее самого приёма. Первая редакция
   шла blur(2px) с заливкой в половину альфы, и на снимке поле переставало
   читаться совсем: игрок, которому только что нанесли урон, на треть секунды
   терял доску. Резкость теперь уходит вдвое меньше, а цвет только тронут. */
@keyframes hit-defocus {
  0%   { filter: none; }
  22%  { filter: blur(1.1px) saturate(.7) brightness(1.08); }
  55%  { filter: blur(.7px) saturate(.85); }
  100% { filter: none; }
}
#grid.hit-glitch { animation: hit-defocus var(--t-in) ease-out; }

/* Двоение: цветной слой уезжает относительно размытой сетки. Красный уходит
   влево, бирюзовый вправо — те же два цвета, что у обрывающейся кардиограммы
   в летящем значке, чтобы удар читался одним пятном. mix-blend-mode: screen —
   слой ПОДСВЕЧИВАЕТ поле, а не закрашивает его: сектора должны остаться
   читаемыми даже в самый мутный кадр. */
#grid-fx {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  mix-blend-mode: screen;
  background:
    linear-gradient(90deg, rgba(231,76,60,.30) 0%, rgba(231,76,60,0) 26%),
    linear-gradient(270deg, rgba(78,205,196,.26) 0%, rgba(78,205,196,0) 26%);
}
@keyframes hit-split {
  0%   { opacity: 0; transform: translateX(0); }
  22%  { opacity: 1; transform: translateX(-5px); }
  55%  { opacity: .7; transform: translateX(4px); }
  100% { opacity: 0; transform: translateX(0); }
}
#grid.hit-glitch + #grid-fx { animation: hit-split var(--t-in) ease-out; }

/* Движение убираем, смысл оставляем — принятый в проекте приём: без расфокуса
   и сдвига, но одной вспышкой удар всё равно объявлен. */
@keyframes hit-split-calm {
  0%, 100% { opacity: 0; }
  30%      { opacity: .9; }
}
@media (prefers-reduced-motion: reduce) {
  #grid.hit-glitch { animation: none; }
  #grid.hit-glitch + #grid-fx { animation: hit-split-calm var(--t-in) ease-out; }
}
#grid {
  display: grid;
  grid-template-columns: repeat(10, var(--cell-size)); /* overridden by JS for boss room */
  grid-template-rows: repeat(10, var(--cell-size));
  gap: 2px;
  background: #020608;
  padding: 4px;
  border: 1px solid var(--border);
  border-radius: 3px;
}

/* ─── CELLS ─────────────────────────────────────── */
.cell {
  width: var(--cell-size); height: var(--cell-size);
  display: flex; align-items: center; justify-content: center;
  /* размер шрифта задаётся инлайн в renderGrid (зависит от cs); здесь только жирность.
     На мобильном жирность повышается до 800 (см. @media) — на десктопе как было. */
  font-size: calc(var(--cell-size) / 2); font-weight: bold;
  border-radius: 3px; cursor: pointer;
  user-select: none;
  transition: background var(--t-tap), box-shadow var(--t-tap);
  position: relative;
}
.cell-hidden { background: var(--surface); border: 1px solid var(--surface-line); }
.tool-equip-pending .cell-hidden { cursor: crosshair; }
/* Cell-hover показываем только на устройствах с реальным курсором — на таче залипает после тапа. */
@media (hover: hover) {
  .tool-locator   .cell-hidden:hover { background: #122234; border-color: var(--teal); box-shadow: 0 0 9px rgba(78,205,196,.35); }
  .tool-echobeamer .cell-hidden:hover { background: #18180a; border-color: var(--gold); box-shadow: 0 0 9px rgba(240,208,96,.35); }
  .tool-equip-pending .cell-hidden:hover { background: #1a1400; border-color: #f0d060; box-shadow: 0 0 9px rgba(240,208,96,.5); }
}
/* Тап-фидбек: короткая pulse-анимация цвета активного инструмента (заменяет hover на тач-устройствах). */
@keyframes cell-tap-pulse-teal {
  0%   { background: #0d1b2a; box-shadow: 0 0 0 0 rgba(78,205,196,0); }
  35%  { background: #1a4555; box-shadow: 0 0 14px 4px rgba(78,205,196,.55); }
  100% { background: #0d1b2a; box-shadow: 0 0 0 0 rgba(78,205,196,0); }
}
@keyframes cell-tap-pulse-gold {
  0%   { background: #0d1b2a; box-shadow: 0 0 0 0 rgba(240,208,96,0); }
  35%  { background: #3a3010; box-shadow: 0 0 14px 4px rgba(240,208,96,.55); }
  100% { background: #0d1b2a; box-shadow: 0 0 0 0 rgba(240,208,96,0); }
}
.tool-locator   .cell-tapped { animation: cell-tap-pulse-teal var(--t-in) ease-out; }
.tool-echobeamer .cell-tapped { animation: cell-tap-pulse-gold var(--t-in) ease-out; }
.tool-equip-pending .cell-tapped { animation: cell-tap-pulse-gold var(--t-in) ease-out; }
.cell-empty  { background: #040a12; border: 1px solid #08111c; cursor: default; }
/* СЕКТОР, СЪЕДЕННЫЙ МАССИВОМ (#359). Вскрытый Массивом сектор выглядел бы ровно
   так же, как вскрытый игроком, и потеря проходила бы незаметно — а «слой
   пустеет» и есть картинка Поглощения. Метка тихая: сектор уже мёртв, кричать
   о нём каждый ход незачем, поэтому не заливка, а фиолетовая тень внутрь —
   цветом Массива и Искажения. */
.cell-absorbed { box-shadow: inset 0 0 0 1px rgba(155, 89, 182, .55), inset 0 0 7px rgba(155, 89, 182, .35); }
/* ОТКУДА ЗАБРАЛИ В ПОСЛЕДНИЙ РАЗ (заказчик, 09.09.2026). Пульсирует, пока Глаз
   не заберёт снова: игрок видит, что именно у него утекло в этот такт, и с какой
   стороны Массив подбирается.

   Дышит ЯРКОСТЬЮ РАМКИ, а не размером и не фоном: сектор стоит в сетке 10×10,
   и любое изменение геометрии сдвинуло бы соседей — сетка «поехала» бы каждый
   такт. Тот же довод, по которому тряска карточки Массива сделана сдвигом на
   пиксель, а не поворотом. */
@keyframes cell-absorb-last {
  0%, 100% { box-shadow: inset 0 0 0 1px rgba(155, 89, 182, .55), inset 0 0 7px rgba(155, 89, 182, .35); }
  50%      { box-shadow: inset 0 0 0 2px rgba(190, 130, 220, .95), inset 0 0 14px rgba(190, 130, 220, .6); }
}
.cell-absorb-last { animation: cell-absorb-last 1.25s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  /* Без анимации метка остаётся статичной, но заметной: это единственный
     указатель на то, откуда только что утекла энергия. */
  .cell-absorb-last {
    animation: none;
    box-shadow: inset 0 0 0 2px rgba(190, 130, 220, .95), inset 0 0 14px rgba(190, 130, 220, .6);
  }
}
.cell-number { background: #060e1c; border: 1px solid #0c1e2e; cursor: default; }
.num-1{color:#4ecdc4}.num-2{color:#2ecc71}.num-3{color:#f39c12}
.num-4{color:#e74c3c}.num-5{color:#9b59b6}.num-6{color:#1abc9c}
.num-7{color:#e91e63}.num-8{color:#fff}
.cell-open  { cursor: default; }
.open-green  { background:rgba(46,204,113,.12); border:1px solid rgba(46,204,113,.3); color:rgba(46,204,113,.5); }
.open-yellow { background:rgba(243,156,18,.12); border:1px solid rgba(243,156,18,.3); color:rgba(243,156,18,.5); }
.open-red    { background:rgba(231,76,60,.12);  border:1px solid rgba(231,76,60,.3);  color:rgba(231,76,60,.5); }
.open-blue   { background:rgba(52,152,219,.12); border:1px solid rgba(52,152,219,.3); color:rgba(52,152,219,.5); }
.open-purple { background:rgba(155,89,182,.12); border:1px solid rgba(155,89,182,.3); color:rgba(155,89,182,.5); }
/* Раскрытый Зондом сегмент эфемера: иконка Эхолуча «бей сюда».
   #177: мигает ровно 5 раз (5.5 с) и остаётся стоять непрозрачной. Анимация
   висит НЕ на самой иконке, а на классе-модификаторе .cell-beam-blink, который
   renderGrid снимает по истечении срока: иначе после конца анимации иконка
   вернулась бы к первому кадру (opacity .22) и стала бы еле видна.
   Длительность продублирована в game.js (флаг c.beamBlinkDone) — менять вместе. */
.cell-beam-hint .beam-hint-svg { width: 74%; height: 74%; pointer-events: none; filter: drop-shadow(0 0 3px rgba(240,208,96,.7)); }
.cell-beam-blink .beam-hint-svg,
.cell-beam-blink .mem-unknown-svg { animation: beam-hint-blink 1.1s ease-in-out 5; }
@keyframes beam-hint-blink { 0%,100% { opacity: .22; } 50% { opacity: 1; } }
/* #176: мембрана, найденная Зондом в лёгком режиме, — пучок «???».
   Крупнее иконки Эхолуча: три знака в секторе 46px должны читаться. */
.cell-membrane-unknown .mem-unknown-svg { width: 86%; height: 86%; pointer-events: none; filter: drop-shadow(0 0 3px rgba(240,208,96,.7)); }
.cell-scanned { cursor: default; }
.scanned-green  { background:rgba(46,204,113,.25); border:1px solid rgba(46,204,113,.6); color:var(--green); box-shadow:0 0 10px rgba(46,204,113,.4); }
.scanned-yellow { background:rgba(243,156,18,.25); border:1px solid rgba(243,156,18,.6); color:var(--yellow); box-shadow:0 0 10px rgba(243,156,18,.4); }
/* ─── ЦВЕТНЫЕ ТЕРМИНЫ В ТЕКСТАХ (#178) ───────────────────────────────
   Название цвета эфемера пишется цветом этого эфемера; ВОЗБУЖДЕНИЕ — красным,
   СКОЛЬЖЕНИЕ — синим (см. colorizeTerms в game.js). Значения те же, что у секторов и
   плашек эфемеров: цвет слова обязан совпадать с цветом тела на сетке, иначе
   подсказка начнёт спорить с тем, что игрок видит.
   font-weight здесь намеренно: на тёмном фоне тонкий цветной шрифт читается
   хуже белого, и без утолщения выделение выглядело бы блёклым, а не акцентом. */
.term-green  { color: #2ecc71; font-weight: bold; }
.term-yellow { color: #f39c12; font-weight: bold; }
.term-red    { color: #e74c3c; font-weight: bold; }
.term-blue   { color: #4ecdc4; font-weight: bold; }
/* Фиолетовый — единственное отступление от палитры секторов: #9b59b6 на почти
   чёрном фоне читается тяжело (тёмное на тёмном), поэтому в ТЕКСТЕ он взят
   светлее. На сетке и в плашках остаётся прежний #9b59b6 — там под ним заливка. */
.term-purple { color: #b07cd0; font-weight: bold; }

/* ─── ИКОНКИ МЕМБРАН (#177) ──────────────────────────────────────────
   Двенадцать рисунков вместо юникод-символов, которые сливались в секторе
   (◎ ⊕ ⊙ — круги, ✦ ✸ — звёзды, ◈ ◇ — ромбы). Файлы: img/membranes/M-NN.svg,
   game-icons.net, CC BY 3.0, авторы — docs/credits.md.

   Рисуем МАСКОЙ, а не <img>: маска заливается currentColor, поэтому один файл
   работает во всех состояниях — фиолетовым на секторе, золотым у сработавшей
   мембраны (.membrane-triggered ниже), бирюзовым в СИГНАТУРАХ. Через <img> цвет
   пришлось бы вшить в файл и держать по копии на каждый случай.
   -webkit-mask-* нужен Safari и старому Chrome; без префикса там пустое место. */
/* Рисунок ВСТРОЕН в разметку (MEMBRANE_ICONS в game.js) — здесь только размер
   и выравнивание. Прежняя версия рисовала маской (mask-image + url на файл),
   и у заказчика иконки не появлялись вовсе: маске нужны и поддержка браузера,
   и загруженный файл, и верный MIME, и отсутствие filter на элементе. Теперь
   ни одной такой зависимости — цвет берётся из currentColor самим SVG. */
.mem-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.15em; height: 1.15em;
  vertical-align: -0.2em;
  line-height: 1;
}
.mem-ic > svg { width: 100%; height: 100%; display: block; }
/* Запасной вариант — юникод-символ вместо рисунка (карта не сгенерирована).
   Ему нужен нормальный кегль, иначе символ окажется мельче своего сектора. */
.mem-ic-text { font-size: 1em; }
/* В секторе слоя иконка крупнее относительно кегля: рисунок должен читаться
   там, где раньше стоял один жирный символ. */
.cell .mem-ic { width: 1.35em; height: 1.35em; vertical-align: -0.3em; }
.mem-sym-lg { width: 1.3em !important; height: 1.3em !important; }
/* Глаз Массива. Крупнее мембранной иконки и с собственным свечением: это
   единственная уязвимость Массива, её нужно видеть через всё поле. */
.eye-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5em; height: 1.5em; line-height: 1; vertical-align: -0.35em;
}
.eye-ic > svg { width: 100%; height: 100%; display: block; }

/* #292: значок Глаза внутри текста записи Архива. Мерится в em и садится на
   базовую линию: рядом стоят обычные буквы, и в пикселях он разъезжался бы с
   ними при любом другом кегле (та же грабля, что была с эмодзи ресурсов). */
.hint-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.15em; height: 1.15em; line-height: 1; vertical-align: -0.22em;
  color: var(--gold);
}
.hint-ic > svg { width: 100%; height: 100%; display: block; }

/* Сработавшая мембрана: только золотой цвет, без свечения на самой иконке.
   Тут был `filter: drop-shadow()` на .mem-ic — и это единственное место, где
   сработавшая мембрана отличалась от прочих. Заказчик видел её пустой, тогда
   как остальные рисовались: filter поверх CSS-маски — известная больная точка
   движков (элемент получает свой слой композитинга, и в ряде сборок WebKit/Blink
   замаскированный элемент пропадает целиком). Свечение декоративно, различение
   даёт цвет — поэтому убрано, а не «починено» подпорками. */
.membrane-triggered { color: var(--gold) !important; text-shadow: 0 0 10px rgba(240,208,96,.9); }

/* ── ЗАВЕРШЁННЫЙ ЭФЕМЕР ─────────────────────────────
   Тело, с которым уже нечего делать, гасится: свечение снимается, заливка
   темнеет, символ — крест. Но КОНТУР сохраняет цвет эфемера — по нему на
   сетке читается, кто здесь лежал, даже когда работа закончена.
   Раньше здесь стоял серый border-color с !important — он бил по всем цветам
   и обесцвечивал завершённые тела.
   ВНИМАНИЕ: не писать в комментарии последовательность звёздочка-слэш —
   она закрывает комментарий досрочно и ломает следующее правило. */
.cell-eph-done {
  box-shadow: none !important;
  border-style: dashed !important;
  background: rgba(255,255,255,.035) !important;
  opacity: .72;
  font-weight: bold;
}
/* Контур задаём явно и одинаково ярко для обоих состояний сегмента: у секторов,
   вскрытых Зондом (open-), собственная рамка всего .3 альфы, и после
   приглушения opacity она пропадала вовсе. Цвет — единственное, что осталось
   от эфемера на сетке, поэтому он должен читаться. */
.cell-eph-done.open-green,  .cell-eph-done.scanned-green  { border-color: rgba(46,204,113,.8) !important; }
.cell-eph-done.open-yellow, .cell-eph-done.scanned-yellow { border-color: rgba(243,156,18,.8) !important; }
.cell-eph-done.open-red,    .cell-eph-done.scanned-red    { border-color: rgba(231,76,60,.8)  !important; }
.cell-eph-done.open-blue,   .cell-eph-done.scanned-blue   { border-color: rgba(59,130,246,.8) !important; }
.cell-eph-done.open-purple, .cell-eph-done.scanned-purple { border-color: rgba(155,89,182,.8) !important; }
/* Крест рисуем крупнее точки — он и есть «зачёркнутая» сектор */
.cell-eph-done:not(.cell-eye):not(.membrane-triggered) { letter-spacing: 0; }
@keyframes flash-red { 0%,100%{opacity:1} 50%{background:rgba(231,76,60,.5);opacity:.8} }
.flash { animation: flash-red var(--t-in) ease; }

/* Цифра рядом со скрытой мембраной.
   Пять вспышек по 0.5 с = 2.5 с (было три / 1.5 с): сигнал легко пропустить,
   если взгляд в этот момент в другой части сетки. Длительность продублирована
   в game.js (сброс флага c.membraneNear) — менять только вместе.

   #193: МЕДЛЕННОЕ мигание — примета ЛЁГКОГО режима (класс -easy ниже), в обычном
   вспышка осталась быстрой и конечной. Причина не в скорости как таковой:
   renderGrid пересоздаёт сектора на каждом ходу, анимация начинается с нулевого
   кадра, и на двухсекундной вспышке активный игрок видел только тусклое начало
   разгорания — сигнал в обычном режиме получался слабее прежнего. У лёгкого
   мигание бесконечное, и там та же беда лечится фазой (см. easyBlinkPhase). */
/* МЕТКА «РЯДОМ СКРЫТА МЕМБРАНА» (заказчик, 06.09.2026). Рамка внутренней
   тенью, а не border: у сектора уже есть своя рамка в 1 px, и вторая сдвинула
   бы содержимое — сетка 10×10 поехала бы на пиксель. Цвет — золото мембран,
   тот же, что у вспышки ниже: метка и мигание говорят об одном. */
.cell-mem-mark { box-shadow: inset 0 0 0 2px rgba(240,208,96,.55); }
.cell-membrane-near { animation: membrane-near-blink .5s ease-in-out 5; }
/* #175, лёгкий режим: тот же сигнал, но без счёта вспышек — мигает, пока
   мембрана рядом не вскрыта. Останавливает его не таймер, а сама игра:
   renderGrid перестаёт вешать класс, когда мембрана становится видимой.
   Оттого и infinite: конца у анимации быть не должно.
   #193: и МЕДЛЕННО — 2 с против 0.5 с в обычном режиме. Медленное дыхание —
   примета лёгкого: оно спокойнее и заметнее боковым зрением, а торопить
   новичка нечем. Длительность продублирована в game.js (EASY_BLINK_MS,
   отрицательная задержка для сохранения фазы) — менять только вместе. */
.cell-membrane-near-easy { animation: membrane-near-blink 2s ease-in-out infinite; }
/* #199, лёгкий режим: сегмент СРАБОТАВШЕЙ мембраны. Намеренно та же анимация,
   что у цифр-указателей выше, — заказчик просил «мигать так же, как ранее
   сектора, которые указывают на них»: одинаковый ритм и связывает эти два
   состояния в одну историю. */
.cell-membrane-fired-easy { animation: membrane-near-blink 2s ease-in-out infinite; }
@keyframes membrane-near-blink {
  0%, 100% { background: transparent; box-shadow: none; }
  50% {
    background: rgba(240,208,96,.42);
    box-shadow: 0 0 12px 2px rgba(240,208,96,.75) inset;
    color: #fff8dc;
  }
}

/* Sonar ping */
@keyframes sonar-ping { 0%{transform:scale(.4);opacity:.8} 100%{transform:scale(2);opacity:0} }
.sonar-ping {
  position: absolute; width: 100%; height: 100%;
  border-radius: 50%; border: 2px solid var(--teal);
  animation: sonar-ping var(--t-in) ease-out forwards;
  pointer-events: none;
}

/* ─── TOOL SECTION (hints row + cards row share one grid) ── */
#tool-section {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 7px;
  row-gap: 5px;
  /* default align-items: stretch — все слоты в одной строке одинаковой высоты */
}
.slot-key-hint { text-align: center; font-size: 14px; color: var(--dim); align-self: center; }
kbd { background: var(--surface); border: 1px solid var(--border); border-radius: 3px; padding: 1px 5px; font-family: var(--font-mono); font-size: 13px; }
/* ─── COMBO LAMPS ────────────────────────────────── */
/* На зонде нет card-cost — лампочки занимают её место (в потоке) */
#combo-lamps {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin-top: 2px;
}
.combo-lamp {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #0c1e2e;
  border: 1px solid #1a3a5c;
  transition: background var(--t-tap), box-shadow var(--t-tap);
}
.combo-lamp.lit {
  background: var(--teal);
  box-shadow: 0 0 5px rgba(78,205,196,.7);
  border-color: var(--teal);
}

#btn-exit-room {
  grid-column: 3 / 5;
  justify-self: end;
  align-self: center;
  background: none; border: 1px solid var(--red); color: var(--red);
  padding: 4px 12px; font-family: var(--font-mono); font-size: 14px;
  letter-spacing: 1px; border-radius: 3px; cursor: pointer; transition: all var(--t-tap);
}
#btn-exit-room:hover { background: rgba(231,76,60,.12); }
/* #323: запертый шлюз. Кнопка больше не `disabled` — иначе браузер не шлёт ей
   события мыши, и подсказка «почему заперто» молчала бы ровно там, где нужна
   (см. renderGrid). Значит вид «нельзя» держим сами: подсветки при наведении
   нет, и кнопка не притворяется нажимаемой. */
#btn-exit-room[aria-disabled="true"]:hover { background: none; }

/* ─── TOOL CARDS ─────────────────────────────────── */
.card-slot {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
  transition: all var(--t-tap);
  overflow: hidden;
  position: relative;
  user-select: none;
  outline: none;
  caret-color: transparent;
  /* ПРАВИЛО: все слоты одинаковой высоты, контент не растягивает строку */
  height: 134px;
  min-width: 0;
  max-width: 100%;
}
.card-slot:hover:not(.empty) { border-color: var(--dim); }
.card-slot.sel-locator    { border-color: var(--teal); box-shadow: 0 0 12px rgba(78,205,196,.3); background: rgba(78,205,196,.06); }
.card-slot.sel-echobeamer { border-color: var(--gold); box-shadow: 0 0 12px rgba(240,208,96,.3); background: rgba(240,208,96,.06); }
/* Искажение на Зонде — только перекраска рамки. Полоска обратного отсчёта
   убрана (#214): индикатор обязан считать сектора, а не такты, и его место
   занимают лампы счётчика. Сколько тактов окну осталось — на плашке эфемера. */
.card-slot.boss-invert-active { border-color: #9b59b6 !important; box-shadow: 0 0 14px rgba(155,89,182,.45) !important; background: rgba(155,89,182,.07) !important; }
.card-slot.empty      { cursor: default; border-style: dashed; opacity: .4; }
/* Закрытый слот: пунктир и приглушённый тон, но ЧИТАЕМЫЙ. При opacity .35 и
   красноватой подложке цена «90 КР» пропадала — игрок не видел, что слот
   вообще можно открыть (в макете .L-slot-off нейтрален и виден). */
.card-slot.slot-locked { cursor: default; border-style: dashed; opacity: .62; background: rgba(126,168,190,.022); }
.card-slot.slot-locked .locked-icon { font-size: 20px; margin-top: 24px; opacity: .5; }
.card-slot.consumable-shield   { border-color: #4ecdc4; box-shadow: 0 0 10px rgba(78,205,196,.25); cursor: pointer; }
.card-slot.consumable-shield.shield-cracked { border-color: #e7943c; box-shadow: 0 0 10px rgba(231,148,60,.35); }
.card-slot.consumable-powerbank { border-color: #f0d060; box-shadow: 0 0 10px rgba(240,208,96,.25); cursor: pointer; }
.card-slot.consumable-shield:hover   { border-color: #7eeee7; box-shadow: 0 0 14px rgba(78,205,196,.4); }
.card-slot.consumable-shield.shield-cracked:hover { border-color: #ffb060; }
.card-slot.consumable-powerbank:hover { border-color: #ffe080; box-shadow: 0 0 14px rgba(240,208,96,.4); }
.card-slot.equip-slot {
  cursor: pointer;
  display: flex;
  flex-direction: column;
  border-width: 2px;
  padding: 0;
  overflow: hidden;
}
.card-slot.equip-slot:hover { filter: brightness(1.08); }
.equip-type-badge { font-size: 8px; color: var(--dim); text-transform: uppercase; letter-spacing: .5px; margin-top: 6px; }
.card-slot.chaos-shield-slot { border-color: #ff6b35; box-shadow: 0 0 10px rgba(255,107,53,.25); cursor: default; }
.card-slot.chaos-shield-slot:hover { border-color: #ff9060; box-shadow: 0 0 14px rgba(255,107,53,.4); }
@keyframes chaos-trigger-flash {
  0%   { box-shadow: 0 0 0 0 rgba(255,107,53,0); background: var(--panel); }
  20%  { box-shadow: 0 0 24px 10px rgba(255,107,53,.85); background: rgba(255,107,53,.3); border-color: #ffcc99 !important; }
  55%  { box-shadow: 0 0 16px 5px rgba(255,107,53,.5); background: rgba(255,107,53,.15); }
  100% { box-shadow: 0 0 10px rgba(255,107,53,.25); background: var(--panel); }
}
.card-slot.chaos-flash { animation: chaos-trigger-flash 2.5s ease-out forwards !important; }

/* ─── ТИПОВАЯ ПОЛОСА-ШАПКА ───────────────────────────── */
.eq-strip {
  flex-shrink: 0;
  width: 100%;
  font-size: 9px;
  font-weight: bold;
  letter-spacing: 1.5px;
  text-align: center;
  padding: 5px 0 4px;
  border-bottom: 1px solid;
  text-transform: uppercase;
}

/* ─── ТЕЛО КАРТОЧКИ ──────────────────────────────────── */
.eq-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4px 4px 16px;
  gap: 3px;
}
.eq-id {
  font-size: 9px;
  color: var(--dim);
  letter-spacing: 1px;
}
.eq-name {
  font-size: 11px;
  font-weight: bold;
  color: var(--text);
  text-align: center;
  word-break: break-word;
  line-height: 1.3;
}
.eq-status {
  font-size: 10px;
  letter-spacing: 0.5px;
}

/* ─── ИНСТРУМЕНТЫ — teal сканлайны ──────────────────── */
.eq-tool {
  background-image: repeating-linear-gradient(
    0deg, transparent, transparent 11px,
    rgba(78,205,196,0.05) 11px, rgba(78,205,196,0.05) 12px
  );
}
.eq-tool-strip {
  background: #051c1c;
  color: #4ecdc4;
  border-bottom-color: rgba(78,205,196,.4);
}
.eq-tool.equip-pending .eq-strip { background: #1a1200; color: #f0d060; border-bottom-color: rgba(240,208,96,.4); }

/* ─── ПАССИВЫ — фиолетовое свечение ─────────────────── */
.eq-passive {
  background-image: radial-gradient(ellipse at 50% 65%, rgba(155,89,182,.13) 0%, transparent 72%);
  animation: passive-breathe 3s ease-in-out infinite;
}
@keyframes passive-breathe {
  0%,100% { box-shadow: 0 0 5px rgba(155,89,182,.2); }
  50%      { box-shadow: 0 0 14px rgba(155,89,182,.5); }
}
.eq-passive-strip {
  background: #0f0618;
  color: #b07dce;
  border-bottom-color: rgba(155,89,182,.4);
}

/* ─── РАСХОДНИКИ — оранжевая штриховка ──────────────── */
.eq-consumable {
  background-image: repeating-linear-gradient(
    -45deg,
    transparent, transparent 9px,
    rgba(230,126,34,.08) 9px, rgba(230,126,34,.08) 10px
  );
  border-style: dashed !important;
}
.eq-consumable-strip {
  background: #1a0d00;
  color: #e67e22;
  border-bottom-color: rgba(230,126,34,.4);
  border-style: solid;
}
@keyframes emi-block-pulse { 0%,100%{box-shadow:0 0 0 0 rgba(231,76,60,0)} 50%{box-shadow:0 0 10px 4px rgba(231,76,60,.65)} }
.card-slot.slot-blocked {
  border-color: rgba(231,76,60,.9) !important;
  background: rgba(231,76,60,.10) !important;
  opacity: 0.7;
  cursor: not-allowed !important;
  position: relative;
  animation: emi-block-pulse var(--t-slow) ease-in-out infinite;
}
.card-slot.slot-blocked::after {
  content: '☠';
  position: absolute;
  top: 4px; right: 6px;
  font-size: 17px;
  color: #e74c3c;
  text-shadow: 0 0 6px rgba(231,76,60,.9);
  pointer-events: none;
}
.emi-turns-badge {
  position: absolute;
  bottom: 3px; left: 50%;
  transform: translateX(-50%);
  font-size: 10px; font-weight: bold;
  color: #e74c3c;
  pointer-events: none;
  white-space: nowrap;
  text-shadow: 0 0 4px rgba(0,0,0,.8);
}
.card-inner {
  display: flex; flex-direction: column; align-items: center;
  padding: 10px 4px 8px;
  gap: 5px;
}
.card-art { width: 64px; height: 64px; }
/* Equipment art (AI-generated icons). Toggle via [data-equipment-art="on"] on <html>. */
.card-art-img {
  display: none;
  width: 64px; height: 64px;
  object-fit: contain;
  border-radius: 3px;
}
[data-equipment-art="on"] .card-art { display: none; }
[data-equipment-art="on"] .card-art-img { display: block; }
.card-name { font-size: 14px; letter-spacing: 2px; color: var(--text); font-weight: bold; word-break: break-word; overflow-wrap: break-word; }
.card-cost { font-size: 14px; }
.card-cost.teal { color: var(--teal); }
.card-cost.gold { color: var(--gold); }
.empty-inner { justify-content: center; min-height: 120px; }
.empty-plus  { font-size: 33px; color: var(--dim); opacity: .8; }
.empty-label { font-size: 14px; color: var(--dim); letter-spacing: 1px; opacity: .8; }

/* ─── INFO COLUMN ────────────────────────────────── */
#info-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 160px; /* ПРАВИЛО: правая панель не сжимается ниже 160px никогда */
  overflow: hidden;
}
.panel { background: var(--panel); border: 1px solid var(--border); border-radius: 3px; padding: 10px 12px; }
.panel-title { font-size: 14px; letter-spacing: 2px; color: var(--dim); text-transform: uppercase; margin-bottom: 8px; padding-bottom: 5px; border-bottom: 1px solid var(--border); }

/* Связность */
#hp-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
#hp-display { display: flex; gap: 7px; }
/* Потолок слоя: сколько заряда и Данные он способен отдать (считается на входе) */
#layer-potential, #sp-layer-potential { display: flex; gap: 10px; align-items: center; }
.lp-item {
  display: flex; align-items: baseline; gap: 4px;
  font-size: 16px; letter-spacing: .5px;
  padding: 2px 7px; border-radius: 3px;
  border: 1px solid var(--border); background: rgba(255,255,255,.02);
}
.lp-ico { font-size: 13px; opacity: .85; }
/* Значок Данные — копия иконки из шапки ресурсов (currentColor берёт цвет .lp-oi) */
.lp-ico-svg { flex-shrink: 0; align-self: center; opacity: .9; }
/* Подпись ресурса: без неё значки читались как деньги */
.lp-cap { font-size: 10px; letter-spacing: 1px; opacity: .7; }
/* Вторая цифра в скобках — доля остатка, лежащая в секторах сетки (пустые сектора
   для заряда, цифры для Данные). Раньше её жали до 12px и гасили до .6 «как
   уточнение» — в результате она просто не читалась. Кегль теперь общий с главной
   цифрой; роль второстепенной держат только скобки и лёгкое приглушение. */
.lp-sub { font-size: inherit; opacity: .85; margin-left: -1px; }

/* Цвета панелей (ТЗ): у Данные синий значок и белый текст, у Заряда — жёлтый значок
   и синий текст. Цвет на .lp-item задаёт ТЕКСТ (цифры и подпись), значку цвет
   назначается отдельно: SVG радара рисуется currentColor, а ⚡ — эмодзи, и на
   большинстве платформ оно и так жёлтое, но там, где шрифт даёт его контуром,
   правило ниже красит его явно. */
.lp-oi     { color: #ffffff; }
.lp-oi .lp-ico-svg { color: var(--teal); }
.lp-energy { color: var(--teal); }
.lp-energy .lp-ico { color: var(--yellow); }
/* Запас исчерпан: в слое этого ресурса больше нет. Гасим, чтобы «0» читался
   как состояние, а не как очередная цифра. */
.lp-drained { opacity: .35; text-decoration: line-through; }
/* Связность рисуется КАРДИОГРАММОЙ: целая линия у сохранившегося деления,
   оборванная у потерянного (docs/design/Layer.html). Сердце пришло из прежнего
   стиля вместе с эмодзи, которое рисовала система, а не игра; заодно ушла
   красная заливка — Связность это рассудок, и её цвет бирюзовый, как у всего
   исправного. Кегль 33→24: значок шире буквы, и на прежнем росте три деления
   не влезали в шапку. */
.heart { font-size: 24px; display: inline-flex; align-items: center; }
.heart.full  { color: var(--teal); filter: drop-shadow(0 0 6px rgba(78,205,196,.55)); }
/* Потерянное деление — КРАСНОЕ в полную силу, а не приглушённое до 55 %
   (заказчик, 30.08.2026: «её красным надо сделать, чтобы показать, что это как
   бы ранение»). Плоская кардиограмма сама по себе читается как отсутствие, но
   бледный красный на тёмном стирался в серый, и потеря не бросалась в глаза.
   Свечение такое же, как у целого деления, — иначе ряд распадается. */
.heart.empty { color: var(--red); filter: drop-shadow(0 0 6px rgba(231,76,60,.55)); }
/* Кинематографичный срыв: последнее сердце мигает 3 раза и гаснет. */
.heart.heart-dying {
  color: var(--red);
  animation: heart-die 1.1s ease forwards;
  transform-origin: center;
}
@keyframes heart-die {
  0%   { opacity: 1;  transform: scale(1);    text-shadow: 0 0 8px rgba(231,76,60,.7); }
  15%  { opacity: .15;transform: scale(1.25); }
  30%  { opacity: 1;  transform: scale(1);    text-shadow: 0 0 16px rgba(231,76,60,1); }
  45%  { opacity: .15;transform: scale(1.25); }
  60%  { opacity: 1;  transform: scale(1);    text-shadow: 0 0 16px rgba(231,76,60,1); }
  75%  { opacity: .15;transform: scale(1.3); }
  100% { opacity: 0;  transform: scale(.2);   text-shadow: none; }
}
/* Смертельная слепок сегмента крестом (Зонд по Эфемеру). */
.cell.cell-lethal-cross {
  color: #ff4d4d !important;
  box-shadow: 0 0 14px 3px rgba(231,76,60,.85) inset, 0 0 10px 2px rgba(231,76,60,.7);
  animation: lethal-cross-flash var(--t-in) ease 2;
}
@keyframes lethal-cross-flash {
  0%,100% { background: rgba(231,76,60,.25); }
  50%     { background: rgba(231,76,60,.6); }
}
/* Мигание кнопки выхода при появлении (открылся выход из слоя). */
#btn-exit-room.exit-appear-blink { animation: exit-appear-blink 1.6s ease 2; }
/* #179: «зов на выход» — слой зачищен, игрок досматривает поле. Пульс раз в 2 с
   и бесконечно: это приглашение, а не уведомление, и смолкнуть оно не должно,
   пока игрок не ушёл. Отдельная анимация, а не exit-appear-blink с другим
   таймингом: у той ровно два цикла, и `infinite` пришлось бы навязывать
   поверх — правило стало бы зависеть от порядка объявления. */
#btn-exit-room.exit-call-blink { animation: exit-call-blink 2s ease-in-out infinite; }
@keyframes exit-call-blink {
  0%, 100% { box-shadow: 0 0 0 0 rgba(78,205,196,0);      background: rgba(78,205,196,.08); }
  50%      { box-shadow: 0 0 16px 5px rgba(78,205,196,.9); background: rgba(78,205,196,.26); }
}
@keyframes exit-appear-blink {
  0%,100% { box-shadow: 0 0 0 0 rgba(78,205,196,0); }
  50%     { box-shadow: 0 0 14px 4px rgba(78,205,196,.95); background: rgba(78,205,196,.22); }
}
/* ─── #347: АВАРИЙНОЕ ОТКЛЮЧЕНИЕ ─────────────────── */
/* Связность кончилась, но игрок ещё на поле: слоты погашены, единственное
   живое место на экране — кнопка подъёма. Зов у неё КРАСНЫЙ, а не бирюзовый:
   бирюзовый зов (.exit-call-blink) означает «слой зачищен, можно уходить», и
   двум противоположным исходам нельзя мигать одним цветом. Правило стоит НИЖЕ
   бирюзового и перебивает его — оба класса на кнопке висят одновременно. */
#btn-exit-room.exit-emergency {
  border-color: rgba(231,76,60,.9);
  color: #ff8b7d;
  animation: exit-emergency-blink 1s ease-in-out infinite;
}
@keyframes exit-emergency-blink {
  0%, 100% { box-shadow: 0 0 0 0 rgba(231,76,60,0);       background: rgba(231,76,60,.10); }
  50%      { box-shadow: 0 0 18px 6px rgba(231,76,60,.95); background: rgba(231,76,60,.34); }
}

/* Погашенные слоты. Не `display: none` и не пустые рамки: игрок должен видеть,
   ЧТО у него было, — просто ничем из этого уже не воспользоваться. Клики сюда
   всё равно не доходят (S.phase !== 'playing' у каждого входа), pointer-events
   стоит ради курсора и ради того, чтобы подсказки при наведении не обещали
   действий, которых больше нет. */
#tool-section.emergency-shutdown .card-slot {
  filter: grayscale(1) brightness(.55);
  pointer-events: none;
  cursor: not-allowed;
}
/* Анимации внутри погашенных слотов останавливаются: мигающая карточка среди
   мёртвых читается как «эта ещё работает». */
#tool-section.emergency-shutdown .card-slot,
#tool-section.emergency-shutdown .card-slot * { animation: none !important; }

/* ─── EPHEMER TRACKER ────────────────────────────── */
/* Список эфемеров тоже прокручивается сам: при ограниченной высоте #info-col он
   не должен выдавливать журнал за нижнюю линию слотов. */
/* #285: панель СКАНЕРА больше не «не отдаёт место» намертво (было flex:0 0 auto).
   При девяти эфемерах она занимала свои 55 % и вместе с панелью ресурсов
   выдавливала журнал за нижнюю границу колонки — журнала не оставалось вовсе.
   Теперь она может ужаться (flex: 0 1 auto), а нижняя граница журнала задана
   явно: min-height у #log-panel — это три-четыре строки, и меньше не станет. */
/* #305: ПОТОЛКА 55 % БОЛЬШЕ НЕТ. Он резал список раньше, чем кончалось место:
   девять эфемеров в плотном виде занимают около 390 px, а 55 % колонки — 445,
   и на обычном виде шесть плашек уже не влезали — часть эфемеров уходила в
   собственную прокрутку при пустом месте под журналом. Порядок обратный:
   сперва список берёт, сколько ему нужно, и только когда журнал упёрся в свой
   min-height, начинает ужиматься сам. Заказчик: «журнал уменьшается по
   размеру — но эфемеры входят все». */
#eph-panel { display: flex; flex-direction: column; min-height: 0; flex: 0 1 auto; }
#eph-list { display: flex; flex-direction: column; gap: 7px; min-height: 0; overflow-y: auto; }
/* ПОЛОСА ПРОКРУТКИ ПОД КАРТОЧКОЙ МАССИВА (#379) — правило на будущее для ВСЕХ
   карточек. `overflow-y: auto` по спецификации делает и `overflow-x` равным
   `auto`: всё, что вылезло за правый край списка, тут же даёт ему нижнюю
   полосу. Вылезала СКРЫТАЯ подсказка углового значка: `.has-tip::after` прячут
   через `visibility: hidden`, то есть в раскладке она стоит, и шириной до
   320 px с `tip-left` (растёт ВПРАВО от левого края значка) уходила за кромку
   карточки на полторы сотни пикселей. Отказ тихий: на экране всё в порядке,
   видно только замером scrollWidth.
   Поэтому угловые значки помечены `tip-right` — подсказка растёт ВЛЕВО,
   внутрь карточки, — а ширина здесь ограничена так, чтобы она помещалась в
   карточку и на узком экране. Заводишь новую подсказку на карточке Массива —
   ставь её тем же приёмом. */
.eph-card .has-tip[data-tip]::after { max-width: 260px; }

/* #285: ПЛОТНЫЙ ВИД — семь и больше эфемеров в слое. Ужимается ровно то, что
   не несёт смысла: высота иконки, отступы плашки и кегль второй строки. Имя,
   счётчики и галочки остаются прежними — их читают, а не «примерно видят».
   Девять плашек в плотном виде занимают около 390 px против 570 в обычном. */
.eph-list-dense { gap: 4px; }
.eph-list-dense .eph-card { padding: 4px 8px; gap: 6px; }
.eph-list-dense .eph-icon { width: 27px; height: 27px; font-size: 18px; }
.eph-list-dense .eph-icon.unknown-icon { font-size: 21px; }
.eph-list-dense .eph-name { font-size: 13.5px; letter-spacing: .5px; }
.eph-list-dense .eph-prog { font-size: 12px; margin-top: 0; }
.eph-list-dense .eph-mem  { font-size: 12px; }
.eph-list-dense .boss-portrait { max-height: 62px; }   /* кадр Массива тоже ниже */

.eph-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 3px;
  border: 1px solid var(--border);
  background: rgba(255,255,255,.02);
  cursor: pointer;
  transition: border-color var(--t-tap);
  user-select: none;
}
.eph-card.unknown { opacity: .6; cursor: default; }
/* #155: вид опознан с первого сегмента (сигнатура расшифрована) — плашка
   мигает три раза, чтобы игрок увидел отдачу от вложенных в дешифровку Данные. */
@keyframes eph-card-flash-kf {
  0%, 100% { background: rgba(255,255,255,.02); border-color: var(--border); }
  50%      { background: rgba(78,205,196,.22);  border-color: var(--teal); box-shadow: 0 0 12px rgba(78,205,196,.45); }
}
.eph-card-flash { animation: eph-card-flash-kf var(--t-in) ease-in-out 3; }
.eph-card.green-eph  { border-color: rgba(46,204,113,.4); }
.eph-card.yellow-eph { border-color: rgba(243,156,18,.4); }
.eph-card.done-eph   { opacity: .7; }
.eph-card:not(.unknown):hover { border-color: var(--teal); }

.eph-icon {
  width: 36px; height: 36px;
  border-radius: 3px;
  display: flex; align-items: center; justify-content: center;
  font-size: 23px;
  flex-shrink: 0;
}
.eph-icon.unknown-icon { background: #0d1b2a; color: var(--dim); font-size: 27px; }
.eph-icon.green-icon  { background: rgba(46,204,113,.2);  color: var(--green); }
.eph-icon.yellow-icon { background: rgba(243,156,18,.2);  color: var(--yellow); }

.eph-info { flex: 1; min-width: 0; }
/* #130: первая строка не переносится и не растит высоту плашки; имя — с многоточием. */
.eph-name-row { display: flex; align-items: center; gap: 5px; flex-wrap: nowrap; overflow: hidden; }
.eph-name  { font-size: 15px; color: var(--text); letter-spacing: 1px; }
.eph-name-row .eph-name { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.eph-name-row .timer-badge,
.eph-name-row .mode-word,
.eph-name-row .mem-activated-check { flex-shrink: 0; }
/* #215: название режима перед его счётчиком, тем же цветом и мигающее в ритме
   секторов рядом с мембраной (2 с — как .cell-membrane-near-easy: непрерывное
   дыхание, а не конечная серия вспышек, ведь режим висит, пока висит).
   Слово не сжимается и не переносится, поэтому в тесноте многоточие съедает имя
   эфемера — оно растяжимо (.eph-name), а название режима важнее: имя игрок и
   так знает по значку и по форме. Мелкий кегль взят, чтобы «ВОЗБУЖДЕНИЕ» —
   самое длинное из трёх — влезало рядом со счётчиком, не роняя строку во вторую.
   Цвета светлее фона плашек-счётчиков: тот же тон, но читаемый как текст. */
.eph-name-row .mode-word {
  font-size: 9px;
  font-weight: bold;
  letter-spacing: .3px;
  white-space: nowrap;
  animation: mode-word-blink 2s ease-in-out infinite;
}
.mode-word.mode-red    { color: #e8695a; }
.mode-word.mode-blue   { color: #5b8df5; }
.mode-word.mode-purple { color: #b97fd6; }
@keyframes mode-word-blink {
  0%, 100% { opacity: .35; }
  50%      { opacity: 1; }
}
.eph-prog  { font-size: 14px; color: var(--dim); margin-top: 2px; }
/* #130: статус мембраны — строго одна строка с многоточием. */
.eph-mem   { font-size: 14px; color: var(--gold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.eph-mem .mem-sym { color: var(--teal); font-weight: bold; margin-right: 2px; }
/* Рисунок мембраны в квадрате слева от карточки эфемера: как только мембрана
   известна, он занимает место цветного знака вида. Цвет наследуется от .eph-icon,
   то есть остаётся цветом эфемера — вид по нему по-прежнему опознаётся. */
.eph-icon .eph-mem-ico { width: 68%; height: 68%; display: block; }
.eph-icon .eph-mem-ico svg { width: 100%; height: 100%; display: block; fill: currentColor; }
/* #130: жёлтая галочка = мембрана активирована (заменяет слово «активирована»). */
.mem-activated-check { color: var(--gold); font-weight: bold; font-size: 14px; margin-left: 3px; }
.timer-badge {
  display: inline-block;
  font-size: 12px;
  font-weight: bold;
  padding: 1px 5px;
  border-radius: 3px;
  color: #fff;
  line-height: 1.4;
}
.red-badge    { background: #c0392b; }
.blue-badge   { background: #2563eb; }
/* Счётчик Искажения фиолетового — тот же значок-таймер, что у Возбуждения и Скольжения. */
.purple-badge { background: #9b59b6; }
.mem-type-badge {
  font-size: 12px;
  color: var(--teal);
  opacity: .75;
  margin-left: 4px;
}

/* ─── LOG ────────────────────────────────────────── */
/* #119: журнал прокручивается — глубокая история действий помещается в панель.
   Десктоп: высоту #info-col ограничивает JS (syncInfoColHeight) по нижней линии
   слотов, поэтому журнал не может уползти ниже центральной колонки и за экран —
   лишние строки уходят в собственную прокрутку #log-entries. */
/* #285: журналу гарантированы три-четыре строки. 132px — это заголовок панели
   (14px + отступы) плюс четыре строки по 21px: считано по тем же числам, что
   стоят у .panel-title и .log-line, а не подобрано.

   БАЗИС НУЛЕВОЙ, А НЕ auto, и это не мелочь. С `flex: 1 1 auto` высота панели
   считается от СОДЕРЖИМОГО: сорок записей журнала — это полторы тысячи
   пикселей, и панель занимала всю колонку, наезжая на СКАНЕР сверху и уходя
   за нижний край. Первая правка добавляла сюда ещё и flex-shrink: 0 — то есть
   прямо запрещала сжимать её обратно. С базисом 0 высота считается от
   ОСТАТКА колонки, лишние записи уходят в прокрутку #log-entries, а min-height
   держит нижнюю границу. */
#log-panel { flex: 1 1 0; min-height: 132px; display: flex; flex-direction: column; }
#log-entries { display: flex; flex-direction: column; gap: 3px; flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* Тон записи несёт ЧЕРТА СЛЕВА, а не значок перед текстом: в стиле «Галерея»
   журнал — столбец строк с цветной кромкой (docs/design/Layer.html). Нижняя
   разлиновка убрана — сорок записей в столбик она превращала в решётку. */
/* Цифра сектора в записи журнала — тем же цветом, что на поле (.num-1…8).
   Жирность своя: в ленте одинаковых по кеглю строк цвет один читается плохо. */
.log-num { font-weight: 700; }
/* Та же цифра, но рядом с ней скрыта мембрана: рамка повторяет метку сектора
   на поле (.cell-mem-mark) — запись и поле обязаны говорить об одном.
   Рамка внутренней тенью и здесь: строки журнала идут вплотную, и настоящий
   border раздвинул бы одну из них на два пикселя. */
.log-num-mem {
  box-shadow: inset 0 0 0 1px rgba(240,208,96,.6);
  padding: 0 4px; border-radius: 2px;
}
/* Ход ЭХОЛУЧОМ — бледная жёлтая подложка (заказчик, 06.09.2026): цвет прибора
   с его карточки. Зонд не помечен ничем, он инструмент по умолчанию.
   Заливка идёт ФОНОМ, а тон записи по-прежнему несёт цветная черта слева:
   два признака не спорят, они про разное — «чем сделано» и «чем кончилось». */
.log-tool-echo { background: rgba(240,208,96,.07); }

.log-line { font-size: 13px; line-height: 1.45; padding: 2px 0 2px 9px; border-left: 2px solid transparent; white-space: pre-wrap; word-break: break-word; overflow-wrap: break-word; }
.log-info    { color: var(--dim-2);  border-left-color: rgba(126,168,190,.35); }
.log-ok      { color: #55d98a;      border-left-color: rgba(46,204,113,.55); }
.log-warn    { color: #f2c46b;      border-left-color: rgba(243,156,18,.55); }
.log-err     { color: #ef7264;      border-left-color: rgba(231,76,60,.55); }
.log-trigger { color: var(--gold); font-weight: bold; }
.log-dim     { color: #2a4a6a; letter-spacing: 4px; text-align: center; }

/* Значок ресурса внутри строки текста (журнал, Профиль, записи Архива).
   Тот же SVG, что в панели ресурсов; цвет — currentColor, размер — в em, чтобы
   значок жил на одной линии с буквами при любом кегле. */
.txt-ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05em; height: 1.05em; line-height: 1; vertical-align: -0.17em;
}
.txt-ic > svg { width: 100%; height: 100%; display: block; }
/* Отзвук — фиолетовый, как его значок в шапке слоя. */
.txt-ic-warp { color: #9b59b6; }
/* Сердце Связности внутри текста — красное, а не цвета подписи. */
.txt-ic-hp { color: var(--red); }

/* ─── ENCYCLOPEDIA POPUP ─────────────────────────── */
#ency-popup {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.7);
  display: flex; align-items: center; justify-content: center;
  z-index: 200;
}
#ency-popup.hidden { display: none; }
#ency-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: 400px;
  box-shadow: 0 0 30px rgba(78,205,196,.2);
}
#ency-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
#ency-title { font-size: 20px; letter-spacing: 2px; color: var(--teal); }
#ency-close { background: none; border: none; color: var(--dim); cursor: pointer; font-size: 21px; padding: 0 4px; }
#ency-close:hover { color: var(--text); }
#ency-body { padding: 18px; font-size: 17px; line-height: 1.8; }
.ency-row { display: flex; justify-content: space-between; padding: 3px 0; border-bottom: 1px solid #0a1520; }
.ency-key { color: var(--dim); }
.ency-val { color: var(--text); }
.ency-empty { color: var(--dim); font-style: italic; margin-top: 8px; }

/* ─── PHASE BAR ──────────────────────────────────── */
#phase-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 8px;
  font-size: 15px;
  letter-spacing: 1px;
}
.phase-step {
  padding: 3px 10px;
  border-radius: 3px;
  border: 1px solid var(--border);
  transition: all var(--t-tap);
  white-space: nowrap;
}
.phase-step.active   { background: rgba(78,205,196,.15); border-color: var(--teal); color: var(--teal); }
.phase-step.done     { background: rgba(78,205,196,.06); border-color: rgba(78,205,196,.3); color: rgba(78,205,196,.5); }
.phase-step.upcoming { color: var(--border); }
.phase-arrow         { color: var(--border); font-size: 14px; }
.loop-bar-label      { color: #9b59b6; font-weight: bold; font-size: 13px; margin-right: 6px; }
.loop-victory-hint   { margin-left: 10px; color: #f0d060; font-size: 11px; font-style: italic; white-space: nowrap; }

/* ─── VICTORY UNLOCKS (экран Победы за Институт) ── */
.victory-unlocks  { margin-top: 14px; padding-top: 10px; border-top: 1px solid #2a2a2a; }
.unlock-title     { color: var(--teal); font-size: 12px; letter-spacing: 1px; margin-bottom: 6px; }
.unlock-done      { color: #4ecdc4; font-size: 13px; margin-bottom: 4px; }
.unlock-todo      { color: #444; font-size: 13px; margin-bottom: 4px; }
.wip              { color: #383838; font-style: italic; }

/* ─── BOSS BAR ───────────────────────────────────── */
#boss-bar {
  display: flex;
  flex-wrap: wrap;           /* ПРАВИЛО: не расширять #center-col — перенос вместо overflow */
  gap: 6px 14px;
  align-items: center;
  justify-content: center;
  background: rgba(231,76,60,.08);
  border: 1px solid rgba(231,76,60,.3);
  border-radius: 3px;
  padding: 6px 12px;
  font-size: 13px;
  letter-spacing: 1px;
  width: 100%;               /* ПРАВИЛО: занимать ширину #center-col, не свою собственную */
  box-sizing: border-box;
  overflow: hidden;
}
#boss-bar.hidden { display: none; }
/* #125 (мобильный): та же боевая инфо Массива, но во вкладке СИГНАТУРЫ. На десктопе
   этот узел не показывается (renderBossBar пишет в оба, видимость решает @media). */
#sp-boss-combat {
  display: flex;
  flex-wrap: wrap;
  gap: 5px 12px;
  align-items: center;
  justify-content: center;
  background: rgba(231,76,60,.08);
  border: 1px solid rgba(231,76,60,.3);
  border-radius: 3px;
  padding: 6px 10px;
  font-size: 13px;
  letter-spacing: 0.5px;
  margin: 4px 0;
  box-sizing: border-box;
}
#sp-boss-combat.hidden { display: none; }

/* #125 (мобильный): панель «ГЛАЗА X/X» на месте кнопки выхода, пока Массив не
   нейтрализован (та же grid-ячейка и высота). На десктопе кнопка выхода
   остаётся как была — панель скрыта. */
#boss-eyes-panel {
  display: none;
  grid-column: 3 / 5;
  justify-self: end;
  align-self: center;
  align-items: center;
  gap: 6px;
  background: rgba(240,208,96,.08);
  border: 1px solid rgba(240,208,96,.45);
  color: #f0d060;
  padding: 4px 12px;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 1px;
  border-radius: 3px;
  white-space: nowrap;
}
#boss-eyes-panel .bep-val { font-weight: bold; font-size: 16px; }

.boss-stat { display: flex; gap: 4px; align-items: center; }
.boss-val  { font-size: 17px; font-weight: bold; color: var(--text); }
.boss-unit { color: var(--dim); font-size: 12px; }
.boss-warp-btn {
  margin-left: auto;
  background: rgba(155,89,182,.2); border: 1px solid rgba(155,89,182,.6);
  color: #c8a0e0; font-family: inherit; font-size: 13px; letter-spacing: 1px;
  padding: 4px 14px; border-radius: 3px; cursor: pointer; transition: all var(--t-tap);
}
.boss-warp-btn:hover { background: rgba(155,89,182,.4); border-color: #9b59b6; color: #e0c0ff; }

/* ─── HOSTILE CELLS ──────────────────────────────── */
@keyframes drone-hint-pulse { 0%,100%{box-shadow:0 0 4px 1px rgba(78,205,196,.3);border-color:rgba(78,205,196,.5)} 50%{box-shadow:0 0 10px 3px rgba(78,205,196,.8);border-color:#4ecdc4} }
.cell-drone-hint {
  border-color: rgba(78,205,196,.5) !important;
  background: rgba(78,205,196,.07) !important;
  animation: drone-hint-pulse 1.2s ease-in-out infinite;
}
/* #192: сектор, подсвеченная Ищейкой или мембраной «Слепок», отличалась от
   пустой только рамкой и пульсацией — на глаз читалась как «тут ничего нет».
   Ставим в центр точку размером с ● вскрытого сегмента, но приглушённую:
   подсветка обещает сегмент, а не показывает его. Точка не пульсирует вместе
   с рамкой — мигающая точка спорила бы с иконкой Эхолуча у раскрытых секторов. */
.cell-drone-hint::after {
  content: '';
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 17%; height: 17%;
  border-radius: 50%;
  background: rgba(78,205,196,.45);
  pointer-events: none;
}
/* H-04 Сторож: 800мс «подсмотр» цвета сегмента до перехода в droneHint-метку */
@keyframes threat-peek-flash { 0%{transform:scale(.85);opacity:0} 30%{transform:scale(1.05);opacity:1} 100%{transform:scale(1);opacity:1} }
.cell-threat-peek {
  animation: threat-peek-flash var(--t-in) ease-out forwards;
  box-shadow: 0 0 12px 2px rgba(255,255,255,.35) !important;
}
.cell-threat-peek.peek-green   { background: rgba(46,204,113,.45) !important; border-color: rgba(46,204,113,.85) !important; }
.cell-threat-peek.peek-yellow  { background: rgba(243,156,18,.45) !important; border-color: rgba(243,156,18,.85) !important; }
.cell-threat-peek.peek-red     { background: rgba(231,76,60,.45)  !important; border-color: rgba(231,76,60,.85)  !important; }
.cell-threat-peek.peek-blue    { background: rgba(59,130,246,.45) !important; border-color: rgba(59,130,246,.85) !important; }
.cell-threat-peek.peek-purple  { background: rgba(155,89,182,.45) !important; border-color: rgba(155,89,182,.85) !important; }
.cell-threat-peek.peek-boss    { background: rgba(155,89,182,.45) !important; border-color: rgba(155,89,182,.85) !important; }
@keyframes neural-hint-pulse { 0%,100%{box-shadow:0 0 0 0 rgba(86,174,200,0)} 50%{box-shadow:0 0 8px 2px rgba(86,174,200,.55)} }
.cell-neural-hint {
  border-color: rgba(86,174,200,.75) !important;
  background: rgba(86,174,200,.12) !important;
  color: #56aec8 !important;
  font-weight: bold;
  animation: neural-hint-pulse 1.4s ease-in-out infinite;
}
@keyframes neighbor-warn { 0%,100%{border-color:var(--surface-line)} 50%{border-color:rgba(231,76,60,.45)} }
/* #348: ЧЕРЕП НА ВСЕХ ДЕВЯТИ СЕКТОРАХ КВАДРАТА, и с 04.09.2026 они НЕОТЛИЧИМЫ
   ДРУГ ОТ ДРУГА (заказчик: «убери у заражения особое выделение центральной
   клетки, пусть все они выглядят одинаково как боковые»).

   Раньше центр был залит ярче и пульсировал свечением: по нему было видно,
   ОТКУДА растёт квадрат, — то есть куда бить Эхолучом. Заказчик эту улику
   снял сознательно: опасность у всех девяти одна и та же (Зонд по зоне помех
   убивает ровно так же, как по чёрному сектору), значит и вид один.

   ОБА КЛАССА ОСТАВЛЕНЫ, хотя рисуют одно. Они разошлись бы обратно при первой
   же правке одного из них, поэтому правила стоят ОДНИМ селектором: разный вид
   тут возможен только нарочно, а не по забывчивости. Сами классы нужны коду —
   центр ставится по `c.isHostile`, зона считается `nearHostile()`.

   Курсор ОБЫЧНЫЙ (заказчик, 03.09.2026). Перечёркнутый круг говорил «сюда
   нельзя», а сюда МОЖНО — и Зондом тоже: это стоит заряда, а на пустом контуре
   Связности, но действие законное и иногда нужное. */
.cell-hostile,
.cell-hostile-neighbor {
  background: rgba(231,76,60,.05) !important;
  border-color: rgba(231,76,60,.3) !important;
  color: rgba(231,76,60,.62) !important;
  animation: neighbor-warn 1.2s ease-in-out infinite;
}
/* Череп рисованный (ICONS.skull), и размер ему задаёт не кегль строки, а доля
   сектора: на мобильном клетка 28 px, и 20 px эмодзи вылезали за неё. */
.cell-hostile .gi,
.cell-hostile-neighbor .gi { height: 62%; opacity: .62; }
/* ─── EMPTY CELL LIGHTNING ANIMATION ─────────────── */
@keyframes lightning-reveal {
  0%   { background: #aaffee; box-shadow: 0 0 18px #4ecdc4; }
  35%  { background: #4ecdc4; box-shadow: 0 0 10px #4ecdc4; }
  70%  { background: #081820; box-shadow: 0 0 3px rgba(78,205,196,.2); }
  100% { background: #040a12; box-shadow: none; }
}
.cell-empty-anim {
  animation: lightning-reveal var(--t-in) ease-out forwards !important;
}

/* ─── BOSS EYE CELLS ─────────────────────────────── */
.cell-eye { color: var(--gold) !important; text-shadow: 0 0 12px rgba(240,208,96,1); }
.open-boss  { background: rgba(155,89,182,.15); border: 1px solid rgba(155,89,182,.4); color: rgba(155,89,182,.5); }
.scanned-boss { background: rgba(155,89,182,.25); border: 1px solid rgba(155,89,182,.6); color: var(--purple); box-shadow: 0 0 10px rgba(155,89,182,.4); }

/* ─── BOSS EPHEMER CARD ───────────────────────────── */
.eph-card.boss-eph {
  border-color: rgba(231,76,60,.5);
  background: rgba(231,76,60,.05);
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding: 10px;
  min-height: 220px;
}
.eph-icon.boss-icon { background: rgba(231,76,60,.2); color: var(--red); font-size: 27px; }
/* #269-испр.: синий Массив и выглядит синим — рамка карточки, кадр и значок.
   Он ведёт себя как Скользящий, и красная оправа обычного Массива сбивала: на
   поле сегменты синие, а карточка кричала «тревога». */
.eph-card.boss-eph.boss-eph-blue { border-color: rgba(59,130,246,.55); background: rgba(59,130,246,.06); }
.boss-eph-blue .eph-icon.boss-icon { background: rgba(59,130,246,.2); color: #3b82f6; }
.boss-eph .boss-portrait {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid rgba(231,76,60,.35);
  background: #0d1b2a;
  display: block;
}
/* Кадр синего Массива выше обычного на 60 % (16/9 → 16/14.4): в широкой рамке
   от него был виден только верх. Правило стоит ПОСЛЕ .boss-eph .boss-portrait:
   специфичность у них одинаковая, и решает порядок. */
.boss-eph img.boss-portrait-blue {
  border-color: rgba(59,130,246,.45);
  aspect-ratio: 16 / 14.4;
  object-position: center 40%;
}
.boss-eph .boss-fallback-icon {
  display: none;
  width: 100%;
  aspect-ratio: 16 / 9;
  align-items: center;
  justify-content: center;
  font-size: 56px;
  color: var(--red);
  background: rgba(231,76,60,.12);
  border: 1px dashed rgba(231,76,60,.35);
  border-radius: 3px;
}
/* Пятно помех показывается ВСЕГДА, когда Массив закрыт: кадра в разметке нет
   вовсе (см. renderEphTracker), поэтому правило «портрет не загрузился» сюда не
   доедет. Красную рамку заглушки снимаем — это не отказ загрузки, а сорванный
   сигнал. */
.boss-eph .boss-fallback-icon.boss-noise {
  display: flex;
  color: transparent;
  border: 1px dashed rgba(126,168,190,.28);
}
/* If portrait fails to load (display:none via onerror), show the fallback */
.boss-eph .boss-portrait[style*="display: none"] + .boss-fallback-icon { display: flex; }
.boss-eph .eph-info { flex: 1 1 auto; }
.boss-eph .eph-name { font-size: 14px; line-height: 1.25; letter-spacing: 1px; }
.shield-badge { font-size: 21px; margin-left: 4px; }

/* ─── OVERLAY ────────────────────────────────────── */
#overlay { position: fixed; inset: 0; background: rgba(3,7,16,.88); display: flex; align-items: center; justify-content: center; z-index: 100; }
#overlay.hidden { display: none; }
/* max-width обязателен: причина срыва — одна длинная фраза в #overlay-sub, она
   не переносилась и растягивала окно на весь экран (1275px против 667px у «Слой
   очищен»). С потолком все итоговые окна держатся в одном габарите. */
#overlay-box { background: var(--panel); border: 1px solid var(--teal); border-radius: 3px; padding: 44px 52px; text-align: center; box-shadow: 0 0 50px rgba(78,205,196,.25); min-width: 400px; max-width: 700px; }
/* #145: узкий вариант для туториального итога — там нет таблицы рапорта,
   только одна фраза, и без потолка окно растягивалось на весь экран. */
#overlay-box.overlay-narrow { max-width: 520px; }
#overlay-title { font-size: 36px; letter-spacing: 3px; margin-bottom: 14px; }
#overlay-sub   { color: var(--dim); font-size: 18px; margin-bottom: 12px; }
#overlay-stats { color: var(--teal); font-size: 17px; margin-bottom: 24px; text-align: left; }
.report-section { color: var(--border); font-size: 14px; letter-spacing: 1px; padding: 4px 0 2px; border-top: 1px solid #0d1e2e; margin-top: 4px; }
.report-gap     { height: 6px; }
.report-row     { display: flex; justify-content: space-between; gap: 20px; padding: 2px 0; }
.report-key     { color: var(--dim); }
.report-val     { color: var(--text); font-weight: bold; }
#btn-overlay-action { background: var(--teal); color: var(--bg); border: none; padding: 14px 40px; font-family: var(--font-mono); font-size: 18px; letter-spacing: 2px; border-radius: 3px; cursor: pointer; font-weight: bold; transition: opacity var(--t-tap); }
#btn-overlay-action:hover { opacity: .85; }

/* ─── SHOP OVERLAY ───────────────────────────────── */
#shop-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.94);
  display: flex; align-items: center; justify-content: center;
  z-index: 150;
  overflow-y: auto;
  padding: 20px;
}
#shop-overlay.hidden { display: none; }
#shop-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: var(--station-w, 1060px); max-width: 100%;
  padding: 28px 32px;
  box-shadow: 0 0 60px rgba(78,205,196,.2);
}
#shop-header { text-align: center; margin-bottom: 16px; }
#shop-title  { font-size: 30px; letter-spacing: 4px; color: var(--teal); }
#shop-subtitle { font-size: 17px; color: var(--dim); margin-top: 4px; letter-spacing: 1px; }
/* Подзаголовок появляется только перед Массивом — пустой не занимает место. */
#shop-subtitle:empty { display: none; }

/* На десктопе обёртки .sres-row «исчезают» — все .sres остаются прямыми flex-детьми
   #shop-res, как было до разбиения на ряды. На мобильном переопределяется в @media. */
.sres-row { display: contents; }

#shop-res {
  display: flex; gap: 14px; flex-wrap: wrap; justify-content: center;
  margin-bottom: 12px;
  background: rgba(78,205,196,.05);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 10px 18px;
  font-size: 18px;
}
.sres { display: flex; gap: 5px; align-items: center; }
/* КРЕДИТЫ — ПОСЛЕДНИЕ И У ПРАВОГО КРАЯ (заказчик, 07.09.2026). Распорка перед
   ними отжимает их вправо, а сама плашка выравнивается по правому краю: все
   прочие ресурсы прижаты влево, и разное выравнивание — это и есть признак,
   что кредиты стоят особняком, а не продолжают ряд добычи.
   Отдельная распорка, а не margin-left:auto у самой плашки: на мобильном ряд
   переносится в две строки, и авто-отступ растащил бы их по разным краям. */
.sres-grow { flex: 1 1 auto; min-width: 4px; }
.sres-money { justify-content: flex-end; text-align: right; }
.pchip-grow { flex: 1 1 auto; min-width: 4px; }
.sres.teal   { color: var(--teal); }
.sres.green  { color: var(--green); }
.sres.yellow { color: var(--yellow); }
.sres.gold   { color: var(--gold); }
.sres.red    { color: var(--red); }

.shop-msg { text-align: center; font-size: 17px; min-height: 22px; margin-bottom: 12px; letter-spacing: .5px; }
.shop-msg.ok  { color: var(--green); }
.shop-msg.err { color: var(--red); }

#shop-panels {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 20px;
}
.org-panel {
  background: rgba(255,255,255,.02);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 16px;
  position: relative;
}
[data-equipment-art="on"] .org-panel { isolation: isolate; }
#org-hospital  { border-color: rgba(46,204,113,.3); }
#org-institute { border-color: rgba(78,205,196,.3); }
#org-market    { border-color: rgba(243,156,18,.3); }

.org-title { font-size: 18px; letter-spacing: 2px; margin-bottom: 4px; }
#org-hospital  .org-title { color: var(--green); }
#org-institute .org-title { color: var(--teal); }
#org-market    .org-title { color: var(--yellow); }

/* Org emblem (AI-generated coat-of-arms). Toggle via [data-equipment-art="on"].
   Sits as a decorative background in the panel's top-right corner, overflowing
   the top border by ~14% of its size. Tabs (incl. "Возврат") sit above the
   emblem via z-index:1. The mask fades the top-right corner into the page. */
.org-emblem {
  display: none;
  position: absolute;
  top: -32px;
  right: -6px;
  width: 122px;
  height: 122px;
  border-radius: 50%;
  /* Кликабельна ради чита тест-режима (10 нажатий по эмблеме ЧР). Контент панели
     лежит выше (z-index:1), поэтому обычные клики по кнопкам эмблема не перехватывает. */
  pointer-events: auto;
  z-index: 0;
  opacity: .85;
  -webkit-mask-image: linear-gradient(45deg, rgba(0,0,0,1) 45%, rgba(0,0,0,.15) 100%);
          mask-image: linear-gradient(45deg, rgba(0,0,0,1) 45%, rgba(0,0,0,.15) 100%);
}
[data-equipment-art="on"] .org-emblem { display: block; }
[data-equipment-art="on"] .org-emoji { display: none; }
[data-equipment-art="on"] .org-panel > .org-desc,
[data-equipment-art="on"] .org-panel > .shop-items { position: relative; z-index: 1; }
/* Tabs (incl. "Возврат") need an opaque backdrop so the emblem behind doesn't bleed through. */
[data-equipment-art="on"] .org-tab { background: rgba(9,20,33,.92); }
[data-equipment-art="on"] .org-tab.tab-locked {
  opacity: .55;
  background: rgba(9,20,33,.6);
  color: rgba(155,177,196,.6);
  border-color: rgba(26,58,92,.55);
}

.org-desc  { font-size: 14px; color: var(--dim); margin-bottom: 14px; letter-spacing: 1px; }
.shop-items { display: flex; flex-direction: column; gap: 10px; }

/* ─── ORG TABS ───────────────────────────────────── */
.org-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.org-tab {
  background: transparent; border: 1px solid var(--border);
  color: var(--dim); font-family: inherit; font-size: 11px;
  padding: 4px 10px; border-radius: 3px; cursor: pointer;
  letter-spacing: .5px; transition: all var(--t-tap);
}
.org-tab:hover { border-color: var(--teal); color: var(--teal); }
.org-tab.active { border-color: var(--teal); color: var(--teal); background: rgba(78,205,196,.08); }
.org-tab.tab-locked { opacity: .3; cursor: not-allowed; }
.org-tab.tab-locked:hover { border-color: var(--border); color: var(--dim); background: transparent; }
/* #80: мигание кнопки «Эксклюзивы» при первом доступе к ним */
@keyframes tab-blink-kf {
  0%, 100% { box-shadow: 0 0 0 0 rgba(78,205,196,0); }
  50%      { box-shadow: 0 0 12px 2px rgba(78,205,196,.9); background: rgba(78,205,196,.22); }
}
.org-tab.tab-blink { animation: tab-blink-kf var(--t-in) ease-in-out 3; }

/* МИГАНИЕ ЭЛЕМЕНТА, НА КОТОРЫЙ УКАЗАЛО СООБЩЕНИЕ (#382, #386). Тот же приём,
   что у вкладки выше, но цвет золотой: им помечено то, что игрок ПОЛУЧИЛ, —
   запись в Архиве, награда в слоте. Мигает свечение и рамка, а не размер:
   ряд слотов от скачущего габарита дёргался бы целиком. */
@keyframes ui-blink-kf {
  0%, 100% { box-shadow: 0 0 0 0 rgba(240,208,96,0); }
  50%      { box-shadow: 0 0 14px 3px rgba(240,208,96,.85); border-color: var(--gold); }
}
.ui-blink { animation: ui-blink-kf .53s ease-in-out 3; }
@media (prefers-reduced-motion: reduce) {
  .ui-blink { animation: none; }
}

/* ─── FULL SLOTS MODAL ───────────────────────────────────────── */
/* z-index 9600 — вровень с generic-confirm и ВЫШЕ Профиля (9250).
   Было 2100: предупреждение открывалось под окном Профиля, и игрок видел его
   только после выхода оттуда — то есть в момент, когда оно уже ни к чему.
   Модалка вызывается из Профиля (попытка забрать премию в занятые слоты) и из
   Организаций, поэтому обязана перекрывать оба. */
#full-slots-modal {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.72); z-index: 9600;
}
#full-slots-modal.hidden { display: none; }
#fsm-box {
  background: var(--panel); border: 1px solid rgba(231,76,60,.5);
  border-radius: 3px; max-width: 380px; width: 90%; padding: 0;
  overflow: hidden; box-shadow: 0 0 30px rgba(231,76,60,.2);
}
#fsm-header {
  padding: 12px 16px; background: rgba(231,76,60,.1);
  border-bottom: 1px solid rgba(231,76,60,.3);
  font-size: 14px; font-weight: bold; color: #ffaaaa; letter-spacing: 1px;
}
#fsm-body {
  padding: 16px; font-size: 13px; color: var(--text); line-height: 1.65;
}
#fsm-body strong { color: var(--teal); }
#fsm-close {
  display: block; width: calc(100% - 32px); margin: 0 16px 16px;
  padding: 9px; background: rgba(78,205,196,.12);
  border: 1px solid rgba(78,205,196,.4); color: var(--teal);
  border-radius: 3px; cursor: pointer; font-family: inherit;
  font-size: 13px; letter-spacing: 1px;
}
#fsm-close:hover { background: rgba(78,205,196,.22); }

/* ─── EQUIP ITEMS IN SHOP ────────────────────────── */
.equip-item {
  background: rgba(155,89,182,.05); border: 1px solid rgba(155,89,182,.25);
  border-radius: 3px; padding: 8px 10px;
}
/* Правило «погасить строку до 40 %» здесь было, но класс `equip-locked` витрина
   никому не выдавала — оно лежало мёртвым со времён прежней раскладки. С #377
   класс ожил (им помечена строка с неоплаченным доступом), и прозрачность
   съела бы ровно то, ради чего строка показана: игрок должен ПРОЧИТАТЬ, что
   он получит за жемчуг. Отличие теперь цветом рамки и подложки, см. ниже. */
/* Эксклюзив — ТА ЖЕ СТРОКА, что стандартный товар (09.09.2026). Своей
   раскладки у него больше нет: класс .shop-item задаёт сетку «знак — название —
   цена — кнопка», здесь остаётся только фиолетовый оттенок, которым эксклюзивы
   отличаются от стандарта, когда обе категории показаны разом.
   ЗДЕСЬ БЫЛА своя сетка в две колонки с кнопкой «Подробнее» внизу — из-за неё
   описание уезжало в модальное окно, а строка была втрое выше соседних. */
.equip-item .equip-lines { min-width: 0; }
.equip-item .item-name { color: #d9bdea; }
.equip-item .equip-type {
  margin-left: 8px; font-size: 10px; color: var(--dim);
  text-transform: uppercase; letter-spacing: .5px; white-space: nowrap;
}
.equip-item .equip-desc { margin-top: 3px; font-size: 12px; line-height: 1.45; color: var(--dim); }
.equip-item .equip-art { display: block; background: #0a1428; }

/* Картинка товара показывается всегда: флаг data-equipment-art висит на <html>
   намертво. ЗДЕСЬ БЫЛА своя раскладка для строк с картинкой — четыре области в
   две колонки, и кнопка в них уезжала В НИЖНИЙ ЛЕВЫЙ УГОЛ: «Резонансный щит» и
   «Накопитель» выглядели иначе всех соседей, а строка становилась втрое выше.
   Заказчик про это и написал: «почему купить внизу слева? купить у нас всегда
   справа, и строчки должны быть одинаковой высоты». Раскладка снята — строки
   с картинкой идут той же сеткой «Галереи», что и все прочие. */
.shop-item-art { display: none; }
[data-equipment-art="on"] .shop-item .shop-item-art { display: block; }
.equip-unlock-hint { font-size: 10px; color: var(--yellow); opacity: .7; margin-top: 2px; }
.btn-equip-buy {
  margin-top: 6px; background: rgba(155,89,182,.2); border: 1px solid rgba(155,89,182,.5);
  color: #c8a0e0; font-family: inherit; font-size: 11px;
  padding: 3px 10px; border-radius: 3px; cursor: pointer;
}
.btn-equip-buy:hover:not(:disabled) { background: rgba(155,89,182,.4); }
.btn-equip-buy:disabled { opacity: .35; cursor: default; }

/* Стили вкладки «Возврат» удалены вместе с самой вкладкой (#160): продажа
   оборудования живёт в окне «ПРОФИЛЬ», см. .pcard-slot-sellable. */

/* КНОПКА ДОСТУПА (#377). Прежняя кнопка «Открыть новое оборудование» стояла
   одна под списком и раскрывала случайный предмет; теперь доступ покупается у
   КОНКРЕТНОЙ строки, поэтому кнопка встала на место «Купить» и держит её
   геометрию. Цвет остался красный — платят жемчугом, а не кредитами, и строка
   должна отличаться от покупки одним взглядом. */
.btn-equip-access {
  background: rgba(231,76,60,.14); border-color: rgba(231,76,60,.55); color: #e7a0a0;
}
.btn-equip-access:hover:not(:disabled) { background: rgba(231,76,60,.28); border-color: #e74c3c; color: #ffb0b0; }
/* Строка с неоплаченным доступом читается как «пока не ваше»: предмет виден
   целиком — заказчик хочет, чтобы игрок знал, за что платит, — но подложка
   глуше, а цена стоит в жемчуге. */
.shop-item.equip-locked { border-color: rgba(231,76,60,.3); background: rgba(231,76,60,.04); }
.item-cost-pearl { color: #e7a0a0; white-space: nowrap; }

.shop-item {
  background: rgba(255,255,255,.02);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 5px;
}
/* padding-right — под бейдж в правом верхнем углу (♥/⚡/💰): без него длинные
   названия Госпиталя заезжали под иконку. Названия и размер шрифта не трогаем. */
/* padding-right — под бейдж в правом верхнем углу (♥/⚡/💰): без него длинные
   названия Госпиталя заезжали под иконку. Шрифт 17→15px, чтобы самые длинные
   («Стабилизация Стабилатом +1 Связности») по-прежнему влезали в ОДНУ строку. */
.item-name { font-size: 15px; color: var(--text); padding-right: 28px; }
.item-win-hint { font-size: 13px; font-weight: bold; color: #f0c030; letter-spacing: .5px; }
.item-cost { font-size: 15px; color: #7ab8d8; }

/* ─── SHOP ITEM BADGE ────────────────────────────── */
.shop-item { position: relative; }
.item-badge {
  position: absolute;
  top: 7px; right: 9px;
  /* 18→24px: сердечки/молнии в углу карточек были слишком мелкими */
  font-size: 24px;
  opacity: .9;
  pointer-events: none;
  line-height: 1;
}
/* #19: число выручки рядом с мешочком */
.item-badge.sell-payout {
  font-size: 14px;
  font-weight: bold;
  color: var(--gold);
  opacity: 1;
  white-space: nowrap;
}
/* #4: универсальное подтверждение */
#generic-confirm-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.78);
  display: flex; align-items: center; justify-content: center;
  z-index: 9600;
  font-family: var(--font-mono);
}
#generic-confirm-overlay.hidden { display: none; }

/* ─── ОКНО ПРЕМИИ (задание №25) ─────────────────────────────────────
   Поверх окна прохождения слоя (#overlay, 100) и карточки эхонавта (9250), но
   под окном-вопросом (9600). Золотая рамка — цвет кредитов и наград в игре. */
#premium-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.78);
  display: flex; align-items: center; justify-content: center;
  z-index: 9550;
  font-family: var(--font-mono);
}
#premium-overlay.hidden { display: none; }
#premium-box {
  width: clamp(280px, 90vmin, 520px);
  background: #061726;
  border: 2px solid rgba(240,208,96,.55);
  border-radius: 3px;
  padding: 22px 24px;
  text-align: center;
  box-shadow: 0 0 36px rgba(240,208,96,.16);
  display: flex; flex-direction: column; gap: 16px;
}
#premium-label {
  font-family: var(--font-head); font-size: 20px; letter-spacing: 3px;
  color: var(--gold);
}
#premium-text { color: var(--text); font-size: 16px; line-height: 1.5; }
#premium-row { display: flex; justify-content: center; flex-wrap: wrap; gap: 10px; }
#premium-foot { color: var(--dim); font-size: 13px; letter-spacing: .5px; }
/* Стили кнопки «Принято» убраны вместе с самой кнопкой (#385). */
/* Плитки — те же, что в «Премировании» карточки, только без действия. Слева
   направо по одной: появляются, дважды вспыхивают и замирают. Задержку каждой
   даёт её номер (--i). */
/* 104 px — замер: при 96 «НАКОПИТЕЛЬ» ломался на мягком знаке, при 110 четыре
   плитки (больше слотов наград не бывает) уже не встают в один ряд. */
.prem-tile {
  width: 104px;
  opacity: 0;
  animation: prem-in .45s ease forwards, prem-blink .5s ease 2;
  animation-delay: calc(var(--i) * .7s + .3s), calc(var(--i) * .7s + .75s);
}
.prem-tile .card-slot { height: 104px; cursor: default; }
@keyframes prem-in {
  from { opacity: 0; transform: translateY(8px) scale(.9); }
  to   { opacity: 1; transform: none; }
}
@keyframes prem-blink {
  0%, 100% { filter: none; }
  50%      { filter: brightness(1.9) drop-shadow(0 0 10px rgba(240,208,96,.8)); }
}
@media (prefers-reduced-motion: reduce) {
  .prem-tile { animation: none; opacity: 1; }
}
#generic-confirm-box {
  width: clamp(260px, 80vmin, 400px);
  background: #061726;
  border: 2px solid rgba(78,205,196,.5);
  border-radius: 3px;
  padding: 24px 26px;
  text-align: center;
  box-shadow: 0 0 36px rgba(78,205,196,.2);
}
/* pre-line: сообщения из нескольких абзацев (протокол идентификации в Атласе)
   разделяются \n прямо в тексте — иначе всё склеивается в один ком. */
#generic-confirm-text { color: var(--text); font-size: 17px; line-height: 1.5; margin-bottom: 20px; white-space: pre-line; }
/* #225: послания Ордена — синим. Тот же ярко-синий, что и на табло Ордена:
   у фракции один цвет во всём интерфейсе. */
#generic-confirm-text.gc-orden {
  color: #4fb0ff;
  text-shadow: 0 0 10px rgba(79,176,255,.25);
}
/* #280: тревожный тон — «ошибка идентификации, связь потеряна». Красный против
   голубого Ордена: игрок обязан различить их с одного взгляда. */
#generic-confirm-text.gc-alert {
  color: #e74c3c;
  text-shadow: 0 0 12px rgba(231,76,60,.45);
}
/* «Не показывать этот отчёт» — та же галочка, что у подсказок (#hint-no-more),
   но в универсальном окне. Метка кликабельна целиком: в 16px квадратик пальцем
   на телефоне не попасть. */
#generic-confirm-nomore {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: -8px 0 16px;
  font-size: 13px; color: var(--dim); letter-spacing: .5px;
  cursor: pointer; user-select: none;
}
#generic-confirm-nomore.hidden { display: none; }
#generic-confirm-nomore input[type=checkbox] {
  width: 16px; height: 16px; accent-color: var(--teal); cursor: pointer; flex: 0 0 auto;
}
#generic-confirm-btns { display: flex; gap: 14px; justify-content: center; }
#generic-confirm-btns button {
  font-family: var(--font-mono);
  font-size: 16px; font-weight: bold;
  padding: 10px 30px; border-radius: 3px; cursor: pointer;
  border: 2px solid rgba(78,205,196,.55);
  background: rgba(78,205,196,.1); color: var(--teal);
}
#btn-generic-yes { border-color: rgba(231,76,60,.6); color: #ff8a7a; background: rgba(231,76,60,.12); }

/* ─── EPHEMER EFFECT LINE ────────────────────────── */
.eph-effect {
  font-size: 13px;
  margin-top: 3px;
  opacity: .85;
  font-style: italic;
}
.btn-shop {
  background: none;
  border: 1px solid var(--border);
  color: var(--text);
  padding: 5px 12px;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 1px;
  border-radius: 3px;
  cursor: pointer;
  transition: all var(--t-tap);
  align-self: flex-start;
  margin-top: 2px;
}
.btn-shop:hover { border-color: var(--teal); color: var(--teal); background: rgba(78,205,196,.08); }
/* #61: кнопка продажи во всю ширину, выручка (💰 N) внутри неё — не накрывает название */
.btn-sell { align-self: stretch; width: 100%; text-align: center; }
.btn-sell .sell-payout { color: var(--gold); font-weight: bold; margin-left: 4px; white-space: nowrap; }

/* #140: предупреждение возврата в Эфир — центрированный модал (стандартное окно), НЕ плашка снизу.
   Карточный фон/рамку даёт .hint-box.hint-normal; здесь — оверлей-подложка, размеры и кнопки. */
#shop-confirm {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(4,10,18,.72);
  z-index: 9000;
  padding: 16px;
}
.shop-confirm-box {
  width: 520px;
  max-width: 95vw;
  text-align: center;
}
.shop-confirm-label {
  font-size: 20px; font-weight: bold; letter-spacing: 2px;
  text-transform: uppercase; color: #e74c3c;
}
#shop-confirm-text {
  font-size: 22px;
  color: var(--text);
  line-height: 1.6;
}
.confirm-warn {
  display: block;
  margin-top: 12px;
  color: #e74c3c;
  font-size: 22px;
  letter-spacing: .5px;
}
#shop-confirm-btns { display: flex; gap: 10px; justify-content: center; }
#btn-confirm-yes {
  background: rgba(231,76,60,.2); border: 1px solid rgba(231,76,60,.6);
  color: #ffaaaa; font-family: inherit; font-size: 22px; letter-spacing: 1px;
  padding: 11px 34px; border-radius: 3px; cursor: pointer;
}
#btn-confirm-yes:hover { background: rgba(231,76,60,.4); }
#btn-confirm-no {
  background: rgba(78,205,196,.1); border: 1px solid rgba(78,205,196,.4);
  color: var(--teal); font-family: inherit; font-size: 22px; letter-spacing: 1px;
  padding: 11px 34px; border-radius: 3px; cursor: pointer;
}
#btn-confirm-no:hover { background: rgba(78,205,196,.2); }

/* ─── EQUIP BUY CONFIRM MODAL ────────────────────────────────── */
#equip-buy-modal {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0,0,0,.72);
  /* 9600 — вровень с generic-confirm и выше Профиля (9250): это же окно
     показывает карточку ПРЕМИИ, которую открывают из Профиля. На прежних 2000
     оно пряталось под ним, как и предупреждение о слотах. */
  z-index: 9600;
}
#equip-buy-modal.hidden { display: none; }
#ebm-box {
  background: var(--panel);
  border: 1px solid rgba(78,205,196,.5);
  border-radius: 3px;
  max-width: 460px;
  width: 90%;
  overflow: hidden;
  box-shadow: 0 0 40px rgba(78,205,196,.18), 0 8px 32px rgba(0,0,0,.5);
}
#ebm-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 14px 8px;
  background: rgba(78,205,196,.07);
  border-bottom: 1px solid rgba(78,205,196,.2);
}
#ebm-type-badge {
  font-size: 11px;
  font-weight: bold;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: #4ecdc4;
}
#ebm-close {
  background: none; border: none; color: var(--dim);
  cursor: pointer; font-size: 15px; line-height: 1; padding: 2px 4px;
}
#ebm-close:hover { color: var(--text); }
#ebm-name-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 14px 16px 6px;
  gap: 10px;
}
#ebm-name {
  font-size: 17px;
  font-weight: bold;
  color: var(--text);
  letter-spacing: 0.8px;
}
#ebm-price-badge {
  font-size: 13px;
  color: #f0d060;
  background: rgba(240,208,96,.1);
  border: 1px solid rgba(240,208,96,.3);
  border-radius: 3px;
  padding: 2px 10px;
  white-space: nowrap;
}
#ebm-desc {
  padding: 4px 16px 20px;
  font-size: 14px;
  color: var(--text);
  line-height: 1.75;
}
#ebm-note {
  margin: 0 16px 10px;
  padding: 7px 10px;
  font-size: 12px;
  color: #ffaaaa;
  background: rgba(231,76,60,.1);
  border: 1px solid rgba(231,76,60,.3);
  border-radius: 3px;
  line-height: 1.5;
}
#ebm-footer {
  display: flex;
  gap: 10px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  background: rgba(0,0,0,.18);
}
#ebm-cancel {
  flex: 1;
  padding: 9px;
  background: none;
  border: 1px solid var(--border);
  color: var(--dim);
  border-radius: 3px;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  letter-spacing: 0.8px;
}
#ebm-cancel:hover { border-color: var(--dim); color: var(--text); }
#ebm-confirm {
  flex: 1.5;
  padding: 9px;
  background: rgba(78,205,196,.12);
  border: 1px solid rgba(78,205,196,.5);
  color: var(--teal);
  border-radius: 3px;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  letter-spacing: 0.8px;
  font-weight: bold;
}
#ebm-confirm:hover { background: rgba(78,205,196,.22); border-color: var(--teal); }

#btn-shop-continue {
  display: block;
  width: 100%;
  background: var(--teal);
  color: var(--bg);
  border: none;
  padding: 15px;
  font-family: var(--font-mono);
  font-size: 20px;
  letter-spacing: 3px;
  border-radius: 3px;
  cursor: pointer;
  font-weight: bold;
  transition: opacity var(--t-tap);
}
#btn-shop-continue:hover { opacity: .85; }

/* #162: подвал Организаций — Атлас / Профиль / следующий слой в одном ряду.
   Главная кнопка (переход дальше) шире боковых и сохраняет прежний вид:
   ширину ей задаёт flex, а не width:100%, поэтому правило выше не трогаем. */
/* Три равные колонки: «Атлас», «Профиль» и переход в слой одной ширины —
   grid держит её независимо от длины подписи (у слоя она ещё и меняется). */
#shop-footer { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; align-items: stretch; }
#shop-footer #btn-shop-continue { width: auto; }
.shop-footer-side {
  background: rgba(78,205,196,.08);
  color: var(--teal);
  border: 1px solid var(--teal);
  padding: 15px 20px;
  font-family: var(--font-mono);
  font-size: 17px;
  letter-spacing: 2px;
  border-radius: 3px;
  cursor: pointer;
  font-weight: bold;
  transition: background var(--t-tap);
}
.shop-footer-side:hover { background: rgba(78,205,196,.2); }
/* #253 и #255: отметка в правом верхнем углу боковых кнопок подвала.
   ★ на «Профиле» — в слотах премирования появилось новое; число на «Атласе» —
   сколько эфемеров открыто, но не расшифровано.
   Содержимое берётся из data-badge псевдоэлементом, а не отдельным узлом:
   подписи кнопок проставляет i18n через innerHTML (data-txt), и живой ребёнок
   был бы стёрт при первой же простановке текста.
   Обе отметки мигают ОДНОЙ анимацией и включаются в одном кадре — потому и
   мигают синхронно, как просил заказчик. */
.shop-footer-side { position: relative; }
.shop-footer-side[data-badge]::after {
  content: attr(data-badge);
  position: absolute; top: -8px; right: -8px;
  min-width: 20px; height: 20px; padding: 0 5px;
  display: flex; align-items: center; justify-content: center;
  box-sizing: border-box;
  font-size: 13px; font-weight: bold; letter-spacing: 0; line-height: 1;
  color: #1a1208; background: var(--gold);
  border-radius: 3px;
  animation: sf-badge-blink 1.1s ease-in-out infinite;
}
@keyframes sf-badge-blink {
  0%, 100% { opacity: 1;  box-shadow: 0 0 0 0 rgba(240,208,96,0); }
  50%      { opacity: .45; box-shadow: 0 0 10px 2px rgba(240,208,96,.75); }
}
/* Пока висит предупреждение о возврате в Эфир (#140), главная кнопка прячется из
   JS — боковые обязаны уйти вместе с ней, иначе подвал остаётся с двумя кнопками
   и дырой посередине. #shop-confirm стоит в разметке перед #shop-footer, поэтому
   хватает соседского комбинатора: трогать четыре места в JS не нужно. */
#shop-confirm:not(.hidden) ~ #shop-footer .shop-footer-side { display: none; }

/* ─── MINI SHAPE GRID ────────────────────────────── */
/* #262: коробка одна на всех — 50×50, как у заглушки .eph-locked-tile ниже.
   Размер продублирован в game.js (MS_BOX_PX), менять только вместе. Раньше
   габарит считал JS от размера тела, и рамка снятой сигнатуры выходила у
   каждого эфемера своя. */
.mini-shape {
  width: 50px; height: 50px;
  display: grid;
  place-content: center;
  grid-template-columns: repeat(5, 10px);
  grid-template-rows: repeat(5, 10px);
  gap: 1px;
  box-sizing: border-box;
  flex-shrink: 0;
}
/* #201: форма, снятая Сканером в этом слое, но не расшифрованная в Атласе.
   Рамка пунктиром и помехи поверх — картинка «своя, снятая на месте», а не
   выданная базой данных. Рамка через outline, а не border: border сдвинул бы
   сетку 10px-секторов и форма перестала бы совпадать с расшифрованной. */
.mini-shape.ms-raw {
  position: relative;
  border: 1px dashed rgba(240,208,96,.55);
  border-radius: 3px;
}
/* Помехи лежат ВНУТРИ той же рамки: раньше плёнка выходила на 3px наружу и
   читалась вторым квадратом рядом с первым (#262). */
.mini-shape.ms-raw::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(
    0deg,
    rgba(240,208,96,.16) 0 1px,
    transparent 1px 3px
  );
}
.ms-cell { width: var(--ms-cell, 10px); height: var(--ms-cell, 10px); border-radius: 1px; background: transparent; }
.ms-cell.seg-green  { background: rgba(46,204,113,.7); }
.ms-cell.seg-yellow { background: rgba(243,156,18,.7); }
.ms-cell.seg-red    { background: rgba(231,76,60,.7); }
.ms-cell.seg-blue   { background: rgba(59,130,246,.7); }
.ms-cell.seg-mem    { background: var(--gold); }

/* ─── RED EPHEMERS ───────────────────────────────── */
.open-red   { background:rgba(231,76,60,.12); border:1px solid rgba(231,76,60,.3); color:rgba(231,76,60,.5); }
.scanned-red { background:rgba(231,76,60,.25); border:1px solid rgba(231,76,60,.6); color:var(--red); box-shadow:0 0 10px rgba(231,76,60,.4); }
.eph-card.red-eph  { border-color: rgba(231,76,60,.4); }
.eph-icon.red-icon { background: rgba(231,76,60,.2); color: var(--red); }

/* ─── BLUE EPHEMERS ──────────────────────────────── */
.open-blue   { background:rgba(59,130,246,.12); border:1px solid rgba(59,130,246,.3); color:rgba(59,130,246,.5); }
.scanned-blue { background:rgba(59,130,246,.25); border:1px solid rgba(59,130,246,.6); color:#3b82f6; box-shadow:0 0 10px rgba(59,130,246,.4); }
.eph-card.blue-eph  { border-color: rgba(59,130,246,.4); }
.eph-icon.blue-icon { background: rgba(59,130,246,.2); color: #3b82f6; }

/* ─── PURPLE EPHEMERS (Отзвук / Проклятые) ─────────── */
.open-purple   { background:rgba(155,89,182,.12); border:1px solid rgba(155,89,182,.3); color:rgba(155,89,182,.5); }
.scanned-purple { background:rgba(155,89,182,.25); border:1px solid rgba(155,89,182,.6); color:var(--purple); box-shadow:0 0 10px rgba(155,89,182,.4); }
.eph-card.purple-eph  { border-color: rgba(155,89,182,.4); }
.eph-icon.purple-icon { background: rgba(155,89,182,.2); color: var(--purple); }
.ms-cell.seg-purple   { background: rgba(155,89,182,.7); }

/* Combo-лампочки под Искажением. Раньше фиолетовыми становились ВСЕ пять — и
   зажжённые, и пустые, — а счётчик отличался только рамкой. Это ломало саму
   систему индикации: лампа должна означать «набрано», а не «идёт режим».
   Теперь режим меняет только ЦВЕТ ЗАЛИВКИ у зажжённых, а незажжённые остаются
   пустыми кружками, как всегда. */
.combo-lamp.invert { border-color: rgba(155,89,182,.45); }
.combo-lamp.lit.invert {
  background: var(--purple);
  border-color: var(--purple);
  box-shadow: 0 0 6px rgba(155,89,182,.8);
}

/* ─── M-02 ВОЛНА — wave animation ───────────────────── */
@keyframes wave-flash {
  0%   { background: rgba(78,205,196,.85); box-shadow: 0 0 12px rgba(78,205,196,.9); }
  60%  { background: rgba(78,205,196,.25); }
  100% { background: inherit; box-shadow: none; }
}
.cell-wave-anim {
  animation: wave-flash var(--t-in) ease-out both;
  animation-delay: calc(var(--wave-col, 0) * 65ms);
}

/* ─── M-04 УСИЛЕНИЕ — Amplify active state ──────────── */
@keyframes amplify-shimmer {
  0%   { box-shadow: 0 0 6px 1px rgba(231,76,60,.4), inset 0 0 8px rgba(231,76,60,.1); border-color: rgba(231,76,60,.7); }
  50%  { box-shadow: 0 0 14px 3px rgba(231,76,60,.8), inset 0 0 14px rgba(231,76,60,.25); border-color: #e74c3c; }
  100% { box-shadow: 0 0 6px 1px rgba(231,76,60,.4), inset 0 0 8px rgba(231,76,60,.1); border-color: rgba(231,76,60,.7); }
}
.card-slot.amplify-active {
  animation: amplify-shimmer var(--t-slow) ease-in-out infinite;
  border-color: rgba(231,76,60,.7) !important;
}
.amplify-badge {
  position: absolute;
  top: 4px; right: 5px;
  font-size: 11px;
  color: #ff7070;
  font-weight: bold;
  text-shadow: 0 0 6px rgba(231,76,60,.9);
  pointer-events: none;
}

/* ─── M-06 ЗАЩИТА — protection bubble on Связность ─────────── */
.heart.protection-bubble {
  font-size: 18px;
  color: var(--teal);
  margin-left: 2px;
  animation: bubble-pulse 1.4s ease-in-out infinite;
  cursor: default;
}
@keyframes bubble-pulse {
  0%,100% { opacity: 0.7; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.15); }
}
/* #399: Резонанс (M-10) — знак мембраны, вращается. Размер в em: рядом стоит
   знак щита того же кегля, и в пикселях они разъехались бы. У двух эффектов
   сразу знаки лежат друг на друге и сменяются каждые 3,5 с — вращение живёт
   на вложенном узле, чтобы не спорить с анимацией смены. */
.heart.protection-bubble .pb-ic { display: inline-flex; align-items: center; justify-content: center; }
.heart.protection-bubble .pb-double { color: var(--gold); }
.heart.protection-bubble .pb-spin { display: inline-flex; animation: pb-spin 4s linear infinite; }
.heart.protection-bubble .pb-double svg { width: 1em; height: 1em; }
.heart.protection-bubble.pb-swap { position: relative; }
.heart.protection-bubble.pb-swap .pb-double { position: absolute; inset: 0; }
.heart.protection-bubble.pb-swap .pb-shield { animation: pb-swap-a 7s infinite; }
.heart.protection-bubble.pb-swap .pb-double { animation: pb-swap-b 7s infinite; }
@keyframes pb-spin   { to { transform: rotate(360deg); } }
@keyframes pb-swap-a { 0%, 45% { opacity: 1; } 50%, 95% { opacity: 0; } 100% { opacity: 1; } }
@keyframes pb-swap-b { 0%, 45% { opacity: 0; } 50%, 95% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .heart.protection-bubble .pb-spin { animation: none; }
}

/* ─── WIP equipment badge ───────────────────────────── */
.equip-wip-badge {
  display: inline-block;
  margin-left: 8px;
  background: rgba(231,76,60,.15);
  border: 1px solid var(--red);
  color: var(--red);
  font-size: 10px;
  letter-spacing: 1px;
  padding: 1px 5px;
  border-radius: 2px;
  vertical-align: middle;
}
.equip-wip { opacity: 0.55; }
.equip-wip .btn-equip-buy { cursor: not-allowed; }

/* ─── Кнопка Отзвук (в keys-bar) ──────────────────────── */
#btn-warp {
  background: rgba(155,89,182,.15);
  border: 1px solid var(--purple);
  color: var(--purple);
  padding: 4px 12px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 14px;
  border-radius: 3px;
  margin-left: 8px;
}
#btn-warp:hover { background: rgba(155,89,182,.3); }
#btn-warp.hidden { display: none; }

/* Отзвук-стабилат в res-bar */
#res-warp { transition: opacity var(--t-tap); }
#res-warp.hidden { display: none; }

/* ─── ARCHIVE BTN (res-bar) ──────────────────────────
   Правила переключателя подсказок (.hint-toggle-wrap, .ht-sw) сняты вместе с
   самим переключателем: #302 убрал его из шапки слоя, он живёт в «МЕНЮ» и в
   карточке эхонавта обычной галочкой. */
#btn-archive {
  background: rgba(78,205,196,.08);
  border: 1px solid rgba(78,205,196,.55);
  color: var(--teal);
  cursor: pointer;
  font-size: 13px;
  font-weight: bold;
  letter-spacing: 1.5px;
  padding: 4px 10px;
  border-radius: 3px;
  line-height: 1.4;
  font-family: var(--font-mono);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.btn-archive-icon { font-size: 15px; display: inline-flex; }
.btn-archive-label { font-size: 12px; }
#btn-help {
  background: rgba(160,180,200,.08);
  border: 1px solid rgba(160,180,200,.45);
  color: var(--text);
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  padding: 4px 8px;
  border-radius: 3px;
  font-family: var(--font-mono);
  line-height: 1;
}
#btn-archive:hover {
  background: rgba(78,205,196,.18);
  border-color: var(--teal);
  color: #b6f1eb;
}
/* Шапка слоя: «МЕНЮ» С ПОДПИСЬЮ и отдельный ДИНАМИК — ровно как в шапке
   станции. Голая шестерёнка рядом с голым бутербродом делала одно и то же, и
   угадать разницу было нельзя (заметка «ШАПКА» на холсте). Метрики те же, что
   у #btn-archive: кнопки стоят в одной строке, и разница в пару пикселей по
   вертикали читается как «съехало». */
#btn-settings {
  background: rgba(78,205,196,.08);
  border: 1px solid rgba(78,205,196,.45);
  color: var(--teal);
  cursor: pointer;
  padding: 4px 10px;
  border-radius: 3px;
  line-height: 1.4;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-head);
  font-size: 12px; font-weight: 500; letter-spacing: 2px; text-transform: uppercase;
}
.btn-settings-label { font-size: 12px; }
#btn-quickmute {
  background: rgba(78,205,196,.08);
  border: 1px solid rgba(78,205,196,.45);
  color: var(--teal);
  cursor: pointer;
  /* Высота ЗАДАНА, а не набегает из padding: значок здесь крупнее буквы, и
     кнопка выросла бы на три пикселя выше «АРХИВ» и «МЕНЮ» рядом. Разница в
     пару пикселей по вертикали читается как «съехало» (та же причина, по
     которой у #btn-settings повторены метрики #btn-archive). 27 px — высота
     соседей: 12 px × 1.4 плюс их padding и рамка. */
  height: 27px; padding: 0 9px;
  border-radius: 3px;
  line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono);
}
#btn-settings .gi, #btn-quickmute .gi { height: 14px; }
/* Тот же динамик, что в шапке станции, и того же размера: одна величина —
   один знак. У него нет подписи рядом, и в общем ряду он читался мельче всех
   (заказчик 30.08.2026). */
#btn-quickmute .gi { height: 20px; }
/* Выключенный звук — приглушённый значок, как в шапке станции. */
#btn-quickmute.qm-off { color: rgba(200,220,235,.5); border-color: var(--border-2); }
#btn-settings:hover, #btn-quickmute:hover {
  background: rgba(78,205,196,.18);
  border-color: var(--teal);
  color: #b6f1eb;
}

/* ─── НАСТРОЙКИ (малое меню) ─────────────────────────────────────
   z-index 9300: выше Атласа (9200), ниже профилей (9500) и generic-confirm
   (9600) — подтверждение выхода обязано лечь поверх этого окна. */
/* ─── ТЕСТОВОЕ МЕНЮ (#244) ────────────────────────────────────────
   Красная кнопка с чёрными буквами: она не часть игры, и спутать её с частью
   игры нельзя. Так же её видно, если она случайно уехала на боевой стенд. */
#btn-test {
  background: #c0392b;
  color: #000;
  border: 1px solid #e74c3c;
  border-radius: 3px;
  font-family: var(--font-mono);
  /* Метрики один в один с #btn-archive: кнопки стоят рядом в одной строке
     шапки, и разница в 4 px по вертикали читается как «съехало».
     min-height здесь БЫЛА и стоила ровно этого: 36 px против 27 у соседей —
     кнопка вылезала из ряда на 5 px вверх (замер 08.09.2026). Высоту задаёт
     тот же padding, что и у соседей, и ничего сверх. */
  font-size: 13px; font-weight: bold; letter-spacing: 1.5px;
  padding: 4px 10px;
  line-height: 1.4;
  display: inline-flex; align-items: center;
  cursor: pointer;
}
#btn-test:hover { background: #e74c3c; }
/* КНОПКА СТОИТ В РЯДУ, А НЕ ЗА ЭКРАНОМ (заказчик, 08.09.2026: «сделай кнопку
   „Тест“ хотя бы на одном уровне с кнопкой меню и остальными, чтобы она не
   стояла криво»).

   С 30.08.2026 она была вынута из потока (`position: fixed`) и висела справа от
   рамки: тогда её просили убрать из шапки, потому что ряд не помещался в
   1060 px. Замер 08.09.2026 показал цену: кнопка стояла на 12 px выше ряда и на
   176 px правее его края — то есть ровно то, что заказчик и назвал кривым.

   Теперь она снова часть ряда, и место ей находится тем же способом, каким его
   находят остальные кнопки шапки: подписью, которая скрывается первой. На узком
   экране от кнопки остаётся одно слово, а не два ряда. */
#btn-test { flex: 0 0 auto; }
#test-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.86);
  display: flex; align-items: center; justify-content: center;
  z-index: 9360;
  padding: 20px;
  overflow-y: auto;
}
#test-overlay.hidden { display: none; }
#test-box {
  background: var(--panel);
  border: 1px solid #e74c3c;
  border-radius: 3px;
  width: 520px; max-width: 100%;
  padding: 20px 22px;
  box-shadow: 0 0 50px rgba(231,76,60,.2);
  display: flex; flex-direction: column; gap: 16px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}
#test-title {
  font-size: 18px; letter-spacing: 3px; color: #e74c3c;
  border-bottom: 1px solid var(--border); padding-bottom: 10px;
}
.test-section { display: flex; flex-direction: column; gap: 8px; }
.test-sec-title { font-size: 13px; letter-spacing: 2px; color: var(--dim); }
/* Слои номерами в ряд: их девять и больше с петлёй, а подписи слоёв длинные —
   в столбик окно уехало бы за экран. Золотой — слой Массива. */
/* ─── СПИСОК СЛОЁВ (08.09.2026) ───────────────────────────────────
   Раньше это был ряд квадратных кнопок с номерами и двумя красными «М».
   Заказчик: «все слои не в линию, а строчки одна за другой», и у каждой строки
   свои варианты реализации с названиями. */
#test-layers { display: flex; flex-direction: column; gap: 4px; max-height: 46vh; overflow-y: auto; }
.test-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 6px 8px; border: 1px solid var(--border-2); border-radius: 3px;
  background: rgba(13,27,42,.5);
}
/* Где сейчас эхонавт — рамкой, а не заливкой: заливка спорила бы с выделением
   применённого варианта, а это разные вещи (место и правила). */
.test-row.here { border-color: rgba(78,205,196,.55); }
.test-row.sel  { background: rgba(231,76,60,.08); }
.test-row-head { display: flex; align-items: center; gap: 8px; min-width: 210px; flex: 0 0 auto; }
.test-row-no {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 24px; flex: 0 0 auto;
  border: 1px solid var(--border-2); border-radius: 2px;
  color: var(--dim); font-size: 13px;
}
.test-row.here .test-row-no { color: var(--teal); border-color: rgba(78,205,196,.55); }
/* СЛОЙ С МАССИВОМ — золотой номер и буква «М» (заказчик, 09.09.2026). Золото
   здесь не украшение: тем же цветом Массивы помечены в шапке слоя, в Архиве и
   на карте погружения. Метка «эхонавт здесь» бирюзовая и перебивает золото —
   так и задумано: где игрок, важнее, чем что там стоит. */
.test-row-no.boss { color: var(--gold); border-color: rgba(240,208,96,.5); }
.test-row-m {
  color: var(--gold); font-size: 13px; letter-spacing: 1px;
  margin-left: -3px; flex: 0 0 auto;
}
.test-row-name { font-size: 13px; color: var(--ink); }
.test-row-final .test-row-name { color: var(--gold); }
.test-row-vars { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.test-var {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 9px; border-radius: 3px; cursor: pointer;
  background: none; border: 1px solid var(--border-2);
  color: var(--dim); font-family: var(--font-mono); font-size: 12px;
}
.test-var:hover { color: var(--ink); border-color: rgba(231,76,60,.6); }
/* ВЫБРАН — пунктиром, ПРИМЕНЁН — заливкой. Пока не нажата «Применить», в игре
   не изменилось ничего, и выглядеть это должно по-разному. */
.test-var.sel { color: var(--ink); border-color: #e74c3c; border-style: dashed; }
.test-var.on  { color: #000; background: #c0392b; border-color: #e74c3c; }
.test-mark {
  font-size: 10px; font-style: normal; letter-spacing: .5px;
  padding: 1px 5px; border-radius: 2px; white-space: nowrap;
}
.test-mark-here { color: var(--teal); border: 1px solid rgba(78,205,196,.45); }
.test-mark-def  { color: #7aa4c2; border: 1px solid var(--border-2); }
.test-var.on .test-mark-def { color: #2b1310; border-color: rgba(0,0,0,.35); }
.test-mark-on   { color: #000; background: rgba(0,0,0,.18); }

/* КНОПКА ТЕСТ В РЯДУ СТАНЦИИ. Красная, как её двойник в шапке слоя: она не
   часть игры, и спутать её с частью игры нельзя. Прячется вместе со всеми
   тестовыми кнопками — по классу `test-ui-on` на <body>, который ставит
   syncTestButtons: обычный игрок за неё не платит ни одним пикселем. */
.station-bar .n-test {
  background: #c0392b; color: #000; border: 1px solid #e74c3c;
  font-weight: bold; letter-spacing: 1.5px;
}
/* КНОПКА ТЕСТ СТОИТ ЗА РАМКОЙ ШАПКИ (заказчик, 09.09.2026: «вынеси вправо за
   рамку уже… иначе там уже всё не влезает иногда»). Ряд станции — это разделы,
   погружение и меню; тестовая кнопка к игре не относится и последней съедала
   место у тех, кто относится. Абсолют от самой шапки (`position: relative` у
   .station-bar), по центру её высоты — как все остальные кнопки ряда, только
   снаружи. Из потока она при этом выходит: ряд её ширину больше не считает. */
.station-bar .n-test {
  position: absolute; left: 100%; top: 50%; transform: translateY(-50%);
  margin-left: 10px;
}
.station-bar .n-test:hover { background: #e74c3c; }
/* Узкое окно: справа от шапки места нет, и кнопка ушла бы за край экрана —
   там она возвращается в ряд. 1360 = ширина раздела 1180 плюс место под неё. */
@media (max-width: 1360px) {
  .station-bar .n-test { position: static; transform: none; margin-left: 0; }
}
body:not(.test-ui-on) .station-bar .n-test { display: none; }
/* Имя применённого варианта у подписи ПОГРУЖЕНИЯ. Приписка, а не вторая
   строка: ничто в одну строку не должно становиться двумя. */
.n-dive-var {
  font-style: normal; margin-left: 6px; padding: 0 5px;
  border: 1px solid rgba(231,76,60,.6); border-radius: 2px;
  color: #e8836f; font-size: 10px; letter-spacing: .5px; white-space: nowrap;
}

/* ─── ОКНО НАСТРОЙКИ ВАРИАНТА (задание №20) ────────────────────────
   Тот же красный корпус, что у тестового меню: это его продолжение, и другой
   цвет читался бы как чужое окно. Лежит ПОВЕРХ меню (z-index выше), потому что
   открывается из него и меню под ним остаётся. */
#varopt-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.9);
  display: flex; align-items: center; justify-content: center;
  z-index: 9380;
  padding: 20px;
  overflow-y: auto;
}
#varopt-overlay.hidden { display: none; }
#varopt-box {
  background: var(--panel);
  border: 1px solid #e74c3c;
  border-radius: 3px;
  width: 520px; max-width: 100%;
  padding: 20px 22px;
  box-shadow: 0 0 50px rgba(231,76,60,.2);
  display: flex; flex-direction: column; gap: 14px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
}
#varopt-head { display: flex; align-items: center; gap: 10px; }
#varopt-title {
  flex: 1 1 auto;
  font-size: 17px; letter-spacing: 2px; color: #e74c3c;
  border-bottom: 1px solid var(--border); padding-bottom: 10px;
}
#varopt-sub { font-size: 13px; letter-spacing: 1px; color: var(--dim); margin-top: -6px; }
#varopt-list { display: flex; flex-direction: column; gap: 14px; }
.varopt-row {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; border: 1px solid var(--border-2); border-radius: 3px;
  background: rgba(13,27,42,.5);
}
.varopt-lab { font-size: 13px; letter-spacing: 1px; color: var(--teal); }
.varopt-note { font-size: 11px; color: var(--dim); line-height: 1.4; }
.varopt-ctl { display: flex; align-items: center; gap: 12px; }
.varopt-ctl .settings-range { flex: 1; }
/* ЗНАЧЕНИЕ — ПОЛЕ, А НЕ ПОДПИСЬ (задание №24). Прежде здесь стояло число
   текстом, и выставить его можно было только ползунком: «пытаешься угадать в 10
   вместо 11». Теперь то же число набирается с клавиатуры, а ползунок и поле
   держат одну величину (varOptSyncPair). */
.varopt-val {
  min-width: 48px; flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 4px; justify-content: flex-end;
}
.varopt-pct-sign {
  font-style: normal; font-family: var(--font-mono); font-size: 13px; color: var(--dim);
}
.varopt-num {
  width: 52px; flex: 0 0 auto;
  background: rgba(13,27,42,.8); color: var(--gold);
  border: 1px solid var(--border-2); border-radius: 3px;
  font-family: var(--font-mono); font-size: 13px; font-weight: bold;
  text-align: center; padding: 3px 0;
}
/* Главное число строки — тем же красным и тем же кеглем, каким оно стояло
   подписью: окно уже учит читать его как величину варианта. */
.varopt-num-main { color: #e74c3c; font-size: 16px; width: 56px; }
.varopt-num:focus { outline: 1px solid var(--teal); outline-offset: 1px; }
/* Нативные стрелки прячем по тем же доводам, что у поля порции (ниже): в Chrome
   они всплывают по наведению, в Safari висят всегда. */
.varopt-num::-webkit-outer-spin-button,
.varopt-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.varopt-num { -moz-appearance: textfield; appearance: textfield; }
/* Строка раскладки: имя с значком — ползунок — доля. Имя фиксированной ширины,
   иначе ползунки шести строк встанут лесенкой и сравнивать доли будет нечем. */
.varopt-mix-row { display: flex; align-items: center; gap: 10px; }
.varopt-mix-name {
  display: inline-flex; align-items: center; gap: 6px;
  width: 116px; flex: 0 0 auto;
  font-size: 12px; color: var(--fg);
}
/* Ширина значка auto, а не 100 %: инлайновый SVG без размеров WebKit растит до
   300x150 (см. svgSized в game.js и грабли по Safari). */
.varopt-mix-name .gi { width: 1.05em; height: 1.05em; flex: 0 0 auto; }
.varopt-mix-name .gi > svg { width: auto; height: 100%; display: block; }
.varopt-mix-row .settings-range { flex: 1; }
.varopt-mix-pct {
  min-width: 44px; text-align: right;
  font-family: var(--font-mono); font-size: 13px; font-weight: bold;
  color: var(--gold); font-variant-numeric: tabular-nums;
}
/* ПОРЦИЯ ВИДА — числом справа от доли (поправка 09.09.2026). Числовое поле, а
   не ползунок: значений всего девять, и попадать ползунком в «4» из девяти
   делений мучительно, а стрелки поля дают ровно шаг в единицу. */
.varopt-amt-x { color: var(--dim); font-size: 12px; flex: 0 0 auto; }
.varopt-amt {
  width: 42px; flex: 0 0 auto;
  background: rgba(13,27,42,.8); color: var(--gold);
  border: 1px solid var(--border-2); border-radius: 3px;
  font-family: var(--font-mono); font-size: 13px; font-weight: bold;
  text-align: center; padding: 3px 0;
}
.varopt-amt:focus { outline: 1px solid var(--teal); outline-offset: 1px; }
/* НАТИВНЫЕ СТРЕЛКИ ПРЯЧЕМ. В Chrome они всплывают по наведению, в Safari висят
   всегда — то есть одно и то же поле в двух браузерах разной ширины и с текстом,
   сдвинутым влево. Ровно тот случай, ради которого Safari проверяется отдельно.
   Значение вводится с клавиатуры, стрелки ↑↓ при фокусе работают и без них. */
.varopt-amt::-webkit-outer-spin-button,
.varopt-amt::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.varopt-amt { -moz-appearance: textfield; appearance: textfield; }
/* Место под поле держим и там, где порции нет («пусто»): без него шесть строк
   встанут лесенкой и сравнивать доли будет не по чему. */
.varopt-amt-none { width: 55px; flex: 0 0 auto; }  /* 42 поля + знак «×» с отступом */

/* «Пусто» — не ресурс, а его отсутствие: пустой кружок вместо значка. */
.varopt-none {
  display: inline-block; width: 1.05em; height: 1.05em; flex: 0 0 auto;
  border: 1px solid var(--dim); border-radius: 50%;
}
/* Ступени Сканера в окне «Зеркального фиолетового» (задание №22): знак прибора
   в кружке того же размера, что значок ресурса, — строки встают ровно. */
.varopt-scan {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05em; height: 1.05em; flex: 0 0 auto;
  border: 1px solid var(--dim); border-radius: 50%;
  font-style: normal; font-family: var(--font-mono); font-size: 10px; line-height: 1;
  color: var(--fg);
}
/* Флажок в окне настроек (поправка к заданию №22 — Искажение): галка и
   название одной строкой. */
.varopt-flag { display: flex; align-items: center; gap: 8px; cursor: pointer; }
.varopt-flag input { width: 16px; height: 16px; margin: 0; flex: 0 0 auto; accent-color: var(--gold); }
.varopt-flag .varopt-lab { margin: 0; }
/* Заражение «Зеркального» (вторая поправка к №22): Зонд не берёт ни череп, ни
   его зону — над ними курсор «запрет» и никакой подсветки. Класс инструмента на
   поле один, поэтому Предиктору (tool-equip-pending) правило не мешает. */
.tool-locator .cell-no-probe { cursor: not-allowed; }
.tool-locator .cell-no-probe:hover { box-shadow: none; }
/* Значок заражения на карточке «Зеркального» (шестая поправка к №22): тот же
   угловой значок, что у Поглощения, но черепа — цветом заражения. */
.boss-infect-badge .gi { color: var(--red); }
/* СЧЁТЧИК ВОЛНЫ РЯДОМ КВАДРАТИКОВ — «ТУМАН» (задание №23). Заказчик: «показывать
   такими же квадратиками, прогресс-барами, красными, как там, где количество
   секторов». Геометрия взята у ряда сегментов тела (.bsd-dot) и уменьшена под
   угловой значок: два ряда квадратиков на одной карточке обязаны читаться одним
   приёмом, иначе игрок будет разбирать, чем они отличаются. */
.bif-pips { display: inline-flex; align-items: center; gap: 2px; margin: 0 1px; }
.bif-pips i {
  width: 6px; height: 6px; border-radius: 1px;
  background: rgba(231, 76, 60, .22);
  box-shadow: none;
  transition: background var(--t-tap) ease, box-shadow var(--t-tap) ease;
}
.bif-pips i.on {
  background: var(--red);
  box-shadow: 0 0 5px rgba(231, 76, 60, .55);
}
/* ПОСЛЕДНИЙ ТАКТ ПЕРЕД ВОЛНОЙ — ЗНАЧОК ПУЛЬСИРУЕТ (правка заказчика 12.09.2026).
   Строка «РОСТ ЗАРАЖЕНИЯ» под Синтезом убрана, и предупреждение переехало сюда:
   одно событие — одно место. Пульсирует рамка и свечение, а не размер: значок
   стоит в углу кадра, и скачущий габарит дёргал бы картинку под ним. */
.boss-eph .boss-absorb-badge.boss-infect-soon {
  animation: infect-soon 0.9s ease-in-out infinite;
}
@keyframes infect-soon {
  0%, 100% { border-color: var(--border-2); box-shadow: none; }
  50%      { border-color: rgba(231, 76, 60, .85); box-shadow: 0 0 10px rgba(231, 76, 60, .45); }
}
/* Знак вопроса внутри значка и в ряду сегментов — тот же кружок, что у Глаз,
   только мельче: там он стоит в отдельной строке, здесь — в плотном ряду. */
.bab-help, .bsd-help { width: 14px; height: 14px; font-size: 10px; margin-left: 6px; }

#test-head { display: flex; align-items: center; gap: 10px; }
#test-head #test-title { flex: 1 1 auto; }
#test-apply:disabled { opacity: .45; cursor: default; }

#test-level-row { display: flex; align-items: center; gap: 12px; }
#test-level-row .settings-range, #test-boss-size-row .settings-range { flex: 1; }
#test-boss-size-val {
  min-width: 34px; text-align: right;
  font-family: var(--font-mono); font-size: 17px; font-weight: bold;
  color: #e74c3c; font-variant-numeric: tabular-nums;
}
#test-level-val {
  min-width: 34px; text-align: right;
  font-family: var(--font-mono); font-size: 17px; font-weight: bold;
  color: var(--teal); font-variant-numeric: tabular-nums;
}
.test-hint { font-size: 12px; color: var(--dim); line-height: 1.45; }
.test-btn {
  background: rgba(231,76,60,.10); color: #e74c3c;
  border: 1px solid rgba(231,76,60,.6); border-radius: 3px;
  font-family: var(--font-mono); font-size: 14px;
  font-weight: bold; letter-spacing: 1px;
  padding: 10px; cursor: pointer;
}
.test-btn:hover { background: rgba(231,76,60,.22); }
.test-btn-main { letter-spacing: 2px; }
/* Кнопка пересборки в шапке Атласа — та же красная, но мельче: шапка тесная.
   Задача №4: подпись стала «ПЕРЕМЕШАТЬ» вместо «ТЕСТ» — кнопка не открывает
   тестовое меню, она тасует карточки. Ширину не задаём числом: white-space
   держит подпись в одну строку, а padding растит кнопку ровно под неё —
   перевод на другой язык не заставит переписывать CSS. */
#btn-atlas-test {
  background: #c0392b; color: #000;
  border: 1px solid #e74c3c; border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 11px; font-weight: bold; letter-spacing: 1px;
  padding: 4px 12px; cursor: pointer;
  white-space: nowrap;
}
#btn-atlas-test:hover { background: #e74c3c; }

/* Задача №4: вход в тестовое меню из Организаций. Окно магазина закрывает
   экран целиком, и до кнопки в шапке слоя оттуда не добраться.
   Кнопка отсюда убрана (заказчик, 30.08.2026): она дублировала #btn-test,
   которая теперь стоит вне потока и видна на всех экранах. */
#shop-box { position: relative; }

/* ФИНАЛ (задача №6): в запертом Атласе живая кнопка одна, и она отвечает на
   попытки нажать что-то другое. Мигание, а не подсветка навсегда: постоянно
   горящая кнопка перестаёт читаться как ответ на действие. */
@keyframes objx-blink {
  0%, 100% { box-shadow: 0 0 0 rgba(231,76,60,0); transform: scale(1); }
  50%      { box-shadow: 0 0 14px rgba(231,76,60,.9); transform: scale(1.06); }
}
.btn-atlas-decipher.objx-blink { animation: objx-blink var(--t-in) ease-in-out 4; }
@media (prefers-reduced-motion: reduce) {
  .btn-atlas-decipher.objx-blink { animation: none; box-shadow: 0 0 14px rgba(231,76,60,.9); }
}

/* ─── ОКНО РЕЖИМА ИГРЫ (#242) ─────────────────────────────────────
   Оформлено по образцу «Настроек»: то же затемнение, та же рамка, тот же кегль
   заголовка — это соседнее окно того же уровня. Шире настроек, потому что
   каждая строка — послабление с пояснением, а не одна подпись. */
#mode-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.86);
  display: flex; align-items: center; justify-content: center;
  z-index: 9350;
  padding: 20px;
  overflow-y: auto;
}
#mode-overlay.hidden { display: none; }
#mode-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: 520px; max-width: 100%;
  padding: 20px 22px;
  box-shadow: 0 0 50px rgba(78,205,196,.2);
  display: flex; flex-direction: column; gap: 14px;
  max-height: calc(100vh - 40px);
}
#mode-title {
  font-size: 18px; letter-spacing: 3px; color: var(--teal);
  border-bottom: 1px solid var(--border); padding-bottom: 10px;
}
#mode-tabs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.mode-tab {
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 1px; font-weight: bold;
  color: var(--dim); background: transparent;
  border: 1px solid var(--border); border-radius: 3px;
  padding: 9px 6px; cursor: pointer;
  transition: color var(--t-tap), border-color var(--t-tap), background var(--t-tap);
}
.mode-tab:hover { color: var(--teal); border-color: var(--teal); }
.mode-tab.active { color: var(--teal); border-color: var(--teal); background: rgba(78,205,196,.12); }
#mode-sub { font-size: 14px; color: #a8c4d4; line-height: 1.5; }
/* Список послаблений прокручивается ВНУТРИ окна: шесть строк на телефоне по
   высоте не влезают, а рамка окна обязана остаться на месте — та же грабля,
   что с перечнем слоёв Атласа (#254). */
#mode-list { display: flex; flex-direction: column; gap: 8px; overflow-y: auto; min-height: 0; }
.mode-row {
  display: flex; align-items: flex-start; gap: 10px;
  border: 1px solid var(--border); border-radius: 3px;
  padding: 9px 11px;
  background: rgba(255,255,255,.02);
  cursor: pointer;
}
/* В обычном и хардкоре галки только ПОКАЗЫВАЮТ состав режима. Гасим строку
   слегка: полупрозрачная до неразличимости, она перестала бы отвечать на
   вопрос «а что мне это даёт». */
.mode-row-fixed { cursor: default; opacity: .82; }
/* #259: выключенное послабление — красная строка. Цвет несёт смысл: синее это
   то, что игра делает за игрока, красное — то, что он делает сам. В хардкоре
   красными становятся все шесть, в настраиваемом строка переключается под
   рукой вместе с галкой. */
.mode-row-hard { border-color: rgba(224,122,90,.45); background: rgba(231,76,60,.05); }
.mode-row-hard .mode-row-label { color: #e07a5a; }
.mode-row-hard .mode-row-text  { color: rgba(224,122,90,.75); }
.mode-row-hard input { accent-color: #e07a5a; }
.mode-row input { margin-top: 3px; accent-color: var(--teal); }
.mode-row-body { display: flex; flex-direction: column; gap: 3px; }
.mode-row-label { font-size: 15px; font-weight: bold; color: #dbe9f2; }
.mode-row-text { font-size: 13px; color: var(--dim); line-height: 1.45; }
#mode-close {
  background: rgba(78,205,196,.10); color: var(--teal);
  border: 1px solid var(--teal); border-radius: 3px;
  font-family: var(--font-mono); font-size: 15px;
  font-weight: bold; letter-spacing: 2px;
  padding: 11px; cursor: pointer;
}
#mode-close:hover { background: rgba(78,205,196,.22); }

#settings-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.86);
  display: flex; align-items: center; justify-content: center;
  z-index: 9300;
  padding: 20px;
}
#settings-overlay.hidden { display: none; }
#settings-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: 360px; max-width: 100%;
  padding: 20px 22px;
  box-shadow: 0 0 50px rgba(78,205,196,.2);
  display: flex; flex-direction: column; gap: 18px;
}
#settings-header {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 10px;
}
#settings-title { font-size: 18px; letter-spacing: 3px; color: var(--teal); }
#settings-close {
  background: none; border: none; color: var(--teal);
  font-size: 18px; cursor: pointer; line-height: 1;
}
.settings-row { display: flex; flex-direction: column; gap: 7px; }
.settings-row-top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.settings-label { font-size: 13px; letter-spacing: 1px; color: var(--text); }
.settings-val { font-size: 13px; color: var(--teal); font-variant-numeric: tabular-nums; }
/* Ползунок: appearance:none обязателен — иначе Chrome/Safari рисуют системный
   светлый трек, который в тёмной панели читается как чужеродная белая полоса. */
.settings-range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 6px; margin: 0;
  background: rgba(78,205,196,.18);
  border: 1px solid var(--border);
  border-radius: 3px;
  cursor: pointer;
}
.settings-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--teal); border: none; cursor: pointer;
  box-shadow: 0 0 8px rgba(78,205,196,.5);
}
.settings-range::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--teal); border: none; cursor: pointer;
}

/* ─── ПАНЕЛЬ ЗВУКА ПОД ДИНАМИКОМ (30.08.2026) ─────────────────────
   Оба ползунка громкости, вынесенные из «МЕНЮ». Панель fixed и одна на все
   пять динамиков (шапка слоя плюс четыре шапки станции): место ей считает
   placeSoundPop() по кнопке, под которой открыли, поэтому ни left, ни top
   здесь не задаются — их пишет JS.
   z-index выше окон станции и «МЕНЮ» (9300), но ниже подтверждений (9600):
   вопрос, заданный игроку, важнее регулятора. */
/* ═══ ПЛЕЕР СЛОЯ (06.09.2026) ═══════════════════════════════════════
   Полоса под полем и журналом: что играет, управление, эквалайзер, динамик.
   Заказчик просил убрать иконку звука из шапки и дать управление музыкой
   отдельным широким блоком — динамик переехал сюда, ползунки остались в
   общей панели #sound-pop.

   Полосы НЕТ на станции и на экране итога: там музыка общая и переключать
   нечего. Прячет её сама игра (renderMusicBar), классом hidden. */
/* ПОЛОСА ДЕЛИКАТНАЯ, А НЕ ЕЩЁ ОДНА ПАНЕЛЬ (заказчик, 06.09.2026). Первая
   редакция была коробкой с рамкой, засечками и кнопками в квадратных обводках —
   и на экране она читалась наравне с полем и журналом, хотя это вспомогательный
   элемент. Теперь: ни рамки, ни фона, ни обводок у кнопок; отделяет её одна
   волосяная черта сверху, ровно как панели отделены друг от друга. */
#music-bar {
  display: flex; align-items: center; gap: 10px;
  /* НАДПИСЬ СТОИТ ПО ЦЕНТРУ ТЁМНОЙ ЗОНЫ, а не по центру своей полосы. Под
     полосой лежит нижний отступ колонки (#app, 14 px — «колонка кончается, а
     не обрывается», 30.08.2026), и он тоже читается как часть блока: при
     равных отступах внутри полосы надпись выходила выше середины. Поэтому
     сверху 12, снизу 0 — отступ колонки и есть нижняя половина. */
  width: 100%; margin-top: 6px; padding: 12px 10px 0;
  background: none; border: none; border-top: 1px solid var(--border);
  transition: opacity var(--t-tap) ease;
}
/* Музыка стоит — полоса приглушена, но не спрятана: она и есть то, чем её
   включают обратно. */
#music-bar.mb-quiet { opacity: .55; }

/* ПОЛОСА НА СТАНЦИИ (08.09.2026). Заказчик: «когда вынырнули, он сейчас
   наверху… давайте сделаем консистентно, одинаково» — управление звуком стояло
   динамиком в шапке станции, а панель громкости выпадала сверху. Динамик из
   шапки убран, полоса переезжает узлом под коробку открытого раздела
   (placeMusicBar в game.js), и звук на станции правят там же, где в слое.

   Здесь она ПАНЕЛЬ, а не волосяная черта: в слое полоса лежит внутри колонки и
   отделяется от неё чертой, а на станции под коробкой раздела пустой фон — без
   рамки полоса висела бы в воздухе. Анатомия взята у шапки станции
   (.station-bar): один и тот же экран, обрамление сверху и снизу одинаковое. */
#music-bar.mb-station {
  flex: 0 0 auto;
  width: var(--station-w, 1060px); max-width: 100%;
  margin: 14px auto 0; padding: 7px 12px;
  background: var(--panel); border: 1px solid var(--border-2); border-radius: var(--r);
}

.mb-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: 0 0 22px; padding: 0;
  background: none; border: none;
  color: var(--dim); cursor: pointer;
  transition: color var(--t-tap) ease;
}
.mb-btn:hover { color: var(--teal); background: none; }
.mb-btn .gi { height: 11px; }
.mb-btn.qm-off { color: var(--dim); opacity: .6; }

/* Название — кнопка только тогда, когда есть из чего выбирать. Курсор-палец
   у единственного трека обещал бы список, которого нет. */
/* Название не жмётся под эквалайзер: сперва оно, потом всё остальное.
   Полоса широкая, а «The Signal in the Sta…» на ней — обидная мелочь. */
.mb-name {
  display: flex; align-items: baseline; gap: 8px; min-width: 0;
  flex: 0 1 auto; max-width: 42%;
  padding: 2px 4px; background: none; border: none;
  color: var(--dim); font-family: var(--font-head); font-size: 12px;
  letter-spacing: .5px; text-transform: none; cursor: default;
  transition: color var(--t-tap) ease;
}
.mb-name-more { cursor: pointer; }
.mb-name-more:hover, #music-bar:hover .mb-name { color: var(--text); }
#mb-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mb-mark { flex: 0 0 auto; font-size: 10px; letter-spacing: 1px; color: var(--dim); opacity: .75; }

/* Эквалайзер — лежачая лента плашек одного размера: рамки стоят на месте
   всегда, а пульс это заливка внутри них. Ни высоты столбика, ни длины штриха
   — он вспомогательный, и ряд, меняющий размер, тянул взгляд с поля.
   Высота под плашку 9 px плюс воздух; ширина плашки и зазор живут в game.js. */
#mb-eq { flex: 1 1 120px; min-width: 60px; height: 14px; display: block; }
.mb-time {
  flex: 0 0 auto; font-family: var(--font-mono); font-size: 10px; color: var(--dim);
  font-variant-numeric: tabular-nums; opacity: .8;
}

/* Список треков слоя — над полосой, той же анатомией, что панель звука. */
#mb-pop {
  position: fixed; z-index: 9380;
  width: 320px; max-width: calc(100vw - 24px);
  padding: 10px 12px;
  background: var(--panel); border: 1px solid var(--border);
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
  animation: sound-pop-in var(--t-tap) ease-out;
}
.mb-pop-t {
  margin-bottom: 8px; font-size: 10px; letter-spacing: 2px;
  text-transform: uppercase; color: var(--dim);
}
.mb-pick {
  display: flex; align-items: baseline; gap: 10px; width: 100%;
  padding: 6px 8px; background: none; border: 1px solid transparent;
  color: var(--text); font-size: 12px; text-align: left; cursor: pointer;
}
.mb-pick:hover { border-color: var(--border); background: rgba(78,205,196,.07); }
.mb-pick.on { border-color: var(--teal); color: var(--teal); }
.mb-pick-n { flex: 0 0 16px; color: var(--dim); font-family: var(--font-mono); }
.mb-pick.on .mb-pick-n { color: var(--teal); }
.mb-pick-t { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mb-pick-d { flex: 0 0 auto; font-family: var(--font-mono); font-size: 11px; color: var(--dim); }

/* На узком экране время уходит: там дорога каждая горизонталь, а секунды
   игроку в слое не нужны — нужно название и кнопка. */
@media (max-width: 599px) {
  #music-bar { gap: 8px; padding: 4px 6px 3px; }
  .mb-time { display: none; }
  #mb-eq { min-width: 40px; }
}

/* ВЫБОР ВИДА ПОЛОСЫ — две кнопки, выбранная подсвечена рамкой. Той же
   анатомией, что список треков (.mb-pick): панель одна, и два разных вида
   выбора в ней читались бы как два разных элемента. */
.vu-mode { display: flex; gap: 6px; }
.vu-mode-btn {
  flex: 1 1 0; padding: 5px 6px;
  background: none; border: 1px solid var(--border);
  color: var(--dim); font-family: var(--font-head); font-size: 11px;
  letter-spacing: .5px; cursor: pointer;
  transition: color var(--t-tap) ease, border-color var(--t-tap) ease;
}
.vu-mode-btn:hover { color: var(--text); border-color: var(--dim); background: none; }
.vu-mode-btn.on { color: var(--teal); border-color: var(--teal); background: rgba(78,205,196,.07); }

#sound-pop {
  position: fixed; z-index: 9380;
  width: 300px; max-width: calc(100vw - 24px);
  display: flex; flex-direction: column; gap: 15px;
  padding: 15px 17px;
  background: var(--panel);
  border: 1px solid var(--border);
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
  animation: sound-pop-in var(--t-tap) ease-out;
}
/* Появление панели: 6 px вниз за 120 мс. Без движения щелчок по динамику
   читается как «ничего не произошло» — панель просто оказывается на экране. */
@keyframes sound-pop-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
/* Метрики выхода живут вместе с остальными строками меню (.settings-link-quit
   ниже по файлу): здесь оставлять нечего — прежняя рамка делала из строки
   главную кнопку меню. */
/* #181: служебная кнопка в «Настройках» («Показывать скрытые сообщения»).
   Спокойный бирюзовый, а не красный «Завершить игру»: действие безобидное и
   обратимое, и оно не должно выглядеть тревожнее выхода из игры. */
.settings-plain-btn {
  font-family: var(--font-mono);
  font-size: 12px; letter-spacing: 1px;
  color: var(--teal);
  background: rgba(78,205,196,.08);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 10px;
  cursor: pointer;
  text-align: center;
}
.settings-plain-btn:hover { background: rgba(78,205,196,.18); border-color: var(--teal); }
/* Галочка-тумблер в «Настройках» (АР). Метка кликабельна целиком — в 18px
   квадратик пальцем на телефоне не попасть. */
.settings-check-row {
  display: flex; align-items: center; gap: 10px;
  cursor: pointer; user-select: none;
}
.settings-check-row input[type=checkbox] {
  width: 18px; height: 18px;
  accent-color: var(--teal);
  cursor: pointer;
  flex: 0 0 auto;
}

/* Перенос прогресса: служебный блок, отделён чертой и приглушён — он не должен
   спорить за внимание с громкостью, ради которой окно открывают обычно.
   Две кнопки в ряд, на узком экране переносятся (flex-wrap). */
.settings-transfer {
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
.settings-transfer-btns { display: flex; flex-wrap: wrap; gap: 8px; }
.settings-transfer-btns button {
  flex: 1 1 120px;
  font-family: var(--font-mono);
  font-size: 12px; letter-spacing: 1px;
  color: var(--teal);
  background: rgba(78,205,196,.08);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 9px 8px;
  cursor: pointer;
}
.settings-transfer-btns button:hover {
  background: rgba(78,205,196,.18);
  border-color: var(--teal);
}
.settings-hint {
  font-size: 11px; line-height: 1.45;
  color: var(--dim, #7c8a99);
  letter-spacing: .3px;
}
/* Пояснение под галочкой (#175): выровнено по её тексту, а не по краю окна —
   иначе читается как отдельный абзац, а не как расшифровка настройки. */
.settings-hint-under { margin: -4px 0 2px 28px; }

/* ─── АР: анимация получения ресурсов ────────────────────────────
   Правый нижний угол ИГРОВОГО ОКНА, а не экрана: слой ложится ВНУТРЬ правого
   нижнего угла ЖУРНАЛА (см. positionResAnimLayer в game.js), поэтому right/top
   здесь — лишь запасные значения на случай, если якорь не найден.
   В слое всегда ровно один значок: когда кредита и Данные приходят разом, второй
   ждёт очереди и выходит на то же место (showNextResourceAnim).
   position:fixed сохранён намеренно: кредит за продажу на Канале обязана
   быть видна поверх окна магазина, а absolute внутри #app ушёл бы под него.
   z-index 9400 — поверх Атласа (9200) и «Настроек» (9300), но ниже профилей
   (9500) и generic-confirm (9600): подтверждения обязаны лечь сверху. Выше
   «Настроек» специально — включил галочку и тут же увидел образец.
   pointer-events:none — слой ничего не перехватывает, игрок продолжает
   кликать по сетке, пока кредит крутится. */
/* Слой во весь экран: значок стартует в его ЦЕНТРЕ и уходит к своему счётчику
   в шапке (заказчик, 29.08.2026). Раньше слой висел в углу журнала, и значок
   просто всплывал на месте — связи с тем, где прибавилось, не было. */
#res-anim-layer {
  position: fixed; inset: 0;
  z-index: 9400;
  pointer-events: none;
  display: flex; align-items: center; justify-content: center;
}
/* Размер приходит из JS (--ar-size ≈ два сектора сетки), длительность и точка
   назначения — тоже (--ar-fx/--ar-fy: смещение от центра экрана до счётчика).
   Две вложенные анимации: внешняя ведёт значок по дороге, внутренняя крутит
   его вокруг своей оси. Одной не обойтись — вращение и перелёт живут в одном
   свойстве transform и затирали бы друг друга. */
.res-fly {
  width: var(--ar-size, 92px); height: var(--ar-size, 92px);
  perspective: 520px;
  color: var(--ar-color, var(--teal));
  filter: drop-shadow(0 0 18px currentColor);
  animation: ar-travel var(--ar-dur, 1400ms) cubic-bezier(.45, .02, .3, 1) forwards;
}
.res-fly-face {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  animation: ar-spin 620ms linear infinite;
}
/* Значок приходит из реестра завёрнутым в <i class="gi">, а тот ростом СО
   СТРОКУ (height: 1em). Внутри летящего диска нужен весь размер, поэтому
   и обёртку, и сам svg растягиваем явно — иначе от «двух секторов» остаётся
   значок в десять пикселей. */
.res-fly .gi { width: 100%; height: 100%; line-height: 0; }
.res-fly .gi > svg { width: 100%; height: 100%; display: block; }

@keyframes ar-spin {
  from { transform: rotateY(0deg); }
  to   { transform: rotateY(360deg); }
}
/* Вспышка в центре, короткая остановка, потом уход к счётчику с уменьшением.
   Остановка обязательна: без неё значок опознать не успеваешь. */
@keyframes ar-travel {
  0%   { opacity: 0; transform: translate(0, 0) scale(.35); }
  14%  { opacity: 1; transform: translate(0, 0) scale(1); }
  46%  { opacity: 1; transform: translate(0, 0) scale(1); }
  100% { opacity: 0; transform: translate(var(--ar-fx, 0), var(--ar-fy, 0)) scale(.22); }
}
/* ПОТЕРЯ СВЯЗНОСТИ. Дорога та же (ar-travel), но лиц два и они сменяют друг
   друга на месте: целая кардиограмма бирюзовым обрывается и краснеет, и уже
   красная уходит к счётчику (заказчик, 30.08.2026). Вращения нет намеренно —
   ресурс прилетает подарком и крутится, а это удар: он должен читаться как
   обрыв, а не как награда. */
.sanity-fly { animation-name: ar-travel-hurt; }
.sanity-fly .res-fly-face { position: absolute; inset: 0; animation: none; }
.sanity-fly .sf-full {
  color: var(--teal); filter: drop-shadow(0 0 18px rgba(78,205,196,.75));
  animation: sf-break var(--ar-dur, 1500ms) ease forwards;
}
.sanity-fly .sf-off {
  color: var(--red); filter: drop-shadow(0 0 18px rgba(231,76,60,.8));
  opacity: 0;
  animation: sf-scar var(--ar-dur, 1500ms) ease forwards;
}
/* Целое лицо: вспышка, короткая остановка — и обрыв (дрожь и гашение). */
@keyframes sf-break {
  0%   { opacity: 0;  transform: scale(.35); }
  10%  { opacity: 1;  transform: scale(1); }
  28%  { opacity: 1;  transform: scale(1); }
  32%  { opacity: 1;  transform: scale(1.06) translateX(-4px); }
  36%  { opacity: 1;  transform: scale(1.06) translateX(4px); }
  44%  { opacity: 0;  transform: scale(.92); }
  100% { opacity: 0;  transform: scale(.92); }
}
/* Оборванное проступает на месте целого и дальше едет с ним заодно. */
@keyframes sf-scar {
  0%,  36% { opacity: 0; transform: scale(1.06); }
  46%      { opacity: 1; transform: scale(.85); }
  60%      { opacity: 1; transform: scale(.85); }
  100%     { opacity: 1; transform: scale(.85); }
}
/* Дорога без начальной вспышки: её отыгрывают сами лица. */
/* Красное деление СТОИТ на месте до 60 % времени и только потом уходит:
   первая редакция начинала полёт на 46 %, и красная фаза целиком проходила уже
   в дороге — на экране мелькал уезжающий след, а не «связность порвалась». */
/* Стоит значок не в центре экрана, а НАД УДАРИВШИМ СЕКТОРОМ (--ar-sx/--ar-sy,
   заказчик 06.09.2026): удар случился в конкретном месте поля, и значок обязан
   выйти оттуда же. Удары, приходящие мимо хода (Возбуждение, Расстройка,
   перегрузка контура, камертон), сектора не имеют — там смещение нулевое и
   значок стартует из середины поля. Конечная точка не меняется:
   --ar-fx/--ar-fy считаются от центра экрана и верны при любом старте. */
@keyframes ar-travel-hurt {
  0%,  60% { opacity: 1; transform: translate(var(--ar-sx, 0), var(--ar-sy, 0)) scale(1); }
  100%     { opacity: 0; transform: translate(var(--ar-fx, 0), var(--ar-fy, 0)) scale(.34); }
}
@media (prefers-reduced-motion: reduce) {
  .res-fly, .res-fly-face { animation-duration: 1ms; }
}

/* ═══ АВАРИЙНОЕ ОТКЛЮЧЕНИЕ: экран при нулевой Связности ═══
   Связность кончилась, играть больше нечем — осталась одна кнопка. Экран
   погружения «временами темнеет, потом светлеет, иногда проходят помехи»
   (заказчик, 06.09.2026): сигнал эхонавта садится, и это видно, не читая
   журнала.

   ЭТАЖ 9100. Выше всего, что лежит на экране погружения (Организации 150,
   Архив 310), и НИЖЕ окон, которые игрок может открыть поверх: Атлас 9200,
   карточка эхонавта 9250, Настройки 9300. Открытое окно аварийка не
   затемняет — там читают текст, а не смотрят на поле.
   pointer-events: none обязателен: под слоем лежит единственная живая кнопка
   экрана, и перехваченный клик оставил бы игрока запертым в слое. */
#emg-layer {
  position: fixed; inset: 0;
  z-index: 9100;
  pointer-events: none;
}
#emg-layer > i { position: absolute; inset: 0; display: block; }

/* Дыхание: ступень «фоновое» (900+ мс). Медленно и без рывков — тревогу уже
   отыграла сирена при взводе, здесь идёт угасание. */
@keyframes emg-breathe {
  0%, 100% { opacity: .10; }
  50%      { opacity: .45; }
}
.emg-dim {
  background: #000;
  opacity: .10;
  animation: emg-breathe 4s ease-in-out infinite;
}

/* Срыв сигнала: сканлайны плюс зерно, включается редко и коротко из JS.
   Полосы теми же 3px/4px, что у глитч-окна подсказок (.hint-glitch::after) —
   помехи в игре должны выглядеть одинаково, откуда бы ни пришли. */
/* Срыв обязан быть ЗАМЕТЕН: он приходит раз в шесть-девять секунд и говорит,
   что связь рвётся. Первая редакция шла одними сканлайнами на .07 и на экране
   читалась как лёгкая сетка — «что-то не так» из неё не следовало. Поэтому у
   срыва теперь и заметный сдвиг развёртки, и провал яркости: сигнал не просто
   рябит, он на мгновение проваливается. */
@keyframes emg-burst {
  0%   { opacity: 0; transform: translateY(-6px); }
  12%  { opacity: .95; }
  40%  { opacity: .4;  transform: translateY(5px); }
  64%  { opacity: .85; transform: translateY(-3px); }
  100% { opacity: 0;   transform: translateY(0); }
}
.emg-static {
  opacity: 0;
  background:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,.10) 0px, rgba(255,255,255,.10) 1px,
      rgba(0,0,0,0) 1px, rgba(0,0,0,0) 3px),
    repeating-linear-gradient(90deg,
      rgba(231,76,60,.06) 0px, rgba(231,76,60,.06) 2px,
      rgba(0,0,0,0) 2px, rgba(0,0,0,0) 5px),
    linear-gradient(rgba(0,0,0,.42), rgba(0,0,0,.42));
}
.emg-static.on { animation: emg-burst 520ms steps(9, end); }

/* Дыхание останавливаем на середине, срывы не показываем вовсе: смысл
   («сигнал сел») держится самим затемнением, а не движением. */
@media (prefers-reduced-motion: reduce) {
  .emg-dim { animation: none; opacity: .3; }
  .emg-static.on { animation: none; }
}

/* Стили видимого чекбокса тест-режима удалены вместе с самим чекбоксом —
   режим включается только читом (10 нажатий по Каналу). */

/* ─── HINT MODAL ────────────────────────────────────── */
/* #166: z-index 9350 — выше Атласа (9200), Профиля (9250) и «Настроек» (9300).
   Было 300: сообщение «АТЛАС ЭФЕМЕРОВ» открывалось ПОД самим Атласом, и игрок
   видел его только после того, как Атлас закрывал — то есть уже не понимая,
   к чему оно относится. Ниже остаются res-anim (9400), экран профилей (9500)
   и generic-confirm (9600) — подтверждения обязаны перекрывать подсказку. */
#hint-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,5,12,.78);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9350;
}
.hint-box {
  width: 700px;
  max-width: 95vw;
  border-radius: 3px;
  font-family: var(--font-mono);
  position: relative;
  overflow: hidden;
}
.hint-header {
  padding: 14px 22px 12px;
  border-bottom: 1px solid;
}
.hint-header-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  letter-spacing: 1.5px;
  margin-bottom: 8px;
  text-transform: uppercase;
}
#hint-label {
  font-size: 18px;
  font-weight: bold;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.hint-body {
  padding: 22px 22px 18px;
  font-size: 20px;
  line-height: 1.7;
  min-height: 80px;
}
.hint-footer {
  display: flex;
  align-items: center;
  /* Кнопка держится ПРАВОГО края, а галочку отодвигает влево её собственная
     распорка (.hint-check { margin-right: auto }). Прежнее space-between делало
     то же самое, пока элементов было два, — но у окна с правилом игры галочки
     нет (#323, noDismiss), и «ПРИНЯТО» уезжала в левый угол. */
  justify-content: flex-end;
  padding: 13px 22px;
  border-top: 1px solid;
  font-size: 16px;
  gap: 12px;
  flex-wrap: wrap;
}
.hint-check {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  flex-shrink: 1;
  min-width: 0;
  margin-right: auto;   /* распорка до кнопки — см. .hint-footer */
}
/* #323: у окна с правилом игры галочки нет (noDismiss). Правило явное: у
   `.hint-check` своё `display: flex`, и одного класса `.hidden` мало — они
   равны по весу, и спор решает порядок в файле. На этом уже обжигались в
   лаборатории текстов. */
.hint-check.hidden { display: none !important; }
.hint-check input { cursor: pointer; accent-color: var(--teal); width: 16px; height: 16px; }
#hint-close {
  background: none;
  border: 1px solid;
  padding: 7px 24px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 20px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  white-space: nowrap;
}
/* normal (teal) */
.hint-normal {
  background: #070f1a;
  border: 1px solid var(--teal);
  color: var(--text);
}
.hint-normal .hint-header         { border-color: rgba(78,205,196,.4); }
.hint-normal .hint-header-top     { color: rgba(78,205,196,.55); }
.hint-normal #hint-label          { color: var(--teal); }
.hint-normal #hint-clearance      { color: rgba(78,205,196,.7); }
.hint-normal .hint-footer         { border-color: var(--border); color: var(--dim); }
.hint-normal #hint-close          { border-color: var(--teal); color: var(--teal); }
.hint-normal #hint-close:hover    { background: rgba(78,205,196,.1); }

/* classified (amber) */
.hint-classified {
  background: #100900;
  border: 1px solid #c8960f;
  color: #e0c06a;
}
.hint-classified .hint-header      { border-color: rgba(200,150,15,.45); background: rgba(200,150,15,.05); }
.hint-classified .hint-header-top  { color: rgba(200,150,15,.6); }
.hint-classified #hint-label       { color: #c8960f; }
.hint-classified #hint-clearance   { color: #c8960f; }
.hint-classified .hint-footer      { border-color: rgba(200,150,15,.3); color: rgba(200,150,15,.6); }
.hint-classified #hint-close       { border-color: #c8960f; color: #c8960f; }
.hint-classified #hint-close:hover { background: rgba(200,150,15,.1); }
.hint-classified .hint-check input { accent-color: #c8960f; }
.hint-censor {
  display: inline-block;
  background: #c8960f;
  color: #c8960f;
  border-radius: 2px;
  padding: 1px 3px;
  letter-spacing: 1px;
  user-select: none;
  font-size: 10px;
  vertical-align: middle;
}

/* glitch (boss — red/error) */
.hint-glitch {
  background: #080000;
  border: 1px solid var(--red);
  color: #ff7070;
  animation: hg-flicker 2.5s infinite;
}
.hint-glitch .hint-header      { border-color: rgba(231,76,60,.4); background: rgba(231,76,60,.04); }
.hint-glitch .hint-header-top  { color: rgba(231,76,60,.65); }
.hint-glitch #hint-label       { color: var(--red); letter-spacing: 3px; }
.hint-glitch #hint-clearance   { display: none !important; }
.hint-glitch .hint-footer      { border-color: rgba(231,76,60,.3); color: rgba(231,76,60,.6); }
.hint-glitch #hint-close       { border-color: var(--red); color: var(--red); }
.hint-glitch #hint-close:hover { background: rgba(231,76,60,.1); }
.hint-glitch .hint-check input { accent-color: var(--red); }
/* scanline overlay */
.hint-glitch::after {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    0deg,
    transparent,
    transparent 3px,
    rgba(0,0,0,.12) 3px,
    rgba(0,0,0,.12) 4px
  );
  pointer-events: none;
}
@keyframes hg-flicker {
  0%,89%,91%,93%,100% { border-color: var(--red); }
  90%,92%             { border-color: transparent; }
}
.glitch-line { display: inline; }

/* #323: ЯСНЫЙ БЛОК ПОСЛЕ ГЛИТЧА. Связь рвётся, а прибор Эхо-Камеры договаривает
   за неё — то самое правило слоя, которого игрок раньше не получал нигде, пока
   сам не находил первый Глаз. Отсюда и вид: не продолжение сломанной передачи,
   а показание прибора — бирюзовый, ровный, за своей чертой.
   Появляется, когда последняя строка глитча дорасшифровалась (класс из JS). */
.glitch-clear {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(78,205,196,.28);
  font-family: var(--font-mono);
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--teal);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 420ms ease, transform 420ms ease;
}
.glitch-clear.shown { opacity: 1; transform: none; }
.glitch-clear > div { position: relative; padding-left: 16px; margin-bottom: 4px; }
.glitch-clear > div:last-child { margin-bottom: 0; }
/* Маркер — не список из трёх пунктов, а три показания подряд: короткая
   засечка вместо точки, тем же цветом и тоньше текста. */
.glitch-clear > div::before {
  content: "";
  position: absolute; left: 0; top: .62em;
  width: 8px; height: 1px;
  background: var(--teal);
  opacity: .6;
}
@media (prefers-reduced-motion: reduce) {
  .glitch-clear { transition: none; transform: none; }
}

/* ─── ARCHIVE MODAL ─────────────────────────────────── */
#archive-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,4,12,.8);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 310;
}
#archive-box {
  /* Панель СТАНЦИИ во всю ширину, а не окошко поверх Организаций: в макете
     Архив — такой же раздел, как Атлас и Эхонавт, и рядом со списком стоит
     колонка «что здесь лежит». В 620 px она не помещалась вовсе. */
  width: var(--station-w, 1060px);
  max-width: 96vw;
  max-height: 86vh;
  background: #060d18;
  border: 1px solid var(--border);
  border-radius: 3px;
  display: flex;
  flex-direction: column;
  font-family: var(--font-mono);
}
#archive-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  letter-spacing: 2px;
  color: var(--teal);
  text-transform: uppercase;
  flex-shrink: 0;
}

#archive-list {
  overflow-y: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* #250: девять ячеек контейнера Ксилла. Заполненная светится, только что
   добавленная коротко вспыхивает — сбор редкий, и он обязан быть заметен. */
.xyll-cells .xyll-pip-on { filter: drop-shadow(0 0 3px rgba(79,216,232,.8)); }
.xyll-cells .xyll-pip-new { animation: xyll-pip-pop var(--t-in) ease-out 2; transform-origin: center; }
@keyframes xyll-pip-pop {
  0%   { opacity: .25; }
  40%  { opacity: 1; filter: drop-shadow(0 0 8px rgba(79,216,232,1)); }
  100% { opacity: 1; }
}

/* #280: карточка «Объект Х» — та же плитка Атласа, но красная и с портретом
   самого эхонавта: это его собственная сигнатура, а не вид Эфира. */
.atlas-card.atlas-card-objx { background: rgba(231,76,60,.04); }
.atlas-card-objx .objx-portrait { object-fit: contain; background: rgba(231,76,60,.06); }
/* Подпись под портретом — ТЕМ ЖЕ шрифтом, что имена видов: класс
   .atlas-card-name стоит на ней вторым, отсюда кегль, жирность и разрядка (и
   мобильные 14px из медиазапроса). Своё здесь только то, что это фраза, а не
   имя: она по центру и переносится по строкам. */
.atlas-card-objx .objx-caption {
  color: #e74c3c; text-align: center; line-height: 1.35;
}
.atlas-card-objx .btn-atlas-decipher { border-color: rgba(231,76,60,.6); color: #e74c3c; }
.atlas-card-objx .btn-atlas-decipher:hover { background: rgba(231,76,60,.15); }
/* #270: запись синего Массива в Архиве — синим краем, как всё скользящее. */
.archive-item.arc-boss-blue { border-left: 3px solid #3b82f6; }

/* #247: кадр Массива в его записи Архива. Ширину держим скромной — запись про
   эффекты, а не галерея, и картинка не должна выдавливать текст за экран. */
.arc-boss-art {
  display: block;
  width: 100%; max-width: 260px;
  border: 1px solid var(--border); border-radius: 3px;
  margin-bottom: 10px;
}

/* #238: переключатель порядка записей. Две кнопки, а не одна с переключением
   надписи: по одной кнопке не видно, какой порядок сейчас, — надпись на ней
   можно прочитать и как «текущий», и как «нажми, чтобы стало». */
.arc-sortbar { display: flex; gap: 6px; margin-bottom: 4px; }
.arc-sort-btn {
  font-family: var(--font-mono);
  font-size: 12px; letter-spacing: 1px; font-weight: bold;
  color: var(--dim); background: transparent;
  border: 1px solid var(--border); border-radius: 3px;
  padding: 6px 10px; cursor: pointer;
}
.arc-sort-btn:hover { color: var(--teal); border-color: var(--teal); }
.arc-sort-btn[data-on] { color: var(--teal); border-color: var(--teal); background: rgba(78,205,196,.12); }

.archive-item {
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 10px 14px;
}
.archive-item-hdr {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}
.archive-item-title {
  font-size: 14px;
  letter-spacing: 1.5px;
  color: var(--teal);
  text-transform: uppercase;
}
.archive-item-ud {
  font-size: 12px;
  color: var(--dim);
}
.archive-ud-err { color: var(--red) !important; }
.archive-item-body {
  font-size: 15px;
  line-height: 1.6;
  color: var(--text);
}
/* ТОН ЗАПИСИ — тот же, что был у окна в игре (заказчик, 29.08.2026): золотой у
   грифованных, красный у сбоя, бирюзовый у обычных. В Архиве все тридцать
   четыре шли одним бирюзовым, и предупреждение читалось как справка. Цвет
   несут заголовок и черта слева — тело остаётся читаемым. */
.archive-item.arc-t-classified { border-left: 3px solid rgba(200,150,15,.6); }
.archive-item.arc-t-classified .archive-item-title { color: #d3a51a; }
.archive-item.arc-t-classified .archive-item-ud    { color: rgba(200,150,15,.75); border-color: rgba(200,150,15,.4); }
.archive-item.arc-t-glitch { border-left: 3px solid rgba(231,76,60,.6); }
.archive-item.arc-t-glitch .archive-item-title { color: #ef7264; }
.archive-item.arc-t-glitch .archive-item-ud    { color: rgba(231,76,60,.75); border-color: rgba(231,76,60,.4); }
.archive-item.arc-t-normal { border-left: 3px solid rgba(78,205,196,.45); }
.archive-item.arc-locked {
  opacity: .35;
  border-style: dashed;
}
.archive-item.arc-locked .archive-item-title { color: var(--dim); }
.archive-item-locked-text { font-style: italic; color: var(--dim); }

/* ─── ARCHIVE TABS ─────────────────────────────────── */
#archive-tabs {
  display: flex;
  gap: 4px;
  padding: 8px 14px 0;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.archive-tab {
  background: rgba(78,205,196,.04);
  border: 1px solid rgba(78,205,196,.25);
  border-bottom: none;
  color: var(--dim);
  padding: 8px 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 1.5px;
  cursor: pointer;
  border-radius: 3px 3px 0 0;
  margin-bottom: -1px;
  transition: background var(--t-tap), color var(--t-tap);
}
.archive-tab:hover { color: var(--teal); background: rgba(78,205,196,.08); }
.archive-tab.active {
  background: #060d18;
  color: var(--teal);
  border-color: rgba(78,205,196,.55);
  border-bottom: 1px solid #060d18;
}

/* ─── ARCHIVE: HELP TAB ─────────────────────────────── */
.help-section { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.help-section-title {
  font-size: 13px;
  letter-spacing: 2.5px;
  color: var(--teal);
  text-transform: uppercase;
  border-bottom: 1px solid rgba(78,205,196,.35);
  padding-bottom: 4px;
  margin-bottom: 2px;
}
.help-intro {
  font-size: 14px;
  color: var(--text);
  line-height: 1.6;
  padding: 10px 14px;
  background: rgba(78,205,196,.06);
  border: 1px solid rgba(78,205,196,.3);
  border-radius: 3px;
}
.help-card {
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: 10px;
  padding: 10px 12px;
  background: rgba(255,255,255,.025);
  border: 1px solid var(--border);
  border-radius: 3px;
  align-items: center;
}
.help-card-locator { border-color: rgba(78,205,196,.5); }
.help-card-echo    { border-color: rgba(240,208,96,.5); }
.help-card-art {
  width: 72px; height: 72px;
  border-radius: 3px;
  background: #050d18;
  object-fit: contain;
}
.help-card-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.help-card-title {
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: bold;
}
.help-card-locator .help-card-title { color: var(--teal); }
.help-card-echo    .help-card-title { color: var(--gold); }
.help-card-cost { font-size: 13px; color: var(--text); opacity: .85; }
.help-card-text { font-size: 13px; line-height: 1.55; color: var(--text); }
.help-card-text b { color: #ffd870; }
.help-row {
  display: grid;
  grid-template-columns: 36px 1fr;
  gap: 10px;
  padding: 8px 10px;
  background: rgba(255,255,255,.02);
  border: 1px solid rgba(78,205,196,.18);
  border-radius: 3px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.help-row b { color: #ffd870; }
.help-bullet {
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  color: var(--teal);
  line-height: 1;
}
.help-bullet-num {
  font-family: var(--font-mono);
  font-weight: bold;
  border: 1px solid var(--teal);
  border-radius: 3px;
  background: #0d1b2a;
  font-size: 16px;
  width: 26px; height: 26px;
}
.help-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.help-list li {
  padding: 6px 10px 6px 22px;
  background: rgba(255,255,255,.02);
  border: 1px solid var(--border);
  border-radius: 3px;
  position: relative;
}
.help-list li::before {
  content: '◆';
  position: absolute;
  left: 8px; top: 6px;
  color: var(--teal);
}

/* ─── MEMBRANE ENTRIES IN ARCHIVE ───────────────────── */
.archive-item.arc-membrane {
  border-color: rgba(78,205,196,.5);
}
.archive-item.arc-summary {
  border-color: rgba(240,208,96,.4);
  background: rgba(240,208,96,.04);
}
/* #178: карточка цвета Эфемеров в Архиве. Рамку не красим в цвет Эфемера —
   заголовок уже несёт его, а цветная рамка на пяти карточках подряд
   превращает список в радугу и мешает читать текст. */
.archive-item.arc-ephemer {
  border-color: rgba(78,205,196,.5);
}
.eph-color-effects {
  font-size: 13px; line-height: 1.5;
  white-space: normal;
}
/* Строка мембраны. Пока это заглушка «?????» — блок намеренно оформлен как
   готовая строка данных, а не как «пусто»: игрок должен видеть, что сведения
   существуют и их предстоит добыть. */
.eph-membrane-slot {
  margin-top: 6px;
  font-size: 13px;
  padding-left: 10px;
  border-left: 2px solid rgba(240,208,96,.35);
}
.eph-membrane-label { color: var(--dim); letter-spacing: .5px; }
.eph-membrane-unknown { color: #f0d060; letter-spacing: 3px; font-weight: bold; }
/* #188: раскрытая мембрана. Рамка ярче, чем у «?????», — по ней видно, где
   знание уже есть, не читая сам текст. */
.eph-membrane-known { border-left-color: rgba(240,208,96,.8); }
.eph-membrane-name { color: #f0d060; font-weight: bold; }
.eph-membrane-name .mem-ic { vertical-align: -2px; }
.eph-membrane-name .mem-ic svg { width: 15px; height: 15px; }
.eph-membrane-effect { margin-top: 3px; line-height: 1.45; }
.mem-symbol-big {
  font-size: 17px;
  color: #f0d060;
  display: inline-block;
  min-width: 18px;
  text-align: center;
}
.mem-code {
  font-size: 11px;
  color: var(--dim);
  letter-spacing: 1px;
}
.mem-summary-line {
  font-size: 13px;
  margin-bottom: 6px;
}
.mem-summary-row {
  margin: 3px 0;
  font-size: 13px;
}
.mem-summary-color {
  display: inline-block;
  min-width: 100px;
  font-weight: bold;
  letter-spacing: 1px;
}
.mem-summary-chip {
  display: inline-block;
  background: rgba(78,205,196,.08);
  border: 1px solid rgba(78,205,196,.25);
  padding: 1px 7px;
  border-radius: 3px;
  font-size: 12px;
  margin-right: 4px;
}
.mem-summary-chip-hidden {
  background: rgba(255,255,255,.04);
  border: 1px dashed rgba(160,200,208,.35);
  color: var(--dim);
  letter-spacing: 2px;
  font-weight: bold;
}
.mem-colors-line {
  margin: 8px 0;
  font-size: 14px;
  color: var(--text);
  letter-spacing: 1px;
}
.mem-colors-line .mem-colors-label {
  color: #ffffff;
  font-weight: bold;
}
.mem-colors-line.mem-colors-none { font-style: italic; color: var(--dim); }
.mem-color-chip {
  display: inline-block;
  border: 1px solid currentColor;
  padding: 2px 8px;
  border-radius: 3px;
  margin-left: 4px;
  font-size: 13px;
  font-weight: bold;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.mem-lore {
  margin-top: 8px;
  color: #a0c8d0;
  font-style: italic;
  font-size: 13px;
  line-height: 1.5;
}
.mem-narrative {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed rgba(78,205,196,.2);
  font-size: 13px;
}

/* #187: подпись «Эффект:» перед самим описанием. Приглушена и разрежена —
   она называет строку, а читать нужно то, что после неё. */
.mem-effect-label {
  display: block;
  font-size: 12px;
  letter-spacing: 2px;
  color: var(--dim, #7c8a99);
  font-weight: normal;
  margin-bottom: 4px;
  text-transform: uppercase;
}
/* #151: эффект мембраны — первым и крупно. Игрок должен сразу понять, что
   произошло; лор и тонкости идут ниже обычным кеглем. */
.mem-effect-lead {
  font-size: 18px;
  line-height: 1.45;
  color: var(--gold);
  font-weight: bold;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: rgba(240,208,96,.07);
  border-left: 3px solid var(--gold);
  border-radius: 0 3px 3px 0;
}

/* ─── MEMBRANE DETAILS BLOCK ────────────────────────── */
.mem-details {
  margin-top: 10px;
  padding: 8px 10px;
  background: rgba(78,205,196,.05);
  border-left: 2px solid rgba(78,205,196,.4);
  border-radius: 0 3px 3px 0;
}
.mem-details-row {
  margin: 4px 0;
  font-size: 13px;
  line-height: 1.5;
}
.mem-details-key {
  color: #4ecdc4;
  font-weight: bold;
  letter-spacing: 0.5px;
}
.mem-details-val { color: var(--text); opacity: .9; }

/* ─── ОТЗВУК на overlay поражения ─────────────────────── */
#btn-overlay-warp {
  display: block;
  width: 100%;
  background: rgba(155,89,182,.18);
  border: 1px solid var(--purple);
  color: var(--purple);
  padding: 12px;
  font-family: var(--font-mono);
  font-size: 18px;
  letter-spacing: 2px;
  border-radius: 3px;
  cursor: pointer;
  margin-bottom: 8px;
  transition: background var(--t-tap);
}
#btn-overlay-warp:hover { background: rgba(155,89,182,.35); }
#btn-overlay-warp.hidden { display: none; }

/* Второстепенная кнопка на экране срыва: уйти к выбору эхонавта.
   Намеренно тише «НОВОГО ПОГРУЖЕНИЯ» — основной сценарий всё-таки играть дальше. */
#btn-overlay-exit {
  display: block;
  margin: 10px auto 0;
  background: none;
  border: 1px solid rgba(120,150,170,.5);
  color: rgba(160,190,205,.85);
  padding: 10px 32px;
  font-family: var(--font-mono);
  font-size: 15px;
  letter-spacing: 2px;
  border-radius: 3px;
  cursor: pointer;
  transition: border-color var(--t-tap), color var(--t-tap);
}
#btn-overlay-exit:hover { border-color: rgba(180,210,225,.9); color: #d6e8f0; }
#btn-overlay-exit.hidden { display: none; }

/* ─── РАСШИФРОВКА эфемера ─────────────────────────────── */
#decipher-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,4,12,.82);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 320;
}
#decipher-box {
  width: 640px;
  max-width: 95vw;
  background: #06100a;
  border: 1px solid var(--teal);
  border-radius: 3px;
  font-family: var(--font-mono);
  padding: 24px 28px;
}
.decipher-header {
  font-size: 12px;
  letter-spacing: 2px;
  color: rgba(78,205,196,.55);
  text-transform: uppercase;
  margin-bottom: 16px;
}
#decipher-body {
  font-size: 18px;
  line-height: 1.7;
  color: var(--text);
  margin-bottom: 24px;
}
.decipher-footer {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}
#btn-decipher-skip {
  background: none;
  border: 1px solid var(--border);
  color: var(--dim);
  padding: 8px 22px;
  font-family: var(--font-mono);
  font-size: 19px;
  letter-spacing: 1px;
  border-radius: 3px;
  cursor: pointer;
}
#btn-decipher-skip:hover { border-color: var(--dim); color: var(--text); }
#btn-decipher-pay {
  background: rgba(78,205,196,.15);
  border: 1px solid var(--teal);
  color: var(--teal);
  padding: 8px 22px;
  font-family: var(--font-mono);
  font-size: 19px;
  letter-spacing: 1px;
  border-radius: 3px;
  cursor: pointer;
}
#btn-decipher-pay:hover { background: rgba(78,205,196,.3); }
#btn-decipher-pay:disabled { opacity: .4; cursor: not-allowed; }
.decipher-mem-note {
  margin-top: 10px;
  padding: 8px 12px;
  border: 1px solid rgba(240,208,96,.5);
  border-radius: 3px;
  background: rgba(240,208,96,.07);
  color: #f0d060;
  font-size: 15px;
  line-height: 1.5;
}

/* ─── MEMBRANE NARRATIVE MODAL ──────────────────────── */
#mem-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,5,12,.78);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 315;
}
#mem-label { font-size: 16px; font-weight: bold; letter-spacing: 2px; text-transform: uppercase; }
#mem-body   { font-size: 17px; }
/* Усиленная мембрана (задание №27): приписка в конце карточки — фиолетовым,
   цветом Массива; строка приза в Атласе и Архиве — тем же цветом. */
#mem-body .mem-boost {
  color: #c8a0e0;
  text-shadow: 0 0 8px rgba(155, 89, 182, .35);
  margin-top: 12px;
}
/* В Атласе строка приза — тем же жёлтым фоном, что «В этом погружении — у …
   эфемеров» (класс atlas-mem-run), и отделена от неё зазором (задание №28). */
.atlas-mem-run.atlas-mem-boost { margin-top: 4px; }
.mem-boost-note {
  color: #c8a0e0;
  font-size: 12px; line-height: 1.4;
  margin-top: 4px;
}
#mem-close  { border-color: #c8960f; color: #c8960f; }
#mem-close:hover { background: rgba(200,150,15,.1); }
#mem-close {
  background: none;
  border: 1px solid;
  padding: 7px 24px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}

/* ─── ЭФ. КАРТОЧКА: заблокированный вид (до расшифровки) ─ */
.eph-locked-tile {
  width: 50px;
  height: 50px;
  background-color: #0d1b2a;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12'><rect x='0' y='0' width='5' height='3' fill='%2314253c'/><rect x='6' y='0' width='6' height='4' fill='%23091420'/><rect x='0' y='4' width='4' height='4' fill='%231a3050'/><rect x='5' y='3' width='4' height='5' fill='%23091420'/><rect x='9' y='5' width='3' height='4' fill='%23172b42'/><rect x='0' y='8' width='3' height='4' fill='%23091420'/><rect x='4' y='8' width='5' height='4' fill='%2314253c'/><rect x='9' y='9' width='3' height='3' fill='%231a3050'/></svg>");
  background-size: 12px 12px;
  border: 1px solid rgba(78,205,196,.25);
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: rgba(78,205,196,.4);
  flex-shrink: 0;
  cursor: help;
}

/* Эмблема текущего прохождения на заглушке. Дешифровка привязана к кампании,
   и символ показывает, чья база данных сейчас в работе. Приглушена, чтобы
   читалась как водяной знак, а не как активная иконка. */
.locked-tile-emblem {
  width: 34px; height: 34px;
  object-fit: contain;
  opacity: .55;
  filter: grayscale(.35);
}

.free-decipher-tile { border-color: rgba(240,208,96,.6) !important; background-color: #1a1400 !important; }
.free-decipher-badge { font-size: 10px; font-weight: bold; color: #f0d060; letter-spacing: .5px; }
/* #105: цена расшифровки прямо на квадрате, скрывающем форму */
.locked-tile-cost {
  font-size: 11px;
  font-weight: 700;
  line-height: 1.05;
  text-align: center;
  color: rgba(78,205,196,.85);
  text-shadow: 0 1px 2px #000;
}

/* ─── Шрифт расходников в слоте (оборудование) ─────── */
.equip-slot .card-name {
  font-size: 10px !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  letter-spacing: 0.3px;
}
.equip-slot .equip-type-badge { font-size: 10px; }

/* ─── ИСКАЖЕНИЕ: баннер во вкладке СИГНАТУРЫ (#122) ────────── */
#inversion-banner, #sp-inversion-banner {
  background: rgba(155, 89, 182, 0.18);
  border: 1px solid #9b59b6;
  border-radius: 3px;
  color: #c77dff;
  font-size: 13px;
  font-weight: bold;
  letter-spacing: 0.5px;
  padding: 5px 10px;
  text-align: center;
  margin: 4px 0;
  animation: inversion-pulse 1.5s ease-in-out infinite;
}
@keyframes inversion-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.65; }
}
/* Значок Данных в текстовых строках (витрина, Атлас, цены) — см. bug.md 212.
   Размер в em, а не в пикселях: рядом стоят эмодзи-символы ресурсов, а они
   растут вместе с font-size строки. Фиксированный размер выглядел мельче
   соседей в каждой из строк — у них разный кегль (18 px в строке ресурсов,
   15 px в ценах). 1.1em выравнивает значок с ними по внешнему диаметру. */
.oi-ico { width: 1.1em; height: 1.1em; vertical-align: -0.22em; }

/* ─── КОНТУР: предупреждение при переполнении ─────── */
.battery-warn #bat-label,
.battery-warn #bat-val {
  color: #e74c3c;
}

/* ─── ОНБОРДИНГ: стартовый инструктаж ───────────────── */
#onboard-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.78);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}
#onboard-overlay.hidden { display: none; }
#onboard-box {
  background: #0d1b2a;
  border: 1px solid #4ecdc4;
  border-radius: 3px;
  padding: 28px 32px 24px;
  max-width: 520px;
  width: 90%;
  box-shadow: 0 0 40px rgba(78,205,196,0.2);
}
#onboard-title {
  font-size: 17px;
  font-weight: bold;
  color: #4ecdc4;
  letter-spacing: 2px;
  text-align: center;
  margin-bottom: 20px;
}
#onboard-rules { display: flex; flex-direction: column; gap: 12px; }
.onboard-rule {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  color: #a8c0cc;
  line-height: 1.5;
}
.onboard-rule b { color: #e0e8ef; }
.onboard-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  background: #132030;
  border: 1px solid #4ecdc4;
  border-radius: 3px;
  color: #4ecdc4;
  font-size: 14px;
  font-weight: bold;
  flex-shrink: 0;
  font-family: monospace;
}
.onboard-icon {
  min-width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
}
#onboard-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 22px;
  gap: 12px;
}
.onboard-skip-label {
  font-size: 13px;
  color: #5a7888;
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
#btn-onboard-start {
  background: #4ecdc4;
  color: #060b18;
  border: none;
  border-radius: 3px;
  padding: 9px 24px;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 1.5px;
  cursor: pointer;
  font-family: monospace;
}
#btn-onboard-start:hover { background: #38b2aa; }

/* ─── ПРОДАЖА ОБОРУДОВАНИЯ ───────────────────────────────────────── */
.card-sell-btn {
  position: absolute;
  bottom: 4px;
  right: 4px;
  background: rgba(240,208,96,.12);
  border: 1px solid rgba(240,208,96,.4);
  color: #f0d060;
  font-size: 9px;
  font-family: var(--font-mono);
  padding: 2px 5px;
  border-radius: 3px;
  cursor: pointer;
  line-height: 1.3;
  letter-spacing: 0.3px;
  transition: background var(--t-tap);
}
.card-sell-btn:hover { background: rgba(240,208,96,.28); }

/* ─── АКТИВНЫЙ ИНСТРУМЕНТ-ЭКИПИРОВКА ────────────────────────────── */
.equip-pending .card-inner { outline: 1px solid rgba(240,208,96,.5); }

/* Стилей главного меню здесь больше нет: экран убран из потока 29.08.2026,
   его место занял экран «Эхонавт» (см. «КАРТОЧКА ЭХОНАВТА НА СТАНЦИИ»). */

/* ─── Вкладка перехвачена другой вкладкой того же профиля ────────── */
#stale-tab-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.94);
  display: flex; align-items: center; justify-content: center;
  z-index: 9700;
  font-family: var(--font-mono);
  padding: 16px;
}
#stale-tab-overlay.hidden { display: none; }
#stale-tab-box {
  width: 440px; max-width: 92vw;
  padding: 28px;
  background: #051120;
  border: 2px solid rgba(255,214,102,.55);
  border-radius: 3px;
  box-shadow: 0 0 40px rgba(255,214,102,.15);
  text-align: center;
}
#stale-tab-title {
  font-size: 18px; font-weight: bold; letter-spacing: 3px;
  color: #ffd666;
  margin-bottom: 12px;
}
#stale-tab-text {
  font-size: 14px; line-height: 1.6;
  color: rgba(78,205,196,.75);
  margin-bottom: 20px;
}
#btn-stale-tab-reload {
  background: rgba(78,205,196,.08);
  border: 2px solid rgba(78,205,196,.5);
  color: #4ecdc4;
  font-family: var(--font-mono);
  font-size: 15px; font-weight: bold; letter-spacing: 2px;
  padding: 11px 22px;
  border-radius: 3px;
  cursor: pointer;
}
#btn-stale-tab-reload:hover { background: rgba(78,205,196,.18); border-color: rgba(78,205,196,.9); }

/* ─── Экран выбора профиля ───────────────────────────────────────── */
#profile-overlay {
  position: fixed; inset: 0;
  background: radial-gradient(circle at 50% 40%, #0a1830 0%, #040a14 80%);
  display: flex; align-items: center; justify-content: center;
  z-index: 9500;
  font-family: var(--font-mono);
  padding: 16px;
}
#profile-overlay.hidden { display: none; }
#profile-box {
  width: 480px;
  max-width: 92vw;
  max-height: 90vh;
  overflow-y: auto;
  padding: 32px 32px 24px;
  background: #051120;
  border: 2px solid rgba(78,205,196,.4);
  border-radius: 3px;
  box-shadow: 0 0 50px rgba(78,205,196,.18);
  text-align: center;
}
#profile-title {
  font-size: 22px;
  font-weight: bold;
  letter-spacing: 3px;
  color: #4ecdc4;
  text-shadow: 0 0 12px rgba(78,205,196,.45);
}
#profile-sub {
  margin: 8px 0 22px;
  font-size: 13px;
  line-height: 1.5;
  color: rgba(78,205,196,.55);
}
#profile-list { display: flex; flex-direction: column; gap: 10px; }
.profile-item {
  display: flex; align-items: center; gap: 10px;
  background: rgba(78,205,196,.07);
  border: 2px solid rgba(78,205,196,.45);
  border-radius: 3px;
  padding: 12px 14px;
  cursor: pointer;
  text-align: left;
  transition: background var(--t-tap), border-color var(--t-tap);
  /* Якорь для звёздочки полной версии (#180) — она ложится в угол абсолютом. */
  position: relative;
}
/* #180: полная версия открыта (введён код). Абсолют, а не элемент потока:
   строка профиля — flex, и обычный элемент сдвинул бы крестик удаления и
   отъел ширину у имени, которое на телефоне и так режется многоточием.
   pointer-events:none — клик по звезде обязан выбирать профиль, как по всей
   строке, а не проваливаться в никуда. */
.profile-item-star {
  position: absolute; top: 4px; right: 6px;
  font-size: 15px; line-height: 1;
  color: #ffd666;
  text-shadow: 0 0 8px rgba(255,214,102,.75);
  pointer-events: none;
}
.profile-item:hover { background: rgba(78,205,196,.16); border-color: rgba(78,205,196,.9); }
.profile-item.profile-active { border-color: rgba(255,214,102,.75); }
/* Имя + прогресс + рекорды колонкой. min-width:0 обязателен — без него длинное
   имя распирает flex-строку и выдавливает кнопку удаления за край карточки. */
.profile-item-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 3px;
}
.profile-item-name {
  font-size: 18px; font-weight: bold; letter-spacing: 1px;
  color: #4ecdc4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Строка автосейва — служебная, самая мелкая и приглушённая в карточке. */
.profile-item-sub {
  font-size: 12px;
  color: rgba(78,205,196,.55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Строка 2 — уровень Эхонавта. Золото то же, что у «★ ЛИЧНЫЙ РЕКОРД»
   в итогах слоя: один язык для достижений. */
.profile-item-level {
  color: var(--gold);
  font-size: 14px;
  font-weight: normal;
  letter-spacing: .5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Портрет испытателя: квадрат слева от текста. flex:0 0 auto — картинка не
   сжимается и не растягивается, что бы ни творилось с длиной имени.
   Фон и рамка нужны на случай, если файл не загрузился: остаётся аккуратный
   квадрат, а не рваная иконка «битой картинки». */
.profile-item-ava {
  flex: 0 0 auto;
  width: 56px; height: 56px;
  border-radius: 3px;
  border: 1px solid rgba(78,205,196,.35);
  background: #061726;
  object-fit: cover;
}
.profile-item.profile-active .profile-item-ava { border-color: rgba(255,214,102,.7); }
/* Ярлык «новый» удалён вместе с узлом: строка уровня пишет «Новый
   эхонавт» — ярлык был дословным повтором (renderProfileList). */
/* Действия карточки: переименовать и удалить. Колонкой у правого края, чтобы
   не растягивать карточку по высоте и не спорить с портретом слева. */
.profile-item-acts {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 2px;
}
.profile-act {
  background: none; border: none;
  color: rgba(78,205,196,.55);
  font-family: var(--font-mono);
  font-size: 17px; line-height: 1;
  padding: 6px 7px;
  cursor: pointer;
  border-radius: 3px;
}
.profile-act:hover { color: #4ecdc4; background: rgba(78,205,196,.14); }
.profile-act-del { color: rgba(255,107,107,.55); }
.profile-act-del:hover { color: #ff6b6b; background: rgba(255,107,107,.12); }

/* Свободный слот. Сам себе кнопка «завести эхонавта»: отдельной кнопки
   «+ Новый» под списком больше нет — три занятых слота и есть ответ на вопрос,
   почему четвёртого не завести. Высота как у занятой карточки, чтобы список
   не прыгал при удалении. */
.profile-slot-empty {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 82px;
  background: rgba(78,205,196,.04);
  border: 2px dashed rgba(78,205,196,.35);
  border-radius: 3px;
  color: rgba(78,205,196,.6);
  font-family: var(--font-mono);
  font-size: 15px; letter-spacing: 1px;
  cursor: pointer;
  transition: background var(--t-tap), border-color var(--t-tap), color var(--t-tap);
}
.profile-slot-empty:hover {
  background: rgba(78,205,196,.12);
  border-color: rgba(78,205,196,.75);
  color: #4ecdc4;
}
.pse-plus { font-size: 22px; font-weight: bold; line-height: 1; }

/* ─── КОД ДОСТУПА В ШАПКЕ ЭКРАНА ──────────────────────────────────
   Код — это логин игрока. Показан целиком: его диктуют себе на второе
   устройство, а прятать звёздочками то, что игрок и так знает, — пустой жест. */
#profile-account {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 8px;
  margin: 0 0 18px;
  padding: 9px 12px;
  border: 1px solid rgba(78,205,196,.25);
  border-radius: 3px;
  background: rgba(78,205,196,.05);
}
#profile-account.hidden { display: none; }
.pacc-label { font-size: 11px; letter-spacing: 2px; color: rgba(78,205,196,.5); }
#profile-code {
  font-size: 18px; font-weight: bold; letter-spacing: 4px;
  color: var(--gold, #f0d060);
}
/* «не сохранён здесь» — это не код, а объяснение: тем же кеглем, что подпись,
   и без золота, иначе читается как настоящий код доступа. */
#profile-code.pacc-unknown {
  font-size: 12px; font-weight: normal; letter-spacing: 1px;
  color: rgba(200,220,235,.5);
}
.pacc-link {
  background: none; border: none;
  border-bottom: 1px dashed rgba(78,205,196,.5);
  color: rgba(78,205,196,.75);
  font-family: var(--font-mono);
  font-size: 13px;
  padding: 0 1px 1px;
  cursor: pointer;
}
.pacc-link:hover { color: #4ecdc4; border-bottom-color: #4ecdc4; }

/* Одна строка о синхронизации вместо прежнего блока «на сервере»: игрок должен
   видеть, что прогресс общий, но не разбираться в устройстве хранилища. */
#profile-sync {
  margin-top: 14px;
  min-height: 16px;
  font-size: 12px; line-height: 1.4;
  color: rgba(78,205,196,.55);
}
#profile-sync.psync-ok   { color: rgba(78,205,196,.7); }
#profile-sync.psync-wait { color: rgba(78,205,196,.5); }
#profile-sync.psync-warn { color: #ffd666; }

/* ─── ВВОД ИМЕНИ ПРЯМО В СЛОТЕ ────────────────────────────────────
   Карточка на время ввода превращается в форму: портрет на месте, вместо имени
   поле, вместо ✎/✕ — ✓/✕. Прежняя форма под списком удалена: она висела всегда
   и не показывала, к какому слоту относится. */
.profile-item-form { cursor: default; border-color: rgba(78,205,196,.9); }
.profile-form-label {
  font-size: 11px; letter-spacing: 1px;
  color: rgba(78,205,196,.55);
  margin-bottom: 4px;
}
.profile-form-input {
  width: 100%; box-sizing: border-box;
  background: #030a14;
  border: 1px solid rgba(78,205,196,.6);
  border-radius: 3px;
  color: #4ecdc4;
  font-family: var(--font-mono);
  font-size: 17px;
  letter-spacing: 1px;
  padding: 7px 10px;
}
.profile-form-input:focus { outline: none; border-color: rgba(78,205,196,.95); }
.profile-act-ok { color: rgba(120,230,180,.85); font-size: 19px; }
.profile-act-ok:hover { color: #7ee6b4; background: rgba(120,230,180,.14); }
#profile-storage-warn {
  margin-top: 16px;
  font-size: 12px; line-height: 1.4;
  color: #ffd666;
}
#profile-storage-warn.hidden { display: none; }
/* Стили главного меню кончились здесь: галочка подсказок и «Режим игры»
   переехали в карточку эхонавта (.pcard-set-row), заглавный кадр и логотип
   ушли вместе с экраном 29.08.2026. Строка режима теперь набрана как остальные
   настройки карточки, а не кеглем имени: она стоит среди них, а не одна. */

/* ─── ДОСТИЖЕНИЯ ────────────────────────────────────────────────── */
/* z-index 9260 — ВЫШЕ Профиля (9250): достижения открываются из его подвала и
   обязаны лечь поверх, иначе окно «открылось» бы под уже видимым Профилем. */
#achievements-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.85);
  display: flex; align-items: center; justify-content: center;
  z-index: 9260;
  font-family: var(--font-mono);
}
#achievements-overlay.hidden { display: none; }
#achievements-box {
  width: 480px; max-width: 92vw;
  background: #051120;
  border: 2px solid rgba(240,208,96,.45);
  border-radius: 3px;
  padding: 18px 22px 20px;
  box-shadow: 0 0 36px rgba(240,208,96,.18);
}
#achievements-header {
  display: flex; justify-content: space-between; align-items: center;
  border-bottom: 1px solid rgba(240,208,96,.2);
  padding-bottom: 10px;
  margin-bottom: 14px;
  color: #f0d060;
  font-size: 16px;
  letter-spacing: 3px;
}
#achievements-close {
  background: none; border: none; color: #f0d060;
  font-size: 18px; cursor: pointer;
}
#achievements-header-actions { display: flex; align-items: center; gap: 12px; }
#achievements-list { display: flex; flex-direction: column; gap: 10px; }

/* ─── АТЛАС ЭФЕМЕРОВ ─────────────────────────────────────────────
   Каркас взят с #shop-overlay (бокс 1100px, цветные табы сверху).
   z-index 9200 — выше и Организаций (150), и главного меню (9000), и достижений
   (9100): Атлас открывается из обоих мест и обязан лежать поверх. Ниже экрана
   профилей (9500) и generic-confirm (9600) — сообщения о премиях должны
   перекрывать сам Атлас. */
#atlas-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.94);
  display: flex; align-items: center; justify-content: center;
  z-index: 9200;
  overflow-y: auto;
  padding: 20px;
}
#atlas-overlay.hidden { display: none; }
#atlas-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: var(--station-w, 1060px); max-width: 100%;
  padding: 24px 28px;
  box-shadow: 0 0 60px rgba(78,205,196,.2);
  max-height: calc(100vh - 40px);
  display: flex; flex-direction: column;
}
#atlas-header {
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  padding-bottom: 12px; margin-bottom: 14px;
}
#atlas-title { font-size: 26px; letter-spacing: 4px; color: var(--teal); }
#atlas-header-right { display: flex; align-items: center; gap: 16px; }
#atlas-progress { font-size: 15px; color: var(--dim); letter-spacing: 1px; }
/* #255: счётчик нерасшифрованных под счётчиком открытых, у правого края шапки.
   Мигает той же анимацией, что и отметки на кнопках подвала Организаций. */
#atlas-progress-col { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
#atlas-undeciphered {
  font-size: 13px; letter-spacing: 1px; font-weight: bold;
  color: var(--gold);
  animation: sf-badge-blink 1.1s ease-in-out infinite;
}
#atlas-undeciphered.hidden { display: none; }
#atlas-oi { font-size: 18px; }


/* ═══ РАЗДЕЛЫ АТЛАСА (#222) ═══════════════════════════════════════
   Верхний ряд вкладок: «ЭФЕМЕРЫ» (карточки) и «СЛОИ» (статистика). Стоит над
   фильтром по цвету и крупнее его — это переключение раздела, а не фильтра. */
#atlas-view-tabs {
  display: flex; gap: 6px; margin-bottom: 10px;
  border-bottom: 1px solid var(--border); padding-bottom: 10px;
}
.atlas-view-tab {
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 2px; font-weight: bold;
  color: var(--dim); background: transparent;
  border: 1px solid transparent; border-radius: 3px;
  padding: 6px 16px; cursor: pointer;
}
.atlas-view-tab:hover { color: var(--teal); background: rgba(255,255,255,.05); }
.atlas-view-tab.active {
  color: var(--teal); border-color: var(--teal);
  background: rgba(78,205,196,.10);
}

/* #254: список слоёв прокручивается ВНУТРИ окна, как и сетка эфемеров.
   Без этого правила строки, не влезшие в высоту экрана, уезжали НАРУЖУ, ниже
   рамки #atlas-box: у бокса стоит max-height и flex-direction: column, а у
   этого контейнера не было ни одного правила вовсе. Выглядело как «рамка не
   расширилась на слой Массива», хотя Массив был просто той строкой, которая
   переполнила экран, — со следующим слоем повторилось бы и без него.
   min-height: 0 обязателен: без него flex-элемент не сжимается ниже
   содержимого и прокрутка не включается. */
#atlas-layers {
  overflow-y: auto;
  min-height: 0;
  padding-right: 4px;
}

/* Строка слоя. Три счётчика в ряд, под ними табличка рейтингов: рекорд и
   среднее по каждому из двух. Никогда не в две строки не требуется — здесь
   это блок, а не строка интерфейса, — но счётчики не переносятся поодиночке:
   flex-wrap рвёт их только целыми парами «подпись + число». */
.atlas-layer-row {
  position: relative;
  border: 1px solid var(--border); border-left: 3px solid var(--teal);
  border-radius: 3px; padding: 10px 12px; margin-bottom: 8px;
  background: rgba(255,255,255,.03);
}
/* #236: подарок Ордена за слой — в правом верхнем углу строки, чтобы не резать
   ни название, ни счётчики. Оправа синяя, как всё, что от Ордена. */
.alr-gift {
  position: absolute; top: 10px; right: 12px;
  width: 56px; height: 56px; padding: 0; cursor: pointer;
  border: 1px solid rgba(79,176,255,.5); border-radius: 3px;
  background: rgba(79,176,255,.08);
  box-shadow: 0 0 10px rgba(79,176,255,.18);
}
.alr-gift img { width: 100%; height: 100%; border-radius: 3px; display: block; }
/* Плашка «награда Ордена» в карточке предмета — синяя, а не золотая: золото
   в этом окне означает цену, а у подарка Ордена цены нет. */
#ebm-price-badge.ebm-orden {
  color: #4fb0ff; border-color: rgba(79,176,255,.55); background: rgba(79,176,255,.10);
}
.alr-gift:hover { border-color: #4fb0ff; box-shadow: 0 0 16px rgba(79,176,255,.4); }
.atlas-layer-row.alr-boss { border-left-color: var(--gold); }
/* Кегль — как в окне вердикта (#overlay-stats, 17px): это такой же отчёт, и
   мельче он читаться не должен. */
.alr-title {
  font-family: var(--font-mono); font-weight: bold;
  font-size: 18px; color: var(--teal); margin-bottom: 6px;
}
.atlas-layer-row.alr-boss .alr-title { color: var(--gold); }
.alr-counts {
  display: flex; flex-wrap: wrap; gap: 4px 22px;
  font-size: 17px; color: #a8c4d4; margin-bottom: 8px;
}
.alr-counts b { font-variant-numeric: tabular-nums; color: #dbe9f2; }
.alr-counts b.alr-ok  { color: #2ecc71; }
.alr-counts b.alr-bad { color: #e74c3c; }
.alr-k { color: var(--dim); }
/* Таблица рейтингов прижата ВЛЕВО, к названию слоя: растянутая на всю
   ширину карточки, она уводила цифры к правому краю и рвала связь между
   строкой и её числами. */
.alr-grid {
  display: grid; grid-template-columns: max-content 86px 86px;
  justify-content: start;
  gap: 3px 22px; align-items: baseline;
  font-size: 17px;
}
.alr-h    { font-size: 14px; letter-spacing: 1px; color: var(--dim); text-align: right; }
.alr-name { color: #a8c4d4; }
.alr-val  { text-align: right; font-variant-numeric: tabular-nums; font-weight: bold; }
.alr-val.alr-inst { color: var(--gold); }
.alr-val.alr-dim  { color: var(--dim); font-weight: normal; }
/* Раздел «СЛОИ» гасит справку по цвету и плашку последнего действия жёстче,
   чем их собственный .hidden: renderAtlas и дешифровка ставят их обратно. */
#atlas-color-desc.force-hide, #atlas-msg.force-hide { display: none; }

#atlas-color-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.atlas-color-tab {
  font-family: var(--font-mono);
  font-size: 12px; letter-spacing: 1px; font-weight: bold;
  color: var(--dim); background: rgba(255,255,255,.03);
  border: 1px solid var(--border); border-radius: 3px;
  padding: 6px 14px; cursor: pointer;
}
.atlas-color-tab:hover { background: rgba(255,255,255,.07); }
.atlas-color-tab.active { color: #0b1a2a; background: var(--teal); border-color: var(--teal); }
/* Активная вкладка окрашивается в свой цвет — так видно, какой раздел открыт. */
.atlas-color-tab[data-color="green"].active  { background: #2ecc71; border-color: #2ecc71; }
.atlas-color-tab[data-color="yellow"].active { background: #f39c12; border-color: #f39c12; }
.atlas-color-tab[data-color="red"].active    { background: #e74c3c; border-color: #e74c3c; }
.atlas-color-tab[data-color="blue"].active   { background: #4ecdc4; border-color: #4ecdc4; }
.atlas-color-tab[data-color="purple"].active { background: #9b59b6; border-color: #9b59b6; }

/* Справка по цвету под вкладками. Цвет левой полосы задаётся из JS по выбранной
   вкладке — так шапка отвечает на переключение так же явно, как сами табы. */
#atlas-color-desc {
  /* pre-line: справка построчная («Зонд: …» / «Эхолуч: …»), переносы значимы. */
  white-space: pre-line;
  font-size: 13px;
  line-height: 1.55;
  color: #a8c4d4;
  background: rgba(255,255,255,.03);
  border: 1px solid var(--border);
  border-left: 3px solid var(--teal);
  border-radius: 3px;
  padding: 9px 12px;
  margin-bottom: 12px;
  flex: none;
}
#atlas-color-desc.hidden { display: none; }

#atlas-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 12px;
  overflow-y: auto;
  padding-right: 4px;
  margin-bottom: 16px;
}
#atlas-empty {
  text-align: center; color: var(--dim); font-size: 16px;
  padding: 40px 20px; line-height: 1.6;
}
#atlas-empty.hidden { display: none; }

.atlas-card {
  background: rgba(255,255,255,.02);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 12px;
  display: flex; flex-direction: column; gap: 8px;
  position: relative;
  perspective: 700px;          /* глубина для переворота плашки бонуса */
}
.atlas-card-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.atlas-card-id   { font-size: 12px; color: var(--dim); letter-spacing: 1px; }
.atlas-card-name { font-size: 16px; letter-spacing: 1px; font-weight: bold; }
.atlas-card-color { font-size: 12px; color: var(--dim); letter-spacing: 1px; }

/* Силуэт формы. Рисуется программно (SVG) — артов эфемеров в проекте нет.
   Если позже появится img/ephemerals/*.webp, картинка ляжет поверх силуэта. */
/* Высота зоны арта фиксирована: силуэты от 1 до 5 секторов в высоту, и без этого
   строки статистики и кнопки «Расшифровать» разъезжаются по вертикали внутри
   одного ряда сетки (самая высокая форма — 5×16px = 80px). */
.atlas-card-art {
  position: relative; display: flex;
  justify-content: center; align-items: center;
  height: 86px; flex-shrink: 0;
}
.atlas-shape-svg { display: block; }
.atlas-card-photo {
  position: absolute; inset: 0; margin: auto;
  max-width: 100%; max-height: 100%; object-fit: contain;
}

.atlas-card-stats { display: flex; flex-direction: column; gap: 3px; font-size: 13px; color: var(--dim); }
.atlas-stat-row { display: flex; justify-content: space-between; gap: 8px; }
.atlas-stat-val { color: #cfe6f5; }

/* Прогресс-бар этапа: 3 → 5 → 7 полных открытий. Первый порог даёт бонус
   1-го уровня, второй — 2-го, третий открывает приз. */
.atlas-progress-wrap { display: flex; flex-direction: column; gap: 4px; }
.atlas-progress-label { font-size: 11px; color: var(--dim); letter-spacing: 1px; }
.atlas-progress-pips { display: flex; gap: 3px; }
.atlas-pip {
  flex: 1; height: 7px; border-radius: 2px;
  background: rgba(255,255,255,.07);
  border: 1px solid var(--border);
}
.atlas-pip.filled { border-color: transparent; }
.atlas-progress-done { color: var(--gold); font-size: 11px; letter-spacing: 1px; }

/* Действие прижато к низу карточки: блок прогресса на 4-м этапе схлопывается в
   одну строку, и без этого кнопки в ряду вставали на разной высоте. */
.btn-atlas-decipher {
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 1px;
  color: var(--teal); background: rgba(78,205,196,.08);
  border: 1px solid var(--teal); border-radius: 3px;
  padding: 7px 10px; cursor: pointer; width: 100%;
  min-height: var(--btn-min-h, 32px);
  margin-top: auto;
}
.btn-atlas-decipher:hover:not(:disabled) { background: rgba(78,205,196,.2); }
.btn-atlas-decipher:disabled { opacity: .4; cursor: default; }
.btn-atlas-decipher.free { color: var(--gold); border-color: var(--gold); background: rgba(240,208,96,.1); }
.atlas-deciphered-mark {
  text-align: center; font-size: 13px; color: var(--green);
  letter-spacing: 1px; padding: 7px 0;
  margin-top: auto;
}

/* ═══ ОКНО ПРИЗА (третий порог карточки) ═══
   z-index 9280 — над Атласом (9200) и Профилем (9250), под «Настройками» (9300),
   чтобы Esc по-прежнему открывал настройки, а не спорил с этим окном. */
#atlas-prize-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.85);
  display: flex; align-items: center; justify-content: center;
  z-index: 9280;
  font-family: var(--font-mono);
  padding: 16px;
}
#atlas-prize-overlay.hidden { display: none; }
#atlas-prize-box {
  width: 460px; max-width: 92vw; max-height: 88vh; overflow-y: auto;
  background: #051120;
  border: 2px solid rgba(240,208,96,.45);
  border-radius: 3px;
  padding: 16px 20px 18px;
  box-shadow: 0 0 36px rgba(240,208,96,.18);
}
#atlas-prize-header {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
  border-bottom: 1px solid rgba(240,208,96,.2);
  padding-bottom: 10px; margin-bottom: 14px;
}
#atlas-prize-title { color: #f0d060; font-size: 16px; letter-spacing: 3px; }
#atlas-prize-sub   { font-size: 12px; letter-spacing: 1px; margin-top: 5px; color: var(--dim); }
#atlas-prize-close {
  background: none; border: none; color: #f0d060;
  font-size: 18px; cursor: pointer; line-height: 1;
}
#atlas-prize-body { font-size: 13px; line-height: 1.55; color: var(--fg, #cfe3ee); }
.atlas-prize-kind {
  display: inline-block; font-size: 11px; letter-spacing: 2px;
  color: #f0d060; border: 1px solid rgba(240,208,96,.4);
  border-radius: 3px; padding: 2px 8px; margin-bottom: 8px;
}
.atlas-prize-name { font-size: 15px; font-weight: bold; margin-bottom: 8px; }
.atlas-prize-art  { display: block; max-width: 100%; margin: 0 auto 10px; border-radius: 3px; }
.atlas-prize-desc { margin-bottom: 10px; }
.atlas-prize-note { font-size: 11px; color: var(--dim); line-height: 1.45; }
#atlas-prize-btns { display: flex; gap: 10px; margin-top: 16px; }
#atlas-prize-btns button {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 1px;
  border-radius: 3px; padding: 9px 10px; cursor: pointer;
  min-height: var(--btn-min-h, 32px);
}
#btn-atlas-prize-take {
  color: #0b1a2a; background: var(--gold); border: 1px solid var(--gold);
}
#btn-atlas-prize-take:hover:not(:disabled) { filter: brightness(1.1); }
#btn-atlas-prize-take:disabled { opacity: .5; cursor: default; }
#btn-atlas-prize-take.hidden { display: none; }
#btn-atlas-prize-skip {
  color: var(--teal); background: rgba(78,205,196,.08);
  border: 1px solid var(--teal);
}
#btn-atlas-prize-skip:hover { background: rgba(78,205,196,.2); }

#btn-atlas-continue {
  font-family: var(--font-mono);
  font-size: 17px; letter-spacing: 2px;
  color: #0b1a2a; background: var(--teal);
  border: none; border-radius: 3px;
  padding: 12px; cursor: pointer; width: 100%;
  flex-shrink: 0;
}
#btn-atlas-continue:hover { filter: brightness(1.1); }

/* ═══ ПРОФИЛЬ ЭХОНАВТА (#159–#163) ═══
   z-index 9250 — над Организациями (150) и Атласом (9200), под «Настройками»
   (9300), экраном профилей (9500) и generic-confirm (9600): подтверждение
   продажи обязано перекрывать само окно. */
#pcard-overlay {
  position: fixed; inset: 0;
  background: rgba(3,7,16,.94);
  display: flex; align-items: center; justify-content: center;
  z-index: 9250;
  overflow-y: auto;
  padding: 20px;
}
#pcard-overlay.hidden { display: none; }
#pcard-box {
  background: var(--panel);
  border: 1px solid var(--teal);
  border-radius: 3px;
  width: var(--station-w, 1060px); max-width: 100%;
  padding: 24px 28px;
  box-shadow: 0 0 60px rgba(78,205,196,.2);
  max-height: calc(100vh - 40px);
  display: flex; flex-direction: column;
}
#pcard-header {
  display: flex; align-items: center; gap: 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 12px; margin-bottom: 14px;
}
#pcard-ava {
  width: 56px; height: 56px; flex-shrink: 0;
  border: 1px solid var(--border); border-radius: 3px;
  background: rgba(78,205,196,.06);
}
#pcard-ident { flex: 1; min-width: 0; }
#pcard-name  { font-size: 24px; letter-spacing: 3px; color: var(--teal); }
#pcard-level { font-size: 14px; letter-spacing: 1px; color: var(--dim); margin-top: 3px; }


/* #176: две вертикальные части. Левая — погружение (состояние, ресурсы, слоты),
   правая — профиль (уровень, общая статистика).

   Половины РОВНО 50/50, и каждая стоит над своей кнопкой подвала (у него та же
   сетка `repeat(2, 1fr)` и тот же зазор). Раньше левая колонка была `auto`, то
   есть по содержимому: длинное название премии в правой части перетягивало
   границу на себя, и раскладка окна гуляла от слота к слоту.

   Ширину левой половины держат СЛОТЫ: они рисуются теми же карточками, что в
   слое, и ужимать их нельзя (правило проекта). Поэтому окно расширено до
   1160 px — половины хватает на --tool-col-w вместе с паддингами секции. */
#pcard-body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: 14px;
  overflow-y: auto;
  margin-bottom: 14px;
}
#pcard-run  { display: block; min-width: 0; }
#pcard-run-inner { display: flex; flex-direction: column; gap: 14px; }
/* Состояние и ресурсы — рядом, над слотами: вдвоём они занимают ровно ширину
   слотов, и левая часть не вырастает выше нужного. */
/* СОСТОЯНИЕ шире РЕСУРСОВ: его подписи длиннее («Ходов за погружение»,
   «Следующий слой»), и при равных половинах они ломались на две строки, чего
   в интерфейсе быть не должно. Ресурсам лишнего не нужно — там короткие
   названия и число справа. */
/* #291: РЕСУРСЫ получают столько ширины, сколько им нужно, а СОСТОЯНИЕ берёт
   остаток. Прежние доли (1.45fr к 1fr) делили место вслепую: длинная подпись
   «Красный жемчуг» переставала помещаться, как только слева появлялась строка
   петли, и ломалась на две строки. Теперь давит не левое окно на правое, а
   наоборот — правому хватает ровно на свои подписи, и они всегда в одну
   строку (страховка ниже — nowrap: перенос там запрещён сквозным правилом
   «ничто в одну строку не должно становиться двумя»). */
.pcard-run-top {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px;
}
.pcard-run-top .pcard-row-key { white-space: nowrap; }
/* Обе секции стоят в ПОЛОВИНЕ окна, и подписи в них длинные («Ходов за
   погружение», «Красный жемчуг»). Поджимаем боковые поля и зазор до значения —
   ровно настолько, чтобы каждая подпись осталась в одну строку. Правка местная:
   прочие секции карточки сохраняют обычные отступы. */
.pcard-run-top .pcard-sec  { padding-left: 10px; padding-right: 10px; }
.pcard-run-top .pcard-rows { column-gap: 8px; }
#pcard-meta { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
/* Ручка и кнопка ящика — механика смартфона, на десктопе их нет вовсе. */
#pcard-run-handle, #pcard-run-open { display: none; }
.pcard-sec {
  border: 1px solid var(--border);
  border-radius: 3px;
  background: rgba(78,205,196,.04);
  padding: 12px 14px;
}
.pcard-sec-wide { grid-column: 1 / -1; }
.pcard-sec-title {
  font-size: 13px; letter-spacing: 2px; color: var(--teal);
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px; margin-bottom: 8px;
}
.pcard-sec-note { color: var(--dim); letter-spacing: 1px; }
.pcard-rows { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; font-size: 16px; }
.pcard-row-key { color: var(--dim); }
.pcard-row-val { text-align: right; font-weight: bold; }
.pcard-hint { font-size: 12px; color: var(--dim); margin-top: 8px; letter-spacing: .5px; }

/* #170: сетка слотов повторяет #tool-section из слоя — 4 колонки, те же зазоры.
   Сами карточки рисуются классом .card-slot, поэтому высота, арт и кегли берутся
   из общего CSS (в т.ч. мобильных переопределений) и совпадают с игрой один в один.
   max-width равен ширине игровой сетки: иначе в широком окне Профиля слоты
   растянулись бы вдвое против того, что игрок видит в слое. */
#pcard-slots {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 7px;
  row-gap: 5px;
  /* Ширину задаёт JS (TOOL_COL_W) — ровно столько же, сколько у #center-col
     в слое. Фолбэк 488px = та же формула для сетки 10×10. */
  width: var(--tool-col-w, 488px);
  max-width: 100%;
  /* #176: прижаты влево, а не по центру — слоты относятся к погружению и живут
     в левой части окна. Центрировать САМУ СЕТКУ не надо (заказчик, 09.09.2026:
     «блоки… надо оставить, как они были»); по центру выравнивается содержимое
     КАЖДОЙ плитки — правило .card-inner ниже. */
  margin: 0;
}
/* #189: премии. Сетка своя, а не #pcard-slots: она стоит в ПРАВОЙ колонке
   Профиля, которая уже левой, и растягивать её под ширину игровой сетки нельзя —
   колонка поедет. Карточки при этом те же .card-slot, только уже. */
/* #301: «размеры слотов под награды должны быть размером со слот» — та же
   сетка и та же ширина, что у #pcard-slots, поэтому плитка выходит один в один.
   Раньше здесь стояла своя, более узкая раскладка под метку «ЗАБРАТЬ». */
#pcard-rewards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 7px;
  row-gap: 5px;
  width: var(--tool-col-w, 488px);
  max-width: 100%;
  margin: 4px 0 0;
}
#pcard-rewards .card-slot { cursor: pointer; }
.card-slot.pcard-reward:hover { border-width: 2px; filter: brightness(1.15); }
/* Пустой слот премии: пунктир — «сюда ещё поместится», а не «здесь сломалось». */
.card-slot.pcard-reward-empty { border-style: dashed; opacity: .45; cursor: default; }
/* Правила метки «ЗАБРАТЬ» (.pcard-take-badge) сняты: #301 убрал её с карточки —
   щелчок теперь открывает окно с описанием, а не забирает премию. */
.pcard-bonus-row {
  font-size: 12px; line-height: 1.45;
  padding: 4px 0 4px 10px;
  border-left: 2px solid rgba(240,208,96,.5);
  margin-bottom: 4px;
}
/* Итог бонуса — первым и золотом: игрок читает «−40 кредитов», а формулировку
   разбирает уже потом. */
.pcard-bonus-val   { color: var(--gold); font-weight: bold; margin-right: 6px; }
.pcard-bonus-text  { color: var(--fg, #cfe3ee); }
.pcard-bonus-count { color: var(--dim, #7c8a99); margin-left: 4px; font-size: 11px; }

/* Бонус на карточке Атласа. Незаработанный приглушён и показывает счётчик
   открытий — так видно, ради чего копится этап. */
.atlas-card-bonus {
  display: flex; gap: 6px; align-items: baseline;
  font-size: 11px; line-height: 1.35;
  margin: 6px 0 4px;
  padding: 5px 6px;
  border-radius: 3px;
  position: relative;          /* якорь для значка вращения */
  transform-origin: center;
  background: rgba(240,208,96,.05);
  border: 1px solid rgba(240,208,96,.18);
  color: var(--dim, #7c8a99);
}
.atlas-card-bonus.got {
  background: rgba(46,204,113,.08);
  border-color: rgba(46,204,113,.4);
  color: var(--fg, #cfe3ee);
}
.atlas-bonus-mark {
  flex: 0 0 auto; font-weight: bold;
  color: var(--gold);
}
.atlas-card-bonus.got .atlas-bonus-mark { color: var(--green, #2ecc71); }

/* Бонус закрыт до дешифровки вида. Плашка остаётся на месте — высота карточек
   в ряду не должна прыгать оттого, что один вид расшифрован, а другой нет. */
.atlas-card-bonus.locked {
  background: rgba(255,255,255,.02);
  border-color: var(--border);
  color: var(--dim, #7c8a99);
}
.atlas-card-bonus.locked .atlas-bonus-mark { color: var(--dim, #7c8a99); }

/* Переворот плашки: значок вращения + два полуоборота вокруг вертикали.
   Содержимое подменяется в середине (atlasFlipBonus), поэтому обратной стороны
   в разметке нет — оборот идёт по одному и тому же элементу. */
.atlas-card-bonus.flippable { cursor: pointer; padding-right: 20px; }
.atlas-card-bonus.flippable:hover { border-color: rgba(240,208,96,.45); }
.atlas-bonus-spin {
  position: absolute; top: 4px; right: 5px;
  font-size: 12px; line-height: 1; color: var(--gold);
  opacity: .75; pointer-events: none;
  animation: atlas-spin-hint 4s linear infinite;
}
.atlas-card-bonus.got .atlas-bonus-spin { color: var(--green, #2ecc71); }
.atlas-card-bonus.flipping { animation: atlas-flip-out var(--t-tap) ease-in forwards; }
.atlas-card-bonus.flip-in  { animation: atlas-flip-in var(--t-tap) ease-out; }
@keyframes atlas-spin-hint { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes atlas-flip-out { from { transform: rotateY(0deg);   } to { transform: rotateY(90deg); } }
@keyframes atlas-flip-in  { from { transform: rotateY(-90deg); } to { transform: rotateY(0deg);  } }
@media (prefers-reduced-motion: reduce) {
  .atlas-bonus-spin { animation: none; }
  .atlas-card-bonus.flipping, .atlas-card-bonus.flip-in { animation-duration: .01s; }
}

/* Кнопка приза за третий порог. Ровно того же размера, что «Расшифровать»:
   она встаёт на то же место внизу карточки. */
.btn-atlas-prize {
  font-family: var(--font-mono);
  font-size: 13px; letter-spacing: 1px;
  line-height: 1.2;            /* эмодзи в подписи иначе делает кнопку выше «Расшифровать» */
  color: var(--gold); background: rgba(240,208,96,.1);
  border: 1px solid var(--gold); border-radius: 3px;
  padding: 7px 10px; cursor: pointer; width: 100%;
  min-height: var(--btn-min-h, 32px);
  margin-top: 6px;
}
.btn-atlas-prize:hover { background: rgba(240,208,96,.22); }
.btn-atlas-prize.taken { opacity: .7; }
.pcard-empty-note {
  font-size: 11px; line-height: 1.45;
  color: var(--dim, #7c8a99);
  padding: 2px 0;
}
/* Уголок с ценой возврата (#160). Внутри 134px карточки, поверх арта. */
.pcard-sell-badge {
  position: absolute; top: 4px; right: 5px;
  font-size: 11px; color: var(--gold);
  background: rgba(9,20,33,.85);
  border: 1px solid rgba(240,208,96,.45);
  border-radius: 3px; padding: 0 4px;
  pointer-events: none;
}
/* Закрытый слот с активной кнопкой «Открыть» (#173): базовая .slot-locked гасит
   карточку до 35% — кнопку на ней было бы не прочитать. */
.card-slot.slot-locked.pcard-unlockable { opacity: .95; background: rgba(30,10,10,.2); }
.card-slot.slot-locked.pcard-unlockable .locked-icon { margin-top: 2px; opacity: .7; }
.pcard-unlock-btn {
  font-family: var(--font-mono);
  font-size: 12px; letter-spacing: 0; line-height: 1.25;
  color: var(--gold); background: rgba(240,208,96,.12);
  border: 1px solid rgba(240,208,96,.5); border-radius: 3px;
  padding: 4px 6px; cursor: pointer; margin-top: 4px;
  max-width: 100%;
}
.pcard-unlock-btn:hover:not(:disabled) { background: rgba(240,208,96,.28); }
.pcard-unlock-btn:disabled { opacity: .4; cursor: default; }

/* #168: обе кнопки подвала Профиля одной ширины — как в подвале Организаций. */
/* Зазор тот же, что у #pcard-body: иначе кнопки и половины над ними
   разъезжались бы на несколько пикселей. */
#pcard-footer { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; flex-shrink: 0; }
#pcard-footer button {
  font-family: var(--font-mono);
  font-size: 17px; letter-spacing: 2px;
  border-radius: 3px; padding: 12px; cursor: pointer;
}
#btn-pcard-atlas {
  background: rgba(78,205,196,.08); color: var(--teal);
  border: 1px solid var(--teal);
}
#btn-pcard-atlas:hover { background: rgba(78,205,196,.2); }
#btn-pcard-back {
  background: var(--teal); color: #0b1a2a; border: none;
}
#btn-pcard-back:hover { filter: brightness(1.1); }

/* ═══ CODE ENTRY MODAL (секретный код полной версии) ═══ */
#code-entry-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.82);
  display: flex; align-items: center; justify-content: center;
  z-index: 9700;
  font-family: var(--font-mono);
}
#code-entry-overlay.hidden { display: none; }
#code-entry-box {
  width: clamp(260px, 80vmin, 360px);
  background: #061726;
  border: 2px solid rgba(240,208,96,.5);
  border-radius: 3px;
  padding: 22px 24px;
  text-align: center;
  box-shadow: 0 0 36px rgba(240,208,96,.2);
}
#code-entry-label {
  color: #f0d060; font-size: 15px; letter-spacing: 3px;
  margin-bottom: 12px;
}
#code-entry-text { color: var(--text); font-size: 14px; margin-bottom: 14px; }
#code-entry-input {
  width: 160px; text-align: center;
  font-family: var(--font-mono);
  font-size: 28px; letter-spacing: 10px; font-weight: bold;
  color: #f0d060; background: rgba(240,208,96,.06);
  border: 2px solid rgba(240,208,96,.45); border-radius: 3px;
  padding: 8px 10px; margin-bottom: 18px; outline: none;
}
#code-entry-input:focus { border-color: rgba(240,208,96,.85); }
#code-entry-btns { display: flex; gap: 12px; justify-content: center; }
#code-entry-btns button {
  font-family: var(--font-mono);
  font-size: 15px; font-weight: bold;
  padding: 9px 24px; border-radius: 3px; cursor: pointer;
  border: 2px solid rgba(78,205,196,.55);
  background: rgba(78,205,196,.1); color: var(--teal);
}
#btn-code-ok { border-color: rgba(240,208,96,.6); color: #f0d060; background: rgba(240,208,96,.12); }
.ach-item {
  position: relative;
  padding: 12px 14px;
  background: rgba(78,205,196,.04);
  border: 1px solid rgba(78,205,196,.25);
  border-radius: 3px;
}
.ach-item.ach-done {
  background: rgba(46,204,113,.07);
  border-color: rgba(46,204,113,.55);
}
.ach-item.ach-locked {
  opacity: .9;
  position: relative;
  overflow: hidden;
}
.ach-item.ach-locked .ach-title,
.ach-item.ach-locked .ach-reward {
  filter: blur(1.5px);
  opacity: .55;
}
/* Замок на плашках закрытых финалов (Госпиталь, Канал) */
.ach-lock {
  position: absolute; top: 9px; right: 11px; z-index: 3;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.65));
}
.ach-has-lock .ach-title { padding-right: 40px; }
.ach-has-lock .ach-status { top: auto; bottom: 10px; }
.ach-title {
  font-size: 13px; color: #b6f1eb; letter-spacing: 1.5px;
  margin-bottom: 4px;
}
.ach-done .ach-title { color: #2ecc71; }
.ach-reward {
  font-size: 11px; color: rgba(255,255,255,.55);
}
.ach-status {
  position: absolute; top: 10px; right: 14px;
  font-size: 11px; letter-spacing: 1px;
}
.ach-done .ach-status { color: #2ecc71; }
.ach-locked .ach-status { color: rgba(255,255,255,.35); }
.ach-wip-stamp {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(-6deg);
  border: 3px solid rgba(231,76,60,.85);
  color: rgba(231,76,60,1);
  font-size: 16px;
  letter-spacing: 4px;
  padding: 6px 14px;
  border-radius: 3px;
  background: rgba(231,76,60,.12);
  font-weight: bold;
  pointer-events: none;
  text-shadow: 0 0 4px rgba(231,76,60,.5);
  white-space: nowrap;
}

/* ─── SIDE PANEL (Android-демо) ─────────────────────────────────── */
#btn-sidepanel {
  display: none;  /* виден только на мобильном через @media */
  background: rgba(78,205,196,.08);
  border: 1px solid rgba(78,205,196,.45);
  color: var(--teal);
  cursor: pointer;
  font-size: 18px;
  padding: 2px 9px;
  border-radius: 3px;
  font-family: var(--font-mono);
  line-height: 1;
}
#header-hp {
  display: none;  /* виден только на мобильном — постоянный Связность-индикатор */
  align-items: center;
  gap: 3px;
  color: var(--red);
  font-weight: bold;
  font-size: 13px;
  padding: 2px 6px;
  border: 1px solid rgba(231,76,60,.4);
  border-radius: 3px;
  background: rgba(231,76,60,.08);
}
#side-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 320px;
  max-width: 90vw;
  background: var(--bg);
  border-left: 2px solid var(--teal);
  box-shadow: -8px 0 30px rgba(0,0,0,.7);
  z-index: 8500;
  transform: translateX(100%);
  transition: transform var(--t-in) ease-out;
  display: none;  /* виден только на мобильном */
  flex-direction: column;
}
#side-panel.opened { transform: translateX(0); }
#sp-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}
#sp-title {
  flex: 1;
  font-size: 14px;
  letter-spacing: 3px;
  font-weight: bold;
  color: var(--teal);
  font-family: var(--font-mono);
  text-transform: uppercase;
}
/* #115: счётчик хода в шапке панели СИГНАТУРЫ — на мобильном строка ресурсов не должна
   разрастаться на два ряда из-за «ТАКТ N» (в шапке слоя он скрыт через @media). */
#sp-turn {
  flex: 0 0 auto;
  font-size: 13px;
  letter-spacing: 1px;
  color: var(--dim);
  font-family: var(--font-mono);
}
#sp-turn span { color: var(--text); font-weight: bold; }
#sp-close {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 14px;
  width: 32px; height: 32px;
  border-radius: 3px;
  cursor: pointer;
}
#sp-body { flex: 1; overflow-y: auto; padding: 10px; display: flex; flex-direction: column; gap: 10px; }
.sp-section { display: flex; flex-direction: column; min-height: 0; }
.sp-section-log { flex: 1; min-height: 120px; }
.sp-section-log #sp-log-entries { flex: 1; overflow-y: auto; }
.sp-section-title {
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--dim);
  border-bottom: 1px solid var(--border);
  padding-bottom: 4px;
  margin-bottom: 8px;
  text-transform: uppercase;
}
#sp-eph-list { font-size: 12px; display: flex; flex-direction: column; gap: 4px; }
#sp-log-entries { font-size: 12px; display: flex; flex-direction: column; gap: 3px; }
#sp-log-entries .log-line { padding: 2px 4px; border-left: 2px solid transparent; line-height: 1.35; }
#sp-log-entries .log-err  { border-left-color: var(--red); color: #ffb0a8; }
#sp-log-entries .log-warn { border-left-color: var(--yellow); color: #ffe7a8; }
#sp-log-entries .log-ok   { border-left-color: var(--green); color: #b8e8c8; }
#sp-log-entries .log-trigger { border-left-color: var(--gold); color: #ffd870; }
#sp-log-entries .log-info { color: var(--dim); }

/* ─── ВКЛАДКИ ОРГАНИЗАЦИЙ ─────────────────────────────────────────
   Правила стиля «Галерея» — в блоке «ОРГАНИЗАЦИИ» в конце файла. Здесь
   осталось только то, что нужно и там: раньше на кнопке фоном работал кроп
   круглой эмблемы, увеличенный на 220 %, — от него читалось цветное пятно, но
   не организация. Теперь на вкладке стоит КАДР организации, как в макете. */

/* ─── DEMO END / PAYWALL (Android-демо) ─────────────────────────── */
#demo-end-overlay {
  position: fixed; inset: 0; z-index: 9500;
  display: flex; align-items: center; justify-content: center;
  background: rgba(2, 6, 14, .92);
  padding: 16px;
}
#demo-end-box {
  width: 100%; max-width: 460px;
  background: linear-gradient(180deg, #0a1828 0%, #050b16 100%);
  border: 2px solid var(--teal);
  border-radius: 3px;
  padding: 22px 22px 18px;
  box-shadow: 0 0 40px rgba(78,205,196,.25);
  color: var(--text);
  font-family: var(--font-mono);
}
#demo-end-header {
  font-size: 16px;
  letter-spacing: 3px;
  color: var(--teal);
  text-align: center;
  border-bottom: 1px dashed rgba(78,205,196,.4);
  padding-bottom: 12px;
  margin-bottom: 18px;
  font-weight: bold;
}
#demo-end-body { font-size: 14px; line-height: 1.55; }
#demo-end-body p { margin: 10px 0; }
/* #265: постер вместо текстового глифа ⌬. Кадр во всю ширину карточки, под ним
   заголовок и текст — так это окно выглядело в андроид-демке. */
#demo-end-hero {
  display: block;
  width: calc(100% + 44px);           /* компенсируем padding карточки */
  margin: -22px -22px 14px;
  border-radius: 3px 3px 0 0;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  opacity: .9;
}
/* #265: «Играть дальше» — жёлтая: это единственная кнопка окна, которая ведёт
   в игру, остальные уводят из неё. */
/* Селектор с двумя классами: общее правило #demo-end-buttons .btn-overlay-action
   идёт НИЖЕ по файлу и при равной специфичности перебивало жёлтый фон. */
#demo-end-buttons .btn-overlay-action.btn-demo-code {
  background: var(--gold);
  border-color: var(--gold);
  color: #1a1208;
  font-weight: bold;
}
#demo-end-buttons .btn-overlay-action.btn-demo-code:hover { background: #ffe08a; border-color: #ffe08a; }
.demo-end-meta {
  font-size: 12px; letter-spacing: 1px;
  color: var(--dim); text-align: center; margin-bottom: 12px;
}
.dem-clr { color: var(--gold); }
.dem-restrict { color: var(--red); }
.demo-end-foot {
  margin-top: 18px !important;
  font-size: 12px; color: var(--dim); text-align: center;
  font-style: italic;
}
#demo-end-buttons {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: 18px;
}
#demo-end-buttons .btn-overlay-action {
  width: 100%;
  text-align: center;
  font-size: 14px;
  padding: 12px 16px;
  letter-spacing: 1px;
  border-radius: 3px;
  font-family: var(--font-mono);
  background: var(--teal);
  color: #02101a;
  border: none;
  cursor: pointer;
  font-weight: bold;
}
#demo-end-buttons .btn-overlay-secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
}


/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ЭКРАН СЛОЯ  (docs/design/Layer.html)
   Слой — девяносто процентов времени игрока, поэтому он идёт третьим шагом
   переноса, сразу за токенами и знаками. Блок стоит ПОСЛЕ прежних правил и
   ПЕРЕД мобильной раскладкой: он перебивает десктопные значения и не мешает
   телефону, где раскладка своя.

   Геометрия поля не тронута вовсе: сектор 46 px, зазор 2, центральная колонка
   488. Правило #126 (клетки НИКОГДА не ужимаются под высоту экрана) в силе.
═══════════════════════════════════════════════════════════════════ */

/* ─── ШАПКА: КТО ИГРАЕТ ─────────────────────────────────────────── */
.rb-who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.rb-face {
  position: relative; width: 38px; height: 38px; flex: 0 0 auto;
  overflow: hidden; border-radius: var(--r-s); background: #060a12;
}
.rb-face img {
  width: 100%; height: 100%; display: block;
  /* Кадр 16:9, а гнездо квадратное: обрезаем по центру и чуть выше середины —
     лицо на этих кадрах стоит в верхней трети, и обрезка «по центру» срезала
     бы его наполовину. */
  object-fit: cover; object-position: center 26%;
}
/* Полоса сигнального цвета под портретом — та же, что под карточкой эхонавта
   на экране выбора. Цвет ставит renderNavBar. */
.rb-face i { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; }
.rb-nick {
  font-family: var(--font-head); font-size: 16px; font-weight: 500;
  letter-spacing: 1.8px; text-transform: uppercase; line-height: 1.1;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rb-lvl {
  flex: 0 0 auto; white-space: nowrap; cursor: default;
  font-family: var(--font-head); font-size: 10.5px; font-weight: 500;
  letter-spacing: 1.6px; text-transform: uppercase; color: var(--gold);
  border: 1px solid rgba(240,208,96,.45); border-radius: var(--r-s);
  padding: 0 5px; line-height: 16px;
}

/* ─── ШАПКА: РЕСУРСЫ И СВЯЗНОСТЬ ────────────────────────────────── */
#res-bar { font-size: 18px; padding: 7px 12px; }
.res-item { font-weight: 600; }
/* Число выравнивается по СВОЕЙ высоте, а не по унаследованной строке. У цифр
   нет выносных элементов вниз, и в высокой строке они сидят выше её середины —
   значок рядом оказывался ниже цифры (заказчик, 29.08.2026). */
.res-item > span { line-height: 1; }
/* Значки ресурсов ростом с цифру рядом: в макетах они одного роста со строкой,
   а не крупнее её. Цвет — свой у каждого ресурса, через currentColor значка. */
.res-item .gi { height: 20px; }
/* …и рисунок обязан ужаться ВМЕСТЕ с обёрткой. Правило `.res-item svg`
   (27 × 27) осталось от прежних значков и перебивало её: обёртка 20 px, svg
   27 px, лишние семь пикселей свисали ВНИЗ — значок сидел на 3,5 px ниже цифры
   (заказчик, 30.08.2026: «поднять иконки чуть выше, по центру с цифрами»).
   Мерить это надо по svg, а не по .gi: у обёртки координаты были правильные.

   ШИРИНА — auto, А НЕ 100 %. У `.gi` ширины своей нет (она считается по
   содержимому), и `width: 100 %` замыкает её саму на себя: Chrome разрывает
   круг по viewBox, а WebKit берёт дефолт замещаемого элемента — 300 px, и
   значок раздувал строку ресурсов. Размер теперь приходит атрибутами из
   svgSized() в game.js, поэтому auto достаточно. */
.res-item .gi > svg { width: auto; height: 100%; display: block; }
.ri-data   { color: #7fd8ff; }
.ri-green  { color: var(--green); }
.ri-yellow { color: var(--yellow); }
.ri-pearl  { color: #e0708a; }
.ri-warp   { color: var(--purple); }
.ri-credit { color: var(--gold); }
/* Связность в шапке — на десктопе тоже. Красной рамки и заливки больше нет:
   Связность это рассудок, а не ранение, и её кардиограмма читается сама. */
#header-hp {
  display: inline-flex; align-items: center; gap: 5px;
  /* Связность читается КАК ОДИН БЛОК, а не как три значка, оброненные в ряд
     ресурсов (заказчик, 30.08.2026). Кардиограммы — одна величина, разбитая на
     деления; ресурсы рядом — разные величины, и путать эти два способа чтения
     нельзя. Оправа лёгкая: рамка волосяная, фон панельный — это группировка,
     а не тревога (красную заливку отсюда убрали намеренно: Связность —
     рассудок, а не ранение). */
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--panel-2);
}
#header-hp-hearts { display: inline-flex; align-items: center; gap: 5px; }

/* ─── ЗАГОЛОВОК СЛОЯ: ЗОЛОТАЯ СПИНА СЛЕВА ───────────────────────── */
#layer-title, #layer-title-mobile {
  height: 34px; padding: 0 11px; align-items: center;
  border: 0; border-left: 3px solid var(--gold);
  border-radius: 0 var(--r) var(--r) 0;
  background: var(--panel);
  letter-spacing: 2.4px;
}
#layer-title .lt-name, #layer-title-mobile .lt-name {
  font-family: var(--font-head); font-weight: 500; font-size: 15px;
  color: var(--head); text-shadow: none;
}
#layer-title .lt-rec, #layer-title-mobile .lt-rec { font-size: 12px; letter-spacing: 0; }

/* ─── ЗАРЯД СЛОЯ — В ЗАГОЛОВКЕ «ЭФЕМЕРЫ» ────────────────────────
   Отдельной полосы #run-line больше нет (15.09.2026): она занимала 34 px высоты
   правой колонки ради одной цифры, и эти пиксели отданы журналу. Цифра прижата
   к правому краю той же распоркой margin-left:auto, что и «ТАКТ» в заголовке
   журнала, — заголовок панели обычный flex, и колонка сетки развалила бы его
   точку ::before. */
#layer-potential { margin-left: auto; }
#eph-panel-title .lp-cap { letter-spacing: 1.2px; }
/* ТАКТ живёт в заголовке ЖУРНАЛА, у правого края (заказчик, 06.09.2026).
   Прижимает его к краю сама распорка margin-left:auto, а не колонка в сетке:
   заголовок панели — обычный flex, и второй способ развалил бы точку ::before. */
#turn-label {
  display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap;
  margin-left: auto;
  font-size: 14px; font-weight: 600; color: var(--gold); letter-spacing: 0;
}
#turn-label > span[data-txt] {
  font-family: var(--font-head); font-size: 11px; font-weight: 400;
  letter-spacing: 2.4px; text-transform: uppercase; color: var(--dim-2);
}
/* Рамки вокруг остатка слоя больше нет: в строке из трёх величин две рамки
   внутри одной панели читались как вложенные окна. Держат их подписи. */
#layer-potential { gap: 14px; }
.lp-item { border: 0; background: none; padding: 0; gap: 5px; font-size: 14px; font-weight: 600; }
.lp-cap {
  font-family: var(--font-head); font-size: 11px; font-weight: 400;
  letter-spacing: 1.6px; text-transform: uppercase; opacity: 1; color: var(--dim-2);
}
.lp-sub { font-size: 12px; font-weight: 400; color: var(--dim-2); }
.lp-oi .lp-ico-svg { color: #7fd8ff; height: 14px; }
.lp-energy .lp-ico .gi { color: var(--gold); height: 14px; }

/* ─── ПАНЕЛИ ПРАВОЙ КОЛОНКИ ─────────────────────────────────────── */
.panel { background: var(--panel-2); border: 1px solid var(--border); padding: 11px 12px 12px; }
/* Точку перед заголовком рисует CSS, а не разметка: содержимое этих элементов
   подставляет каталог текстов (data-txt, innerHTML), и дописанный руками <b>
   стёрся бы первой же подстановкой — молча. */
.panel-title {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 3px; color: var(--dim);
  padding-bottom: 7px; margin-bottom: 9px;
}
/* Шапка ЖУРНАЛА ниже на десятую часть (заказчик, 15.09.2026): 33 px → 29.
   Ужимаем отбивки, а не кегль: буквы того же размера, что у соседней панели,
   иначе два заголовка перестают читаться как пара. */
.panel-title.log-title { padding-bottom: 5px; margin-bottom: 7px; }
.panel-title::before {
  content: ""; width: 8px; height: 8px; flex: 0 0 auto;
  background: var(--teal); box-shadow: 0 0 8px rgba(78,205,196,.7);
}

/* ─── КОНТУР ─────────────────────────────────────────────────────
   Деления залиты градиентом и обведены своим цветом (в макете так). Логика
   цвета НЕ тронута: красным горит только верхнее деление и только при полном
   контуре, следующее оранжевым — это решение по замечанию #197, а макет
   нарисован ровно с такого, полного контура, и с ним сходится. */
.bat-pip { border-radius: var(--r-s); border: 1px solid transparent; }
.bat-pip.empty    { background: #0c1e2e; border-color: rgba(126,168,190,.22); }
.bat-pip.full     { background: linear-gradient(180deg, rgba(78,205,196,.42), rgba(78,205,196,.22)); border-color: rgba(78,205,196,.60); box-shadow: none; }
.bat-pip.warn     { background: linear-gradient(180deg, rgba(231,76,60,.62), rgba(231,76,60,.34)) !important; border-color: rgba(231,76,60,.75); box-shadow: none !important; }
.bat-pip.warn-mid { background: linear-gradient(180deg, rgba(243,156,18,.60), rgba(243,156,18,.32)) !important; border-color: rgba(243,156,18,.72); box-shadow: none !important; }
#bat-val { font-size: 12px; font-weight: 600; color: var(--dim); }
#bat-label .gi { height: 16px; }

/* ─── СЛОТЫ ИНСТРУМЕНТОВ: КВАДРАТНЫЕ, СЕТКОЙ ────────────────────── */
/* Единственный способ держать подписи всех восьми слотов на ОДНОЙ линии:
   три ряда фиксированной высоты — рисунок, название, стоимость. При свободной
   раскладке подпись съезжала у каждого слота на свою высоту, потому что у
   одного есть лампы серии, у другого цена, у третьего ничего. */
.card-slot { height: 117px; background: linear-gradient(180deg, #0d1a27 0%, #091420 100%); border-color: var(--border-2); box-shadow: inset 0 1px 0 rgba(190,225,240,.07); }
.card-slot::after {
  content: ""; position: absolute; left: 8px; right: 8px; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(126,168,190,.35), transparent);
}
.card-inner {
  display: grid; grid-template-rows: 48px 18px 14px; gap: 5px;
  /* КОЛОНКА ВО ВСЮ ШИРИНУ ПЛИТКИ (заказчик, 09.09.2026: «иконки, надписи, слоты…
     нужно центрировать по центру именно этого квадратика»). Без явной колонки
     grid считал её ПО САМОМУ ШИРОКОМУ содержимому — 52 px значка при плитке в
     117 — и прижимал к левому краю: значок, подпись, «+ СЛОТ», замок и кнопка
     «Открыть» стояли слева, хотя каждый по отдельности был отцентрован внутри
     этой узкой колонки. Заодно длинная подпись переносится по всей ширине
     плитки, а не по ширине значка. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center; align-items: center;
  padding: 9px 4px 8px; height: 100%;
}
/* #309: та же прибавка, что в карточке эхонавта — слоты в слое и в карточке
   показывают одно и то же снаряжение, и разного размера быть не должно. */
.card-art, [data-equipment-art="on"] .card-art-img { width: 52px; height: 52px; }
.card-name { font-family: var(--font-head); font-size: 13px; font-weight: 500; letter-spacing: 2.2px; line-height: 1; }
.card-cost { font-size: 12px; font-weight: 600; line-height: 1; }
#combo-lamps { margin-top: 0; gap: 4px; }
.combo-lamp { width: 8px; height: 8px; background: #0c1e2e; border-color: rgba(126,168,190,.30); }
/* Пустой и запертый слот: пунктир и никакого блика — он не прибор, а место. */
.card-slot.empty, .card-slot.slot-locked {
  background: rgba(126,168,190,.022); border-style: dashed; border-color: rgba(126,168,190,.22); box-shadow: none;
}
.card-slot.empty::after, .card-slot.slot-locked::after { display: none; }
.empty-inner { min-height: 0; }
.empty-plus { font-size: 20px; line-height: 1; opacity: 1; color: var(--dim-2); }
.empty-label { font-family: var(--font-head); font-size: 11.5px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--dim-2); opacity: 1; line-height: 1; }
.card-slot.slot-locked .locked-icon { font-size: 19px; margin-top: 0; opacity: 1; color: var(--dim-2); }

/* Выбранный инструмент — СПИНА слева, а не рамка целиком: рамка спорит с
   рамками соседей, спина видна боковым зрением.

   #306: спина, рамка и свечение горят цветом САМОГО ИНСТРУМЕНТА, а не одним
   золотом на двоих. Зонд в игре бирюзовый везде — значок, карточка, подсветка
   сектора под курсором (.tool-locator .cell-hidden:hover), — и только его
   собственная подсветка была золотой, то есть цветом Эхолуча. Заказчик:
   «подсветка зонда при его выборе сейчас жёлтая, сделай синюю».

   Кадры разведены на две анимации, а не сведены к одной через currentColor:
   свечение обязано быть цветом спины, а currentColor — это цвет ТЕКСТА
   карточки, и вспышка выходила белёсой. */
.card-slot.sel-locator {
  border-color: rgba(78,205,196,.60);
  background: linear-gradient(180deg, #08201f 0%, #051413 100%);
}
.card-slot.sel-echobeamer {
  border-color: rgba(240,208,96,.60);
  background: linear-gradient(180deg, #1a1608 0%, #120f05 100%);
}
.card-slot.sel-locator::before, .card-slot.sel-echobeamer::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; z-index: 2;
}
.card-slot.sel-locator::before {
  background: var(--teal); box-shadow: 0 0 14px rgba(78,205,196,.55);
  animation: slot-spine-teal var(--t-in) ease;
}
.card-slot.sel-echobeamer::before {
  background: var(--gold); box-shadow: 0 0 14px rgba(240,208,96,.55);
  animation: slot-spine-gold var(--t-in) ease;
}
@keyframes slot-spine-teal {
  from { box-shadow: 0 0 2px rgba(78,205,196,.2); }
  to   { box-shadow: 0 0 14px rgba(78,205,196,.55); }
}
@keyframes slot-spine-gold {
  from { box-shadow: 0 0 2px rgba(240,208,96,.2); }
  to   { box-shadow: 0 0 14px rgba(240,208,96,.55); }
}

/* Подсказка клавиши и кнопка выхода — в ряду над слотами, как в макете. */
.slot-key-hint { display: flex; align-items: center; justify-content: flex-start; gap: 6px; font-size: 12px; color: var(--dim-2); }
kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 19px; height: 19px; padding: 0 4px;
  border: 1px solid rgba(126,168,190,.35); border-radius: var(--r-s);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; color: var(--dim);
  background: none;
}

/* ═══════════════════════════════════════════════════════════════════
   МОБИЛЬНАЯ РАСКЛАДКА (смартфон / планшет)
   Полная версия раздаётся с сервера: с компьютера — широкая раскладка выше,
   с телефона/планшета — этот блок (интерфейс андроид-демки).
   Условие ниже ОБЯЗАНО совпадать с MOBILE_MQ в js/game.js — CSS и JS должны
   переключаться одновременно, иначе сетка/СИГНАТУРЫ разъедутся с вёрсткой.
     • max-width:599px       — телефон в портрете, узкое окно десктопа;
     • pointer:coarse ≤900px — телефон в ЛАНДШАФТЕ и планшеты (палец, не мышь).
═══════════════════════════════════════════════════════════════════ */
@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  :root {
    --cell-size: 36px;
    --btn-min-h: 44px;
  }
  /* «(Esc)» — подсказка для клавиатуры; на телефоне её нет, и суффикс только
     сбивает с толку. Сама строка остаётся: это единственный вход в громкость
     из главного меню, где шапки с ⚙ не видно. */
  body {
    /* Edge-to-edge: к базовым 6px добавляем safe-area, чтобы строка ресурсов не
       уходила под статус-бар сверху, а снизу учитывался жестовый inset. */
    padding:
      calc(6px + var(--safe-top))
      calc(6px + var(--safe-right))
      calc(6px + var(--safe-bottom))
      calc(6px + var(--safe-left));
    min-height: 100dvh;
  }
  #app { width: 100%; max-width: 100%; }

  /* Top resources bar: два ряда. Первый — ресурсы (без Связности), второй — Связность + кнопки. */
  #res-bar {
    flex-direction: column;
    align-items: stretch;
    /* #14: ресурсы крупнее (+~18%) и жирнее */
    font-size: 15px;
    font-weight: bold;
    gap: 4px;
    padding: 5px 8px;
    /* #219: выравнивание по рамке схемы питания — десктопное. Здесь схемы нет. */
    margin-left: 0;
    width: auto;
  }
  /* Верхняя строка ресурсов слоя: шрифт +20% (цифры и «ТАКТ» в одну строку). */
  .res-item { font-weight: bold; font-size: 18px; }
  /* Десктопный отступ между ресурсами здесь НЕ нужен и вреден: на телефоне
     шапка идёт двумя рядами с переносом, места нет вовсе, и лишние 13 px на
     каждый ресурс выталкивали ряд за край (383 → 409 при ширине 376).
     Пары «значок + число» тут разводит перенос строки, а не воздух. */
  .res-item + .res-item { margin-left: 0; }
  /* #36: цифры на поле жирнее — на телефоне обычный bold читался хуже. */
  .cell { font-weight: 800; }
  /* #16: на экране результата («Слой очищен» и т.п.) шапка с данными видна
     поверх затемнения, но кнопки Архив/панель СИГНАТУРЫ заблокированы. (#overlay z-index:100) */
  body.result-overlay #res-bar { position: relative; z-index: 110; }
  body.result-overlay #btn-archive,
  body.result-overlay #btn-settings,
  body.result-overlay #btn-sidepanel { pointer-events: none; opacity: .45; }
  .res-bar-row {
    display: flex;
    align-items: center;
    gap: 5px;
    flex-wrap: wrap;
  }
  .res-item svg { width: 22px; height: 22px; }
  .res-divider { height: 20px; margin: 0 2px; }
  /* #115: «ТАКТ N» переезжает в правый верхний угол СИГНАТУР (#sp-turn) — иначе
     верхняя строка ресурсов разрастается на два ряда. На десктопе остаётся в шапке. */
  #turn-label, #turn-divider { display: none; }
  /* «Подсказки» — теперь в Главном меню → Настройки, в шапке игры не нужны */
  /* Связность в шапке — кардиограммы. Красной рамки вокруг них нет: с ней
     получалась рамка внутри рамки, а тревогу и так несёт оборванная линия
     потерянного деления. */
  #header-hp { padding: 0; gap: 4px; border: 0; background: none; line-height: 1; }
  /* #10: больше воздуха между сердечками */
  #header-hp-hearts { display: inline-flex; gap: 4px; align-items: center; }
  #header-hp-hearts .heart { font-size: 16px; line-height: 1; }

  /* КТО ИГРАЕТ на телефоне не показываем. Имя, портрет и уровень занимают
     около 150 px, и шапка ресурсов из-за них расползалась на три строки —
     против сквозного требования «ничто в одну строку не должно становиться
     двумя». Своё имя игрок и так знает; шапка на телефоне про запасы. */
  .rb-who { display: none; }

  /* Inline kbd подсказки в слотах — мельче */
  kbd { font-size: 11px; padding: 0 3px; }
  .slot-key-hint { font-size: 12px; }

  /* Card titles на мобильном — мельче, в одну строку. «ЗОНД»/«ЭХОЛУЧ» должны входить.
     #22: ни одно название не переносится. */
  .card-name { font-size: 11px; letter-spacing: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Стоимость инструмента (-2з / +4з / бесплатно) — крупнее, заметнее */
  .card-cost { font-size: 16px; font-weight: bold; }
  .card-art, [data-equipment-art="on"] .card-art-img { width: 50px; height: 50px; }
  /* #58: слоты чуть ниже (118→110, ~-7%) — слой целиком помещается на экран. */
  .card-slot { height: 110px; }
  /* Ряды сетки слота под мобильную высоту: рисунок 44, название 16, цена 13.
     На десктопных 48/18/14 подписи вылезали за нижнюю кромку. */
  .card-inner { grid-template-rows: 44px 16px 13px; gap: 4px; padding: 7px 3px 6px; }
  .card-art, [data-equipment-art="on"] .card-art-img { width: 44px; height: 44px; }

  /* Мобильная раскладка центральной колонки. Активный инструмент уезжает из
     внешнего блока (он скрыт) внутрь tool-section — слева от «УЙТИ ИЗ СЛОЯ». */
  #center-col { align-items: stretch; }
  #grid-wrap            { align-self: stretch; }
  #layer-title          { display: none; }
  .slot-key-hint        { display: none; }
  /* Заголовок слоя на телефоне живёт внутри #tool-section и занимает СТРОКУ
     ЦЕЛИКОМ (1 / -1). Половины строки, как у прежней плашки «Сейчас», ему не
     хватает: «Слой 12 (Последняя отмель) · Рекорд: 1240» в 166 px не помещается
     ни при каком кегле, и название резалось до «Сло…». Кнопка «ВЫЙТИ ИЗ СЛОЯ»
     (и панель «ГЛАЗА» у Массива) съезжают в свою строку ниже.
     Цена — примерно 30 px высоты. Отыграны они здесь же: заголовок сделан
     компактным (26 px против кнопочных 44), а сектора сетки НЕ ТРОГАЕМ —
     ужимать их под высоту экрана прямо запрещено (CLAUDE.md).
     Строчные буквы и letter-spacing 0 — тоже ради ширины: капс и разрядка
     раздували строку примерно на четверть. */
  #layer-title-mobile {
    display: flex;
    grid-column: 1 / -1;
    align-self: center;
    padding: 4px 8px;
    font-size: 12px;
    letter-spacing: 0;
    text-transform: none;
    min-height: 26px;
  }
  #layer-title-mobile .lt-rec { font-size: 11px; }

  /* Кнопки магазина и UI — тач-friendly высота 44px */
  .btn-shop, .btn-equip-buy, #btn-exit-room, .btn-overlay-action,
  .org-tab, #btn-archive, #btn-test, .btn-decipher-skip, .btn-decipher-pay,
  .hint-close, .archive-tab, #achievements-close {
    min-height: var(--btn-min-h);
  }
  .btn-shop, .btn-equip-buy { font-size: 13px; padding: 8px 10px; }
  .org-tab { font-size: 13px; padding: 8px 10px; }
  /* #14: кнопки Архив/панель СИГНАТУРЫ ниже — освобождают место под крупный ряд ресурсов */
  #btn-archive, #btn-test, #btn-sidepanel, #btn-settings {
    /* #35: панель СИГНАТУРЫ и Архив одной высоты (оба = var(--btn-min-h)=44px на телефоне) */
    min-height: var(--btn-min-h);
    padding: 4px 10px;
    font-size: 13px;
  }
  /* Настройки открываются поверх слоя — на телефоне окно во всю ширину. */
  #settings-overlay { padding: 12px; }
  #settings-box { width: 100%; padding: 14px 16px; gap: 14px; }
  #settings-title { font-size: 16px; letter-spacing: 2px; }
  /* Толще трек и крупнее ползунок — попасть пальцем в 6px невозможно. */
  .settings-range { height: 10px; }
  .settings-range::-webkit-slider-thumb { width: 24px; height: 24px; }
  .settings-range::-moz-range-thumb { width: 24px; height: 24px; }
  .settings-check-row input[type=checkbox] { width: 24px; height: 24px; }
  #btn-settings-quit { min-height: var(--btn-min-h); }
  /* Запасные отступы поменьше: на телефоне угол ближе к содержимому. */

  /* Battery col — горизонтальная над сеткой (вертикальная съедает половину экрана) */
  #battery-col {
    flex-direction: row;
    align-items: center;
    gap: 4px;
    width: auto;
    flex: 0 0 auto;
    /* #219: сдвиги под рамку схемы питания — только десктоп. На телефоне схемы
       нет вовсе (buildPowerRig выходит на isMobileUI), и контур стоит плашкой
       над сеткой во всю ширину. */
    margin-top: 0;
    margin-left: 0;
    padding: 4px 6px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 3px;
  }
  #bat-pips { flex-direction: row; gap: 2px; flex: 1; min-width: 0; }
  /* Пипы контура в 1.5× длиннее. Размер подгоняется так,
     чтобы при maxBat=10 (10×W + 9×gap + label + val) всё влазило в ширину экрана. */
  .bat-pip { width: 27px; height: 20px; }
  #bat-label { font-size: 16px; line-height: 1; }
  #bat-val { font-size: 11px; }

  /* Game area — на узком экране переносим info-col вниз
     (в Task G это станет sliding-sidebar, временно — просто flex-wrap) */
  #game-area { flex-direction: column; align-items: stretch; gap: 6px; }
  #info-col { min-width: 100%; flex: 1 0 100%; }

  /* Ачивки — статус не должен наезжать на заголовок */
  .ach-status { position: static !important; display: block; margin-top: 4px; }

  /* Атлас: бокс на всю ширину, сетка в 2 колонки (карточка узкая — силуэт
     и три строки статистики читаются и в половине экрана). */
  #atlas-overlay { padding: 8px; align-items: stretch; }
  #atlas-box {
    width: 100% !important; max-width: 100% !important;
    padding: 10px !important;
    max-height: calc(100vh - 16px);
  }
  /* Карточка эхонавта: строка рекордов на телефоне не влезает в ширину и
     распирала бокс, включая горизонтальную прокрутку всей страницы. Уменьшаем
     шрифт (на десктопе он остаётся крупным) и разрешаем перенос. */
  .profile-item { padding: 10px 8px; gap: 8px; }
  .profile-item-name { font-size: 16px; }
  /* letter-spacing 0: разрядка съедала те самые ~10 px, из-за которых
     «Новый эхонавт» не помещался и обрывался многоточием. */
  .profile-item-level { font-size: 11.5px; letter-spacing: 0; }
  .profile-item-sub { font-size: 11px; }
  /* Портрет чуть мельче: на 360 px каждый пиксель ширины уходит в текст,
     а три строки должны читаться целиком, без многоточий. */
  .profile-item-ava { width: 48px; height: 48px; }

  #atlas-header { padding-bottom: 8px; margin-bottom: 8px; gap: 8px; }
  #atlas-title { font-size: 17px; letter-spacing: 2px; }
  #atlas-header-right { gap: 10px; }
  #atlas-progress { font-size: 12px; }
  #atlas-oi { font-size: 15px; }
  #atlas-color-tabs { gap: 4px; margin-bottom: 8px; }
  .atlas-color-tab { font-size: 11px; padding: 6px 8px; flex: 1; }
  /* Справка по цвету: на телефоне это 5–6 строк, поэтому ограничена по высоте и
     прокручивается внутри себя — сетка карточек не должна уезжать за экран. */
  #atlas-color-desc {
    font-size: 11.5px; line-height: 1.45;
    padding: 7px 9px; margin-bottom: 8px;
    max-height: 22vh; overflow-y: auto;
  }
  #atlas-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px; margin-bottom: 10px;
  }
  .atlas-card { padding: 8px; gap: 6px; }
  .atlas-card-name { font-size: 14px; }
  .atlas-card-stats { font-size: 12px; }
  .btn-atlas-decipher { font-size: 12px; padding: 6px 6px; }
  .btn-atlas-prize    { font-size: 12px; padding: 6px 6px; }
  #btn-atlas-continue { font-size: 15px; padding: 10px; }

  /* Магазин: табы организаций сверху, видна одна панель */
  #shop-org-tabs {
    display: flex;
    gap: 6px;
    margin-bottom: 6px;
  }
  #shop-panels { display: block !important; margin-bottom: 8px; }
  .org-panel { display: none !important; margin-bottom: 0; padding: 10px !important; }
  .org-panel.org-active { display: block !important; }
  /* Круглая эмблема в правом верхнем углу развёрнутой панели — маленькая, не мешает заголовку */
  [data-equipment-art="on"] .org-emblem {
    display: block !important;
    width: 56px; height: 56px;
    top: -4px; right: -4px;
    opacity: .85;
    -webkit-mask-image: none;
    mask-image: none;
  }
  /* Шоп-бокс на мобильном — full width, без лишних отступов */
  #shop-box { max-width: 100% !important; width: 100% !important; padding: 8px !important; }
  /* Отступ под кнопку ТЕСТ отсюда убран вместе с самой кнопкой (30.08.2026):
     она больше не стоит в углу витрины и ресурсам строку не заслоняет. */
  /* Заголовок «Перед Слой 2» / «🏛 ОРГАНИЗАЦИИ» — на мобильном не нужны (экономим экран) */
  #shop-header { display: none; }
  /* Ресурсы — РОВНО 2 ряда:
     ряд 1 = Данные + стабилата + кредита (деньги подняты сюда),
     ряд 2 = Связность + заряд + слоты. */
  #shop-res {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* #26: шапка ресурсов крупнее (12→14px), пропорционально товарам вкладки */
    font-size: 14px;
    padding: 6px 8px;
    margin-bottom: 6px;
    text-align: left;
  }
  #shop-res .res-divider { display: none; }
  .sres-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
  }
  /* первый ряд: данные равномерно распределены по всей ширине строки */
  .sres-row-1 { justify-content: space-between; gap: 2px 10px; }
  /* второй ряд: оставляем компактным, но центрируем */
  .sres-row-2 { justify-content: center; gap: 2px 14px; }
  .sres { white-space: nowrap; justify-content: flex-start; font-weight: bold; }
  /* Заголовок организации — компактнее */
  .org-title { font-size: 15px; margin-bottom: 2px; letter-spacing: 1px; }
  .org-desc  { font-size: 11px; margin-bottom: 6px; }
  .org-tabs  { margin-bottom: 6px; gap: 4px; }
  .org-tab   { font-size: 12px !important; padding: 6px 8px !important; min-height: 36px !important; }
  /* Карточка товара — компактнее, чтобы 4 шт. влезали без скролла */
  .shop-items { gap: 6px; }
  .shop-item  { padding: 6px 8px; gap: 2px; }
  /* #26: самые мелкие шрифты магазина крупнее (+~15-20%), цены жирные */
  .item-name  { font-size: 15px; line-height: 1.25; word-break: keep-all; }
  .item-cost  { font-size: 13px; font-weight: bold; }
  .item-win-hint { font-size: 11px; }
  .item-badge { font-size: 13px; top: 5px; right: 6px; }
  .btn-shop   { font-size: 11px !important; padding: 5px 10px !important; min-height: 30px !important; margin-top: 1px !important; }
  /* shop-item с иконкой (Накопитель, Щит) — иконка мельче, имя в одну строку,
     а «Купить» спанит обе колонки, чтобы стоять у левого края как у обычных товаров */
  [data-equipment-art="on"] .shop-item:has(.shop-item-art) {
    grid-template-columns: 42px 1fr;
    grid-template-areas:
      "art name"
      "art hint"
      "art cost"
      "btn btn";
    gap: 2px 8px;
  }
  [data-equipment-art="on"] .shop-item .shop-item-art { width: 42px; height: 42px; }
  /* Сообщение магазина пустое — не занимает место */
  .shop-msg { min-height: 0; font-size: 12px; margin-bottom: 4px; }
  .shop-msg:empty { display: none; }
  /* Кнопка «Продолжить» — компактнее */
  #btn-shop-continue { font-size: 14px !important; padding: 10px 14px !important; }
  /* #162: три равные кнопки подвала. На узком экране колонка ≈110px, поэтому
     шрифт у ВСЕХ трёх один (12px без разрядки) и подпись не переносится —
     иначе «Слой 2 →» ломался на две строки и кнопка становилась выше соседей. */
  #shop-footer { gap: 6px; }
  .shop-footer-side,
  #shop-footer #btn-shop-continue {
    font-size: 12px !important; letter-spacing: 0;
    padding: 10px 6px !important; white-space: nowrap;
  }

  /* Профиль: одна колонка, слоты по два в ряд */
  #pcard-overlay { padding: 8px; }
  #pcard-box { padding: 14px 12px; max-height: calc(100vh - 16px); }
  #pcard-name { font-size: 18px; letter-spacing: 2px; }
  #pcard-ava { width: 44px; height: 44px; }
  #pcard-body { grid-template-columns: 1fr; gap: 10px; }
  .pcard-rows { font-size: 14px; }

  /* ─── #176: левая часть (ПОГРУЖЕНИЕ) — выдвижной ящик, как СИГНАТУРЫ ──────────
     Две колонки в 360px не помещаются, а ужимать слоты запрещено. Поэтому в
     потоке остаётся только правая часть (уровень + статистика), а погружение
     выезжает поверх неё свайпом от ЛЕВОГО края (закрытие — свайпом влево),
     кнопкой «◀ ПОГРУЖЕНИЕ» и нажатием на ручку. Направление зеркально СИГНАТУРАМ:
     тот живёт справа, этот — слева, каждый со своей стороны экрана. */
  /* Ящик занимает ВСЮ ширину экрана. Это не косметика: слоты обязаны быть той же
     ширины, что в слое (#170), а любая боковая рамка или торчащая ручка отъели бы
     у них те самые пиксели. Поэтому ручка — горизонтальная полоса сверху. */
  #pcard-run {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: 100vw; max-width: 100vw;
    background: var(--bg);
    box-shadow: 8px 0 30px rgba(0,0,0,.7);
    z-index: 30;                     /* поверх #pcard-box в его контексте */
    transform: translateX(-100%);
    transition: transform var(--t-in) ease-out;
    display: flex; flex-direction: column;
    padding: 0;
  }
  #pcard-run.opened { transform: translateX(0); }
  #pcard-run-inner {
    flex: 1; min-width: 0;
    overflow-y: auto; overscroll-behavior: contain;
    /* 6px — те же поля, что у страницы в слое: по ним fitPcardSlots считает
       ширину сетки слотов. Менять только вместе с PAGE_PAD в game.js. */
    padding: 8px 6px 16px;
    gap: 10px;
  }
  #pcard-run-handle {
    display: flex; align-items: center; justify-content: space-between;
    flex: 0 0 auto;
    padding: 9px 12px;
    background: var(--panel);
    border-bottom: 1px solid var(--teal);
    cursor: pointer;
  }
  /* Слева — полоска-грип (за неё тянут), справа — прямая подсказка: свайп
     угадывается не всеми, а промахнуться мимо жеста легко. */
  #pcard-run-handle::before {
    content: '';
    width: 46px; height: 4px; border-radius: 2px;
    background: rgba(78,205,196,.55);
  }
  #pcard-run-handle::after {
    content: 'ПОГРУЖЕНИЕ · закрыть ✕';
    font-size: 11px; letter-spacing: 1px; color: var(--dim);
  }
  .pcard-run-top { grid-template-columns: 1fr; gap: 10px; }
  /* Кнопка вызова ящика — в правой части, под статистикой. */
  #pcard-run-open {
    display: block; width: 100%;
    font-family: var(--font-mono);
    font-size: 13px; letter-spacing: 1px;
    color: var(--teal);
    background: rgba(78,205,196,.1);
    border: 1px solid rgba(78,205,196,.5);
    border-radius: 3px;
    padding: 11px 8px;
    cursor: pointer;
  }
  /* #170 (критично для смартфона): слоты обязаны быть той же ширины, что в слое.
     Ширину и сдвиг считает JS (fitPcardSlots) — сюда её не зашить: между сеткой
     и краем экрана лежат отступы оверлея, коробки и секции ПЛЮС полоса прокрутки
     #pcard-body, а она разной ширины на разных платформах (16px в настольном
     Chrome, 0 при overlay-скроллбарах телефона). Любое фиксированное число здесь
     промахнулось бы ровно на её толщину. */
  #pcard-overlay { padding: 6px; }
  #pcard-box { padding: 12px 6px; }
  /* Секция слотов на телефоне отдаёт всю ширину сетке: боковые поля обнулены,
     заголовок отступ сохраняет отдельно. */
  #pcard-slots { width: auto; max-width: none; }
  .pcard-sec-slots { padding-left: 0; padding-right: 0; }
  .pcard-sec-slots > .pcard-sec-title,
  .pcard-sec-slots > .pcard-hint { padding-left: 10px; padding-right: 10px; }
  /* Полоса прокрутки Профиля на телефоне — накладная (как системная на iOS/Android):
     иначе в мобильной эмуляции настольного браузера она съедает 16px ширины и ряд
     слотов оказывается уже игрового. */
  #pcard-body { scrollbar-width: none; }
  #pcard-body::-webkit-scrollbar { width: 0; height: 0; }
  .pcard-unlock-btn { font-size: 10px; padding: 4px 3px; letter-spacing: 0; }
  #pcard-footer button { font-size: 13px; letter-spacing: 1px; padding: 10px 8px; }

  /* Sidebar и постоянный Связность в шапке — только на мобильном */
  #btn-sidepanel { display: inline-flex; align-items: center; justify-content: center; min-height: var(--btn-min-h); }
  #header-hp { display: inline-flex; }
  #side-panel { display: flex; }
  /* На мобильном info-col визуально не нужен — содержимое доступно через sidebar */
  #info-col { display: none !important; }

  /* Hint-модалка: компактные размеры, ПРИНЯТО не должен уезжать за экран */
  .hint-header { padding: 10px 14px 8px; }
  /* #: заголовок окон-сообщений («ЭХОКАМЕРА | …» + «УРОВЕНЬ ДОПУСКА: N»)
     не влезал в одну строку на узких экранах (≤360px) и переносился.
     Поджат letter-spacing + размер, спаны в nowrap — самый длинный
     («ОТЧЁТ ОБ ОБРАЗЦЕ») влезает в одну строку с запасом. */
  .hint-header-top { font-size: 10px; letter-spacing: 0.3px; margin-bottom: 4px; }
  .hint-header-top span { white-space: nowrap; }
  #hint-label { font-size: 15px; letter-spacing: 1.5px; }
  .hint-body { font-size: 14px; padding: 14px 14px 12px; line-height: 1.55; min-height: 60px; }
  .hint-footer { font-size: 12px; padding: 10px 14px; gap: 8px; }
  .hint-check input { width: 14px; height: 14px; }
  #hint-close { font-size: 13px; padding: 8px 14px; letter-spacing: 1px; min-height: var(--btn-min-h); }

  /* ─── #53/#55/#60 + латентные: ВСЕ модалки входят в экран ───────────────
     Любое сообщение/диалог при большом содержимом прокручивается, кнопка
     действия всегда достижима (а не уезжает за нижний край экрана).
     #ency-box (энциклопедия) — экран полной версии, в демке его нет. */
  #hint-box, #mem-box, #decipher-box, #overlay-box, #ebm-box,
  #generic-confirm-box, #onboard-box, #ency-box, #fsm-box {
    max-height: 88vh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* #overlay-box (результат «Слой очищен»/«вы сорвались»): min-width:400px не
     влезает в узкий экран — снимаем. */
  #overlay-box { min-width: 0; width: 100%; max-width: 95vw; }
  /* #67: оверлей результата слоя — компактнее по высоте, заголовок −30%,
     кнопка «→ К ОРГАНИЗАЦИЯМ» в одну строку, рапорт контрастнее. */
  #overlay-box   { padding: 20px 18px; }
  #overlay-title { font-size: 25px; letter-spacing: 1.5px; margin-bottom: 8px; }
  #overlay-sub   { font-size: 14px; margin-bottom: 8px; }
  #overlay-stats { font-size: 14px; margin-bottom: 14px; }
  #overlay-stats .report-key { color: #a9c8d6; }
  #overlay-stats .report-val { color: #eaf6fb; }
  #btn-overlay-action { white-space: nowrap; padding: 11px 22px; font-size: 15px; letter-spacing: 1px; }
  /* #76: кнопки «Дальше»/«Расшифровать» ВСЕГДА в одну строку (критичное UI-правило).
     nowrap + гибкие ширины: «Дальше» компактная, «Расшифровать» тянется — цена в Данные
     всегда помещается (#103). */
  .decipher-footer { flex-wrap: nowrap; gap: 8px; }
  #decipher-box { padding: 16px 16px; }
  #decipher-body { font-size: 14px; }
  #btn-decipher-skip {
    font-size: 13px; padding: 8px 10px; min-height: var(--btn-min-h); letter-spacing: .3px;
    flex: 0 0 auto; white-space: nowrap;
  }
  #btn-decipher-pay {
    font-size: 13px; padding: 8px 12px; min-height: var(--btn-min-h); letter-spacing: .3px;
    flex: 1 1 auto; min-width: 0; white-space: nowrap;
  }
  /* #60: диалоги-подтверждения (возврат/уйти из организаций) — шрифт и кнопки
     заметно меньше, всё помещается. #111/#117/#132: плашка ниже, кнопки ближе
     к тексту, меньше межбуквенный интервал (без широких пробелов в «Да, иду»). */
  #shop-confirm-text, #generic-confirm-text { font-size: 14px; line-height: 1.4; margin-bottom: 8px; }
  #shop-confirm, #generic-confirm { padding: 9px 12px; }
  #shop-confirm-btns button, #generic-confirm-btns button {
    font-size: 13px; padding: 5px 14px; min-height: 40px; letter-spacing: .2px;
  }

  /* ─── #58: вертикальный fit слоя ─────────────────────────────────────
     Кнопки выхода/Архив/панель СИГНАТУРЫ и заголовок слоя ниже (44→36) — освобождают
     место, чтобы нижние слоты не обрезались. */
  #btn-exit-room, #btn-archive, #btn-test, #btn-sidepanel, #btn-settings {
    min-height: 36px;
  }
  /* Заголовок слоя из этого правила исключён намеренно: он не кнопка, пальцем в
     него не целятся, и лишние 10 px высоты здесь дороже — он и так занял целую
     строку (см. #layer-title-mobile выше). */
  #btn-exit-room { padding: 4px 10px; }
  /* #125: панель «ГЛАЗА X/X» (замена кнопки выхода у Массива) — та же компактная
     высота. Показывается ТОЛЬКО на мобильном: в базовых стилях она display:none,
     чтобы на десктопе кнопка выхода работала как раньше. */
  #boss-eyes-panel:not(.hidden) { display: flex; }
  #boss-eyes-panel { min-height: 36px; padding: 4px 12px; }

  /* #125/#59: боевая инфо Массива на мобильном живёт во вкладке СИГНАТУРЫ
     (#sp-boss-combat), а строка #boss-bar под сеткой скрыта — она съедала
     высоту, из-за которой не влезала слой. На десктопе #boss-bar остаётся.
     Компактные подписи; перенос разрешён — в сигнатурах есть место по ширине. */
  #boss-bar { display: none !important; }
  #sp-boss-combat { gap: 4px 10px; font-size: 12px; letter-spacing: 0; }
  #sp-boss-combat .boss-val  { font-size: 13px; }
}

/* ═══ ТУТОРИАЛ ═══════════════════════════════════════════════════ */
/* Панель сообщений занимает нижний ряд слотов (5–8), во всю ширину #tool-section.
   Зонд/Эхолуч (card-0/1) и пустые слоты 3–4 (card-2/3) остаются на местах.
   Оформление — машинный «электронный» шрифт 60-х: фосфорный текст + скан-линии. */
/* Шрифт панели туториала: Tektur — квадратный индустриальный, как маркировка
   военного защищённого оборудования середины XX века (с кириллицей). */
/* ═══ ШРИФТЫ СТИЛЯ «ГАЛЕРЕЯ» ═══
   Oswald — метки-капсы и заголовки, JetBrains Mono — числа и текст. Оба
   переменные по начертанию (одна запись покрывает весь диапазон веса), оба
   разложены на кириллицу и латиницу тем же способом, что Tektur.
   В МАКЕТАХ они подключены с Google Fonts — в игру так нельзя: Steam-сборка и
   мобильные должны работать без сети. Файлы лежат в web/fonts/, бандлер
   забирает оттуда все .woff2 сам. Лицензия у обоих OFL. */
@font-face {
  font-family: 'Oswald';
  font-style: normal; font-weight: 300 600; font-display: swap;
  src: url('fonts/Oswald-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Oswald';
  font-style: normal; font-weight: 300 600; font-display: swap;
  src: url('fonts/Oswald-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2013-2014, U+2018-2019, U+201C-201D, U+2026, U+2212;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/JetBrainsMono-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/JetBrainsMono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2013-2014, U+2018-2019, U+201C-201D, U+2026, U+2212;
}
@font-face {
  font-family: 'Tektur';
  font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/Tektur-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Tektur';
  font-style: normal; font-weight: 400 700; font-display: swap;
  src: url('fonts/Tektur-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2013-2014, U+2018-2019, U+201C-201D, U+2026, U+2212;
}
#tutorial-hint {
  grid-column: 1 / -1;           /* во всю ширину → отдельный нижний ряд */
  height: 121px;                 /* −10% от высоты ряда слотов (134px) — экран туториала короче */
  margin-top: 0;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  padding: 12px 16px;
  border: 2px solid rgba(120,255,150,.4);
  border-radius: 3px;
  background-color: #08160b;
  background-image: repeating-linear-gradient(
    0deg, rgba(0,0,0,.28) 0px, rgba(0,0,0,.28) 1px, transparent 1px, transparent 3px);
  color: #7cfc9a;
  font-family: 'Tektur', var(--font-mono);
  font-size: 16px; font-weight: 700;
  letter-spacing: .5px; line-height: 1.4;
  text-transform: uppercase;
  text-shadow: 0 0 6px rgba(120,255,150,.7), 0 0 2px rgba(120,255,150,.95);
  box-shadow: inset 0 0 20px rgba(120,255,150,.12);
  animation: tut-crt-flicker 3.5s steps(60) infinite;
}
#tutorial-hint.hidden { display: none; }
/* «ДАЛЕЕ» на панели приказов (финал обучения): дочитал — жмёт сам. */
#tutorial-hint .tut-next {
  flex: none; margin-left: 18px; padding: 8px 16px;
  font: inherit; font-size: 13px; letter-spacing: 1px;
  color: #08160b; background: #7cfc9a; border: 0; border-radius: 3px;
  text-shadow: none; cursor: pointer;
}
#tutorial-hint .tut-next:hover { filter: brightness(1.15); }
#tutorial-hint.tut-shake {
  animation: tut-shake var(--t-in) ease;
  border-color: #ff8a7a; color: #ff8a7a;
  text-shadow: 0 0 6px rgba(255,138,122,.7);
}
/* Жёлтый «внимание» — шаг переключения на Эхолуч */
#tutorial-hint.tut-attention {
  color: #f5d020;
  border-color: rgba(245,208,32,.6);
  text-shadow: 0 0 7px rgba(245,208,32,.8), 0 0 2px rgba(245,208,32,.95);
  box-shadow: inset 0 0 20px rgba(245,208,32,.14);
}
/* Помигать трижды при смене текста (перебивает crt-flicker на время) */
#tutorial-hint.tut-blink { animation: tut-blink var(--t-slow) ease; }
/* Критическая ошибка (задание №25): панель краснеет и говорит тремя строками.
   КЕГЛЬ ПОДОБРАН ЗАМЕРОМ, а не на глаз: каждая строка обязана встать в одну
   («ничто в одну строку не должно становиться двумя»). На поле 1440 под текст
   452 px; при 12 px без разрядки самая длинная строка — 422 px, при 13 px — 457,
   и она ломалась пополам. Высота панели зафиксирована — ряд под полем не прыгает. */
#tutorial-hint.tut-critical {
  flex-direction: column; gap: 4px;
  border-color: rgba(231,76,60,.7);
  background-color: #1a0808;
  color: #ff6b5b;
  text-shadow: 0 0 6px rgba(231,76,60,.7), 0 0 2px rgba(231,76,60,.95);
  box-shadow: inset 0 0 20px rgba(231,76,60,.15);
  font-size: 12px; line-height: 1.3; letter-spacing: 0;
}
#tutorial-hint .tut-line { display: block; }
/* На телефоне (390 px — 342 px под текст) строка не встаёт даже при 10,5 px:
   переносы там неизбежны, пока тексты такой длины. Кегль меньше, чтобы шесть
   строк уместились в высоту панели. */
@media (max-width: 600px) {
  #tutorial-hint.tut-critical { font-size: 11px; line-height: 1.25; }
}
@keyframes tut-blink {
  0%{opacity:1} 15%{opacity:.12} 30%{opacity:1} 45%{opacity:.12}
  60%{opacity:1} 75%{opacity:.12} 90%{opacity:1} 100%{opacity:1}
}
@keyframes tut-crt-flicker {
  0%,97%,100% { opacity: 1; }
  98% { opacity: .82; } 99% { opacity: .95; }
}
@keyframes tut-shake {
  0%,100% { transform: translateX(0); }
  20% { transform: translateX(-6px); } 40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); } 80% { transform: translateX(4px); }
}
/* Кнопка СИГНАТУР недоступна в туториале. Кнопки выхода в обучении нет вовсе:
   подъём из камеры запускает финал, когда оба тела вскрыты (tutorialFinaleNext). */
/* В туториале СИГНАТУРЫ виден, но неактивен (приглушён, клики игнорируются). */
/* Настройки в туториале тоже приглушены: у обучения свой выход (finishTutorial),
   а showMainMenu из него оставил бы TUT.active висеть на следующом погружении. */
.tut-active #btn-sidepanel,
.tut-active #btn-settings { opacity: .4 !important; pointer-events: none !important; cursor: default; }
.tut-active #btn-exit-room { visibility: hidden !important; }
/* После критической ошибки кнопка выхода открыта — на обычном месте (задание №25). */
.tut-active.tut-critical #btn-exit-room { visibility: visible !important; }
/* В обучении нижний ряд слотов (5–8) уступает место панели приказов — до финала:
   там панель уходит и показывает, что под ней четыре закрытых слота (tut-reveal). */
.tut-active:not(.tut-reveal) #card-4,
.tut-active:not(.tut-reveal) #card-5,
.tut-active:not(.tut-reveal) #card-6,
.tut-active:not(.tut-reveal) #card-7 { display: none !important; }
/* Подсветка слотов: Эхолуч на приказе «возьмите», слоты 3–4 и открывшиеся 5–8 в
   финале. Всё — классом на корне, а не на слоте: renderToolCards переписывает
   className слотов, и выданный им класс терялся бы молча (так и было у Эхолуча). */
.tut-echo #card-1,
.tut-reveal #card-4, .tut-reveal #card-5, .tut-reveal #card-6, .tut-reveal #card-7 {
  border-color: var(--gold) !important;
  box-shadow: 0 0 0 2px var(--gold), 0 0 16px rgba(240,208,96,.8) !important;
  animation: tut-pulse var(--t-slow) ease-in-out infinite;
}
/* Слоты 3–4 в финале мигают сильнее прочих подсветок: на них панель и показывает
   (заказчик, 11.09.2026: «должны мигать сильнее»). */
.tut-slots #card-2, .tut-slots #card-3 {
  border-color: var(--gold) !important;
  box-shadow: 0 0 0 3px var(--gold), 0 0 28px rgba(240,208,96,.95) !important;
  animation: tut-slot-blink .8s ease-in-out infinite;
}
@keyframes tut-slot-blink {
  0%,100% { filter: brightness(1); opacity: 1; }
  50%     { filter: brightness(1.9); opacity: .5; }
}
/* Цифра, которую называет приказ панели («Мигающая цифра 4…»). */
.cell.cell-tut-point {
  box-shadow: 0 0 0 3px var(--gold) inset, 0 0 16px rgba(240,208,96,.9) !important;
  animation: tut-slot-blink .8s ease-in-out infinite;
  z-index: 2;
}
@keyframes tut-pulse {
  0%,100% { filter: brightness(1); }
  50% { filter: brightness(1.5); }
}

/* Модалки туториала (предложение / завершено) */
#tutorial-offer-overlay, #tutorial-done-overlay {
  position: fixed; inset: 0;
  background: rgba(4,10,20,.82);
  display: flex; align-items: center; justify-content: center;
  z-index: 9650;
  font-family: var(--font-mono);
  padding: 16px;
}
#tutorial-offer-overlay.hidden, #tutorial-done-overlay.hidden { display: none; }
#tutorial-offer-box, #tutorial-done-box {
  width: clamp(280px, 90vmin, 460px);
  background: #07101c;
  border: 2px solid rgba(240,208,96,.5);
  border-radius: 3px;
  padding: 22px 24px;
  text-align: center;
  box-shadow: 0 0 40px rgba(240,208,96,.18);
}
#tutorial-offer-label, #tutorial-done-label {
  color: var(--gold); font-weight: bold; letter-spacing: 1px;
  font-size: 14px; margin-bottom: 14px;
}
#tutorial-offer-text, #tutorial-done-text {
  color: var(--text); font-size: 15px; line-height: 1.55; margin-bottom: 20px;
}
#tutorial-offer-btns { display: flex; flex-direction: column; gap: 10px; }
#tutorial-offer-btns button, #tutorial-done-btns button {
  font-family: var(--font-mono);
  font-size: 15px; font-weight: bold;
  padding: 12px 18px; border-radius: 3px; cursor: pointer;
  border: 2px solid rgba(78,205,196,.55);
  background: rgba(78,205,196,.1); color: var(--teal);
}
#btn-tutorial-ready { border-color: rgba(240,208,96,.7); color: var(--gold); background: rgba(240,208,96,.12); }
#tutorial-done-btns { display: flex; justify-content: center; }
#tutorial-done-btns button { padding: 12px 40px; }

/* ═══ КОД ПРИГЛАШЕНИЯ ═══════════════════════════════════════════════
   Первый экран закрытой версии. Держится на тех же цветах и кеглях, что
   выбор эхонавта: это соседние шаги одного входа. */
#invite-overlay {
  position: fixed; inset: 0;
  background: radial-gradient(circle at 50% 40%, #0a1830 0%, #040a14 80%);
  display: flex; align-items: center; justify-content: center;
  z-index: 9550;   /* выше выбора эхонавта (9500): сначала допуск */
  font-family: var(--font-mono);
  padding: 16px;
}
#invite-overlay.hidden { display: none; }
#invite-box {
  width: 486px; max-width: 92vw;
  padding: 32px 32px 26px;
  background: #051120;
  border: 2px solid rgba(78,205,196,.4);
  border-radius: 3px;
  box-shadow: 0 0 50px rgba(78,205,196,.18);
  text-align: center;
}
#invite-title {
  font-size: 22px; font-weight: bold; letter-spacing: 3px;
  color: #4ecdc4; text-shadow: 0 0 12px rgba(78,205,196,.45);
}
#invite-sub {
  margin: 10px 0 22px;
  font-size: 13px; line-height: 1.5;
  color: rgba(200,220,235,.72);
}
#invite-input {
  width: 100%; box-sizing: border-box;
  padding: 12px 14px;
  background: #030a14;
  border: 1px solid rgba(78,205,196,.45);
  border-radius: 3px;
  color: #eaf6ff;
  font-family: inherit; font-size: 20px;
  letter-spacing: 4px; text-align: center;
}
#invite-input:focus { outline: none; border-color: rgba(78,205,196,.95); }
#invite-error {
  min-height: 18px;          /* место занято всегда: текст ошибки не двигает кнопку */
  margin: 10px 0 4px;
  font-size: 12px; line-height: 1.4;
  color: rgba(200,220,235,.6);
}
#invite-error.invite-err { color: #ff6b6b; }
#btn-invite-ok {
  width: 100%;
  margin-top: 8px; padding: 12px;
  background: rgba(78,205,196,.12);
  border: 1px solid rgba(78,205,196,.6);
  border-radius: 3px;
  color: #4ecdc4;
  font-family: inherit; font-size: 15px; font-weight: bold; letter-spacing: 2px;
  cursor: pointer;
}
#btn-invite-ok:hover:not(:disabled) { background: rgba(78,205,196,.2); border-color: rgba(78,205,196,.9); }
#btn-invite-ok:disabled { opacity: .5; cursor: default; }

/* ─── КАРТОЧКА ЭХОНАВТА НА СТАНЦИИ ────────────────────────────────
   Раньше (класс .pcard-menu-mode) вне погружения здесь ПРЯТАЛИСЬ состояние,
   ресурсы, слоты и премии: погружения нет, RUN — пустой каркас из initRun(),
   и цифры были бы выдумкой. С 29.08.2026 сохранение поднимается при входе на
   станцию (enterStation), поэтому цифры настоящие, и заказчик просил их
   видеть: «имеет смысл показывать все его ресурсы… и как выглядят слоты для
   приборов и что там лежит». Прятать больше нечего — класс остался ради
   кнопки достижений и крестика.
   У чистого эхонавта в слотах пусто, а ресурсы нули — это и есть то, с чем он
   уйдёт в первое погружение, а не выдумка. */
#btn-pcard-ach {
  background: rgba(240,208,96,.08);
  color: var(--gold, #f0d060);
  border: 1px solid rgba(240,208,96,.55);
}
#btn-pcard-ach:hover { background: rgba(240,208,96,.18); }
/* В погружении подвал остаётся о погружении: достижения там — лишний повод уйти из
   Организаций, и кнопка прячется (на станции она на месте). */
#pcard-overlay:not(.pcard-menu-mode) #btn-pcard-ach { display: none; }
/* Крестик карточки на станции не нужен и вреден: карточка ЕСТЬ станция, и
   закрыть её значит уйти в пустоту. Уходят отсюда шапкой — в Атлас, в
   Организации, в погружение. Ровно то же решение, что у Организаций, где «×»
   не поставлен намеренно. Настройки эхонавта видны только здесь же. */
body.at-station #pcard-close { display: none; }
/* Настройки эхонавта видны только на станции: в погружении их менять поздно.
   display здесь именно flex — строка настроек набрана в один ряд, и `block`
   отсюда молча перебивал бы раскладку ниже по файлу. */
#pcard-settings { display: none; }
body.at-station #pcard-settings { display: flex; }

/* Кнопки окна допуска. «Отмена» появляется только при СМЕНЕ кода (backend.js):
   на первом запуске отменять нечего — за этим экраном игры ещё нет. */
#invite-btns { display: flex; gap: 10px; }
#invite-btns #btn-invite-ok { flex: 1 1 auto; width: auto; }
#btn-invite-cancel {
  flex: 0 0 auto;
  margin-top: 8px; padding: 12px 18px;
  background: none;
  border: 1px solid rgba(78,205,196,.3);
  border-radius: 3px;
  color: rgba(200,220,235,.7);
  font-family: inherit; font-size: 14px; letter-spacing: 1px;
  cursor: pointer;
}
#btn-invite-cancel:hover { border-color: rgba(78,205,196,.6); color: #cfe3ee; }
#btn-invite-cancel.hidden { display: none; }

/* Выбор языка в «Настройках». Кнопки те же, что у переноса прогресса, — здесь
   только пометка текущего: без неё выбранный язык виден лишь по самому тексту
   вокруг, а это и так очевидно только тому, кто оба языка знает. */
.settings-transfer-btns button.lang-on {
  color: var(--bg);
  background: var(--teal);
  border-color: var(--teal);
}

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ШАПКА СТАНЦИИ  (docs/design/Shop.html, Atlas.html, Pcard.html)
   Один ряд на четыре экрана — Атлас, Организации, Эхонавт, Архив. Слева кто
   играет, в середине разделы, справа «Погружение» с указанием слоя, динамик и
   «Меню». На слое и в комнате Массива её нет: оттуда выходят кнопкой
   «Выйти из слоя».
═══════════════════════════════════════════════════════════════════ */
/* Ширину шапка берёт У СВОЕГО ЭКРАНА, а не свою собственную. Раньше здесь
   стояли жёсткие 1060 px при коробках 1100 (Организации, Атлас), 1160
   (Эхонавт) и 1180 (Архив) — шапка выходила уже раздела под ней на 40–120 px,
   и это было видно на всех четырёх экранах разом (заказчик, 29.08.2026).
   max-width: 100 % — не calc от вьюпорта: шапка и коробка лежат в одном
   столбце, у них общий родитель, и только так они ужимаются одинаково. */
.station-bar {
  position: relative; z-index: 2;
  width: var(--station-w, 1060px); max-width: 100%;
  margin: 0 auto 14px;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  background: var(--panel); border: 1px solid var(--border-2); border-radius: var(--r);
}
.station-bar .n-who { display: flex; align-items: center; gap: 9px; padding-right: 4px; min-width: 0; }
.station-bar .rb-face { width: 34px; height: 34px; }
.station-bar .rb-nick { font-size: 15px; }
.n-div { width: 1px; height: 24px; background: rgba(126,168,190,.22); flex: 0 0 auto; }
.n-sect { display: flex; gap: 6px; }
.n-grow { flex: 1; }
.n-b {
  display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px;
  border: 1px solid var(--border-2); border-radius: var(--r);
  background: var(--panel-2); color: var(--dim);
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; white-space: nowrap;
  cursor: pointer; transition: border-color var(--t-tap), color var(--t-tap), background var(--t-tap);
}
.n-b:hover { border-color: rgba(78,205,196,.45); color: var(--teal-2); }
/* #310: подсветка «Организации» после предупреждения о медосмотре. Тот же
   жёлтый, что у тревожной кнопки погружения, — это указание, куда идти, а не
   украшение: гаснет, как только игрок туда зашёл. */
body.medcheck-hint .n-b[data-station-go="shop"] {
  border-color: var(--gold); color: var(--gold);
  box-shadow: 0 0 12px rgba(240,208,96,.35);
  animation: medcheck-pulse 1.6s ease-in-out infinite;
}
@keyframes medcheck-pulse {
  0%, 100% { box-shadow: 0 0 6px rgba(240,208,96,.25); }
  50%      { box-shadow: 0 0 16px rgba(240,208,96,.55); }
}

/* #307: разделы, закрытые до первого погружения. Затемнены и не отзываются на
   наведение — «сюда пока нельзя», а не «кнопка сломалась». */
.n-b-off, .n-b-off:hover {
  opacity: .38; cursor: default;
  border-color: var(--border); color: var(--dim-2);
}
/* Раздел, в котором игрок СЕЙЧАС, отмечен золотом — тем же, что выбранный
   инструмент в слое: один цвет на «вот здесь вы находитесь». */
.n-b-here, .n-b-here:hover {
  border-color: rgba(240,208,96,.55); background: rgba(240,208,96,.07); color: var(--gold);
}
.n-dive {
  white-space: nowrap; cursor: pointer;
  display: inline-flex; align-items: center; gap: 10px; padding: 7px 8px 7px 14px;
  border: 1px solid rgba(78,205,196,.55); border-left: 3px solid var(--teal);
  border-radius: var(--r); background: rgba(78,205,196,.08); color: var(--teal-2);
  font-family: var(--font-head); font-size: 13px; font-weight: 500;
  letter-spacing: 2.2px; text-transform: uppercase;
}
.n-dive:hover { background: rgba(78,205,196,.14); }
/* «ПОГРУЖЕНИЕ» — главное действие станции, и оно ЗОВЁТ (заказчик, 29.08.2026).
   Медленный перелив по кромке: 3.2 с, ровно один проход яркости по рамке и
   тексту. Не мигание — мигание на станции читалось бы как тревога, а тревожная
   кнопка тут уже есть, жёлтая (.n-dive-warn), и спутать их нельзя.
   Предупреждение перебивает зов: у него своя анимация ниже по каскаду. */
.n-dive { animation: dive-call 3.2s ease-in-out infinite; }
@keyframes dive-call {
  0%, 62%, 100% { border-color: rgba(78,205,196,.55); background: rgba(78,205,196,.08); box-shadow: 0 0 0 0 rgba(78,205,196,0); }
  80%           { border-color: rgba(78,205,196,.95); background: rgba(78,205,196,.17); box-shadow: 0 0 14px 0 rgba(78,205,196,.28); }
}
.n-dive:hover { animation: none; }
.n-dive-w { display: flex; align-items: center; gap: 8px; padding-left: 10px; border-left: 1px solid rgba(78,205,196,.28); }
.n-dive-n {
  white-space: nowrap; font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  letter-spacing: 0; color: var(--text); text-transform: none;
}
/* ЗНАК СЛОЯ в кнопке ПОГРУЖЕНИЕ. По умолчанию виден запасной вектор (.gi), а
   картинка — только после того, как она РЕАЛЬНО загрузилась: класс lc-file
   вешает onload самой картинки. Наоборот (прятать по onerror) означало бы
   пустое место всё время, пока файла нет — так было до 12.09.2026, пока знаков
   не нарисовали.
   РАЗМЕР: 26 px против 20 у вектора. Знак предметный — дверь, колокол,
   контейнер, — и на 20 px предмет не узнаётся, остаётся цветное пятно. */
.n-dive-ic { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex: 0 0 20px; color: var(--teal); }
.n-dive-ic .gi { height: 18px; }
.n-dive-ic.lc-file { width: 26px; height: 26px; flex: 0 0 26px; }
.n-dive-ic img { display: none; width: 26px; height: 26px; object-fit: contain; }
.n-dive-ic.lc-file .gi { display: none; }
.n-dive-ic.lc-file img { display: block; }
.n-dive-warn .n-dive-ic { color: #f2a93b; }
/* Мало Связности или заряда — кнопка желтеет со значком и МЕДЛЕННО дышит
   рамкой: 1.6 с, чтобы это читалось как предупреждение, а не как мигание. */
.n-dive-warn { border-color: rgba(243,156,18,.60); border-left-color: var(--yellow); background: rgba(243,156,18,.08); color: #f2a93b; animation: dive-warn-pulse 1.6s ease-in-out infinite; }
.n-dive-warn .n-dive-w { border-left-color: rgba(243,156,18,.32); }
.n-dive-warn .n-dive-n { color: #f2a93b; }
@keyframes dive-warn-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(243,156,18,0); }
  50%      { box-shadow: 0 0 0 2px rgba(243,156,18,.22); }
}
@media (prefers-reduced-motion: reduce) {
  .n-dive, .n-dive-warn { animation: none; }
}
.n-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex: 0 0 auto; cursor: pointer;
  border: 1px solid var(--border-2); border-radius: var(--r);
  background: var(--panel-2); color: var(--dim);
}
.n-ico:hover { border-color: rgba(78,205,196,.45); color: var(--teal-2); }
.n-b .gi, .n-dive .gi, .n-ico .gi { height: 14px; }
/* Динамик крупнее соседних знаков: у него нет подписи рядом, и в общем ряду
   он читался мельче всех (заказчик 30.08.2026). Кнопка 32×32 — запас есть. */
.n-ico .gi { height: 20px; }

/* Окна станции держат шапку и коробку в столбик, а не по центру: раньше
   коробка центрировалась во весь экран, и приставленный сверху ряд оказался бы
   ей на голове. */
#shop-overlay, #atlas-overlay, #pcard-overlay, #archive-overlay {
  flex-direction: column; align-items: center; justify-content: flex-start;
  padding-top: 18px;
}
/* ОДНА ШИРИНА НА ЧЕТЫРЕ РАЗДЕЛА (заказчик, 30.08.2026: «переключаюсь между
   Атласом, Эхонавтом, Организациями, Архивом — надо, чтобы все четыре были
   одинаковые по ширине»). Было четыре числа: 1100, 1100, 1160 и 1180 — рамка
   прыгала на каждом переходе, и это читалось как дёрганый интерфейс, а не как
   разные экраны.
   Взята САМАЯ ШИРОКАЯ из прежних (1180, Архив), а не средняя: сузить карточку
   эхонавта значило бы вернуть ей прокрутку, которую только что убрали
   («карточка обязана влезать в один экран»), а расширить Организации и Атлас
   безопасно — у обоих содержимое тянется.
   Число ОДНО и живёт здесь: коробки берут его этой же переменной. */
#shop-overlay, #atlas-overlay, #pcard-overlay, #archive-overlay { --station-w: 1180px; }
/* На станции эти окна — САМ экран, а не окно поверх игры: под ними больше нет
   ни главного меню, ни поля слоя, и полупрозрачная подложка показывала бы
   пустой каркас. */
body.at-station #shop-overlay,
body.at-station #atlas-overlay,
body.at-station #pcard-overlay,
body.at-station #archive-overlay { background: var(--bg); }

@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  /* Телефон: разделы значками без подписей — четыре слова по-русски в 390 px
     не встают в строку ни при каком кегле, а переносить ряд нельзя. */
  .station-bar { width: 100%; margin-bottom: 8px; padding: 6px 8px; gap: 6px; }
  .station-bar .n-who, .n-div { display: none; }
  .n-b { padding: 7px 9px; }
  .n-b span, .n-dive > span:not(.n-dive-w) { display: none; }
  .n-dive { padding: 7px 8px 7px 10px; gap: 6px; }
}

/* РАЗДЕЛ СТАНЦИИ — ТАКАЯ ЖЕ РАМКА, ЧТО У ШАПКИ И ПОЛОСЫ (заказчик, 09.09.2026:
   «основной блок находится в яркой рамке… сделать рамку как у остальных блоков
   сверху и снизу, не такую яркую»). Бирюзовый кант со свечением остался от той
   поры, когда это было ОКНО поверх игры и должно было выделяться; на станции
   раздел — сам экран, и три его блока (шапка, коробка, полоса плеера) обязаны
   читаться одним целым. Свечение снимается вместе с цветом: без канта оно
   висело бы бирюзовым ореолом ни от чего. */
body.at-station #pcard-box,
body.at-station #atlas-box,
body.at-station #shop-box,
body.at-station #archive-box {
  border-color: var(--border-2); border-radius: var(--r); box-shadow: none;
}

/* КАРТОЧКА ЭХОНАВТА ПОКАЗЫВАЕТСЯ ЦЕЛИКОМ, БЕЗ ВНУТРЕННЕЙ ПРОКРУТКИ (заказчик,
   09.09.2026). Ограничение высоты вместе с `overflow-y: auto` у тела карточки
   давало полосу прокрутки ВНУТРИ раздела: низ — настройки, режим игры, версия —
   уезжал под край, и добраться до него можно было только колесом внутри блока.
   Не влезло по высоте — прокручивается ВЕСЬ раздел вместе с шапкой и полосой
   (у окна станции свой `overflow-y: auto`), а сама карточка остаётся целой.

   Атлас и Архив здесь не трогаются: там внутри списки на сотни строк, и
   прокрутка списка — это не обрезанный блок. Их высота ужата под полосу
   плеера: шапка 54 + отступ 14, полоса 38 + отступ 14, поля окна 18 и 20. */
body.at-station #pcard-box { max-height: none; }
body.at-station #pcard-body { overflow-y: visible; }
body.at-station #atlas-box,
body.at-station #archive-box { max-height: calc(100vh - 158px); }

/* Пока шапка станции на месте, прежние кнопки переходов в подвалах не нужны:
   «← АТЛАС», «ПРОФИЛЬ» и «ПРОДОЛЖИТЬ» из подвала Организаций, «← АТЛАС» и
   «НАЗАД» из подвала Эхонавта, «ПРОДОЛЖИТЬ» из Атласа — всё это теперь разделы
   и «Погружение» в одном ряду наверху. В погружении шапки нет, и подвалы
   остаются единственным выходом: поэтому правило висит на признаке .at-station,
   а не убрано из разметки. */
body.at-station #btn-shop-atlas,
body.at-station #btn-shop-profile,
body.at-station #btn-shop-continue,
body.at-station #btn-pcard-atlas,
body.at-station #btn-pcard-back,
body.at-station #btn-atlas-continue { display: none; }
/* Подвал Организаций без кнопок схлопывается: оставлять пустую полосу незачем. */
body.at-station #shop-footer:not(:has(button:not([style*="display: none"]))) { padding: 0; }

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ОРГАНИЗАЦИИ  (docs/design/Shop.html)
   Витрина ОДНА и во всю ширину. До этого три организации стояли рядом в три
   колонки: каждая узкая, у каждой свой заголовок, свои вкладки «Стандарт /
   Эксклюзивы» и свой список — три одинаковых интерфейса на одном экране.
   Выбор идёт вкладкой с кадром организации, у выбранной кадр разворачивается
   полосой 148 px.
═══════════════════════════════════════════════════════════════════ */
#shop-org-tabs { display: flex; gap: 8px; margin-bottom: 14px; }
.shop-org-tab {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 13px 5px 5px; cursor: pointer;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--panel-2); color: var(--dim-2);
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  transition: border-color var(--t-tap), color var(--t-tap), background var(--t-tap);
}
.shop-org-tab img {
  /* Кадр, а не значок: 36×26 — узкая полоска, по которой узнаётся именно снимок
     помещения. В квадрате 26×26 от широкого кадра оставался тёмный кусок стены,
     по которому не отличить Госпиталь от Канала. */
  width: 36px; height: 26px; object-fit: cover; object-position: center 45%;
  border-radius: 1px; display: block; flex: 0 0 auto;
}
.shop-org-tab:hover { border-color: rgba(78,205,196,.45); color: var(--teal-2); }
.shop-org-tab.active {
  border-color: rgba(240,208,96,.55); background: rgba(240,208,96,.06); color: var(--gold);
}
.shop-org-tab.tab-locked { opacity: .4; cursor: not-allowed; }

#shop-panels { display: block; margin-bottom: 14px; }
.org-panel { display: none; padding: 0; background: none; border: 1px solid var(--border); }
.org-panel.org-active { display: block; }
/* Кадр организации полосой в шапке витрины. Название и вкладки лежат НА кадре,
   поэтому низ кадра затемнён: иначе белые буквы теряются в светлых местах. */
.org-shot { position: relative; height: 148px; overflow: hidden; border-bottom: 1px solid var(--border); }
.org-shot img { width: 100%; height: 100%; object-fit: cover; object-position: center 42%; display: block; }
.org-shot::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,7,13,.35) 0%, rgba(4,7,13,.15) 42%, rgba(4,7,13,.92) 100%);
}
/* Название, описание и вкладки лежат НА кадре, по его нижней кромке. Селектор
   повторён с признаком [data-equipment-art], иначе его перебивает прежнее
   правило с тем же признаком: оно возвращает position: relative, и строки
   съезжали под кадр — ровно то, что стиль убирает. */
.org-panel > .org-head,
[data-equipment-art="on"] .org-panel > .org-head {
  position: absolute; left: 20px; right: 18px; top: 86px; z-index: 2; margin: 0;
}
/* Имя организации на кадре — БЕЛОЕ у всех трёх. Цвет здесь ничего не кодирует
   (зелёный Госпиталь, бирюзовый Институт), а на кадре цветные буквы теряются;
   различает витрины сам кадр. Селектор с id — иначе его перебивают прежние
   правила #org-hospital .org-title и т. д. */
.org-panel .org-head .org-title,
#org-hospital .org-head .org-title,
#org-institute .org-head .org-title,
#org-market .org-head .org-title {
  position: static; margin: 0;
  font-family: var(--font-head); font-size: 19px; font-weight: 500; letter-spacing: 4px;
  text-transform: uppercase; color: var(--head);
}
/* Чем это место отличается от соседнего — одной строкой. Без неё три витрины
   различались только кадром и списком товаров. */
.org-sub { margin-top: 6px; font-size: 12px; color: var(--dim); max-width: 62%; }
.org-panel > .org-tabs,
[data-equipment-art="on"] .org-panel > .org-tabs {
  position: absolute; right: 18px; top: 100px; z-index: 2; margin: 0;
}
/* Подпись под товарами: почему витрина такая, какая есть. */
.org-note {
  padding: 0 16px 14px; font-size: 11.5px; line-height: 1.5; color: var(--dim);
}
.org-tab {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  padding: 6px 13px; border-radius: var(--r-s);
  border-color: var(--border-2); background: rgba(10,20,31,.75); color: var(--dim-2);
}
.org-tab.active { border-color: rgba(240,208,96,.55); background: rgba(240,208,96,.10); color: var(--gold); }
/* Круглая эмблема с кадра УБРАНА: в макете её нет, а кадр и есть лицо
   организации. Узел остаётся в разметке невидимым — по нему идёт чит
   тест-режима (десять нажатий по эмблеме Канала); тот же чит работает и по
   заголовку, так что ничего не потеряно. */
.org-panel .org-emblem,
[data-equipment-art="on"] .org-panel .org-emblem {
  display: block; top: 8px; right: 8px; width: 54px; height: 54px;
  opacity: 0; -webkit-mask-image: none; mask-image: none; z-index: 2;
}
.org-panel > .shop-items { padding: 14px 16px 16px; }

/* Товар — СТРОКА во всю ширину, а не карточка в узкой колонке: значок, название
   с эффектом, цена, кнопка. В три колонки название переносилось на три строки,
   и «Стабилизация Стабилатом +1 Связности» занимало столько же места, сколько
   весь кадр организации. */
.shop-items { gap: 8px; }
.shop-item {
  display: grid; align-items: center;
  grid-template-columns: 40px 1fr auto auto; gap: 14px;
  padding: 9px 12px; background: var(--panel-2); border-color: var(--border);
}
.shop-item .item-badge {
  position: static; display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; font-size: 20px;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
}
.shop-item .shop-item-art { width: 40px; height: 40px; object-fit: contain; grid-row: 1; grid-column: 1; }
[data-equipment-art="on"] .shop-item:has(.shop-item-art) .item-badge { display: none; }
.item-name { font-size: 14.5px; color: var(--text); }
/* Что товар ДЕЛАЕТ — отдельным цветом и с отбивкой: в макете это не часть
   названия. Слитно «Стабилизация +1 Связности» читалось одной длинной фразой. */
.item-eff { margin-left: 10px; }
.eff-teal { color: var(--teal); }
.eff-gold { color: var(--gold); }
.eff-dim  { color: var(--dim); }
.item-cost { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--dim); white-space: nowrap; }
/* Кнопка покупки — КНОПКА: рамка и фон, как в макете. Голый текст справа от
   цены читался как ещё одна подпись, а не как то, на что надо нажать. */
.shop-item .btn-shop {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  padding: 7px 14px; border-radius: var(--r-s);
  background: rgba(240,208,96,.07); border: 1px solid rgba(240,208,96,.50); color: var(--gold);
}
.shop-item .btn-shop:hover:not(:disabled) { background: rgba(240,208,96,.16); }
.shop-item .btn-shop:disabled {
  background: rgba(126,168,190,.03); border-color: rgba(126,168,190,.22); color: var(--dim);
}
.btn-shop {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; white-space: nowrap;
}
.item-win-hint { grid-column: 2; font-size: 11px; color: var(--gold); }
/* КОНТЕЙНЕР КСИЛЛА — СТРОКА, А НЕ ПЛАШКА (заказчик, 15.09.2026: «не делай
   контейнер ксилла такой широкой плашкой, уменьши её по высоте раза в
   полтора»). Высоту держали три вещи: картинка 40 px, поля 9 px и подпись
   «необходим, чтобы выиграть игру» ОТДЕЛЬНОЙ строкой сетки. Подпись ушла
   вправо, в ту же строку, где название, картинка и поля — мельче. */
/* ПЯТЬ КОЛОНОК, А НЕ ЧЕТЫРЕ, И МЕСТО КАЖДОМУ НАЗВАНО ЯВНО. Первая редакция
   просто убрала у подписи `grid-column: 2` — и стало хуже: подпись встала в
   третью колонку, а кнопка уехала на вторую строку сетки. Высота осталась
   прежней (замер: 79 px против 60 у соседних строк), хотя картинка и поля уже
   были мельче. Отказ тихий: строка выглядит «просто широкой». */
#xyll-container-item {
  /* Поля — общие со всей витриной (9 px): строка обязана стоять в одном ритме с
     соседями. Замер: 79 px было, 52 стало — ровно «в полтора раза» из
     постановки; на 5 px полей выходило 43, то есть строка проваливалась бы
     ниже соседних шестидесяти. */
  padding: 9px 12px; gap: 10px;
  grid-template-columns: 26px 1fr auto auto auto;
}
#xyll-container-item .shop-item-art,
#xyll-container-item .item-badge { grid-column: 1; grid-row: 1; width: 26px; height: 26px; font-size: 15px; }
#xyll-container-item .item-name     { grid-column: 2; grid-row: 1; font-size: 13.5px; }
#xyll-container-item .item-win-hint {
  grid-column: 3; grid-row: 1; font-size: 10.5px; letter-spacing: .3px;
  white-space: nowrap; align-self: center;
}
#xyll-container-item .item-cost { grid-column: 4; grid-row: 1; }
#xyll-container-item .btn-shop  { grid-column: 5; grid-row: 1; padding: 5px 12px; }

/* Эксклюзив в общем ряду: та же строка, только с фиолетовым оттенком — чтобы
   при обеих включённых категориях было видно, где кончается стандарт. */
.shop-item.equip-item { background: rgba(155,89,182,.06); border-color: rgba(155,89,182,.30); }
.shop-item.equip-item .item-cost { color: var(--gold); }
/* Знак Связности в строке товара — чуть выше буквы и с воздухом справа:
   вплотную к «+1» он читается как часть числа. */
.item-eff .gi { height: 1.15em; margin-right: 4px; vertical-align: -0.2em; }
/* Знаки Надлома в строке щита — красные и КРУПНЕЕ подписи: перечёркнутая
   кардиограмма ростом со строчную букву превращается в три чёрточки и не
   читается вовсе. */
.item-eff .ic-wound { color: var(--red); height: 1.45em; margin-right: 3px; vertical-align: -0.32em; }

/* ─── КАТЕГОРИИ ВИТРИНЫ (чекбоксы) ───────────────────────────────
   Вид тот же, что у прежних вкладок, но перед подписью — квадрат отметки:
   без него две подсвеченные кнопки читаются как «две активные вкладки», а не
   как две поставленные галки. Заливка квадрата и есть галка. */
.org-cat { display: inline-flex; align-items: center; gap: 8px; }
.org-cat::before {
  content: ""; display: block; width: 10px; height: 10px;
  border: 1px solid currentColor; border-radius: 2px;
  background: transparent; flex: 0 0 auto;
}
.org-cat.active::before { background: currentColor; box-shadow: inset 0 0 0 2px rgba(10,20,31,.9); }
.org-cat.tab-locked::before { opacity: .5; }
/* Галка «Эксклюзивы» — фиолетовая, тем же цветом, что названия эксклюзивов и
   рамки их строк (заказчик, 09.09.2026). Золотой она читалась как ещё одна
   вкладка стандарта; теперь по цвету видно, что она включает именно тот
   список, который ниже подсвечен фиолетовым. */
.org-cat[data-cat="equipment"] { color: rgba(200,160,224,.55); border-color: rgba(155,89,182,.32); }
.org-cat[data-cat="equipment"]:hover:not(:disabled) { color: #d9bdea; border-color: rgba(155,89,182,.6); }
.org-cat[data-cat="equipment"].active {
  color: #d9bdea; border-color: rgba(155,89,182,.62); background: rgba(155,89,182,.14);
}
/* Обе галки сняты — витрина пуста, и это надо объяснить словами. */
.org-cats-empty { padding: 14px 16px 18px; font-size: 12.5px; color: var(--dim); }

/* ─── ШАПКА ВИТРИНЫ ──────────────────────────────────────────────
   Слева название с шестицветной полоской набора эхонавтов, справа запасы.
   Полоска — подпись стиля: она же стоит под заголовками на других экранах и
   показывает набор целиком. */
#shop-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; margin-bottom: 16px; text-align: left;
}
#shop-title {
  font-family: var(--font-head); font-size: 22px; font-weight: 500;
  letter-spacing: 5px; text-transform: uppercase; color: var(--head);
  display: flex; align-items: center; gap: 10px;
}
#shop-head-left::after {
  content: ""; display: flex; width: 210px; height: 3px; margin-top: 11px;
  background: linear-gradient(90deg,
    #63c246 0 16.6%, #d94b6a 16.6% 33.3%, #d99a3a 33.3% 50%,
    #cf3b32 50% 66.6%, #8a5bd6 66.6% 83.3%, #eb9a3a 83.3% 100%);
}
#shop-subtitle:not(:empty) { margin-top: 8px; font-size: 13px; color: var(--yellow); }
.sres-row-1 { display: flex; align-items: center; gap: 16px; }
.sres { font-size: 16px; font-weight: 600; color: var(--text); gap: 6px; line-height: 1; }
.sres .gi, .sres .oi-ico { height: 17px; }
.sres.teal   .gi { color: var(--teal); }
.sres.green  .gi { color: var(--green); }
.sres.yellow .gi { color: var(--yellow); }
.sres.red    .gi { color: #e0708a; }
.sres.gold   .gi { color: var(--gold); }
/* Значок ЗАРЯДА золотой даже внутри бирюзовой строки (заказчик, 06.09.2026):
   цвет величины важнее цвета строки. Правило записано с классом строки, иначе
   `.sres.teal .gi` выше перебивает его специфичностью — ровно на этом уже
   спотыкались с пустым делением Связности в карточке эхонавта. */
.sres .gi.gi-gold { color: var(--gold); }
/* Строка состояния: Связность, контур, слоты — подписи капсами, числа моно. */
#shop-res {
  display: flex; align-items: center; justify-content: flex-start; gap: 0;
  padding: 9px 14px; margin-bottom: 14px; text-align: left;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--r);
}
.sres-row-2 { display: flex; align-items: center; gap: 16px; }
.sres-div { width: 1px; height: 20px; background: var(--border-2); flex: 0 0 auto; }
.sres-k {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 1.8px; text-transform: uppercase; color: var(--dim);
}
.sres-row-2 .sres { gap: 8px; color: var(--text); }

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: КАРТОЧКА ЭХОНАВТА  (docs/design/Pcard.html)
   Портрет — во всю высоту левой колонки. Раньше он был аватаркой 56 px в шапке
   рядом с именем; в этом стиле эхонавт и есть лицо, и тот же кадр стоит в шапке
   слоя, в карточке на экране выбора и на экране итога.
═══════════════════════════════════════════════════════════════════ */
/* Шапка: слева название, справа ДВЕ ПРИБОРНЫЕ СТРОКИ — состояние и запасы.
   Раньше это были две панели внизу окна: девять чисел занимали треть высоты, и
   карточка перестала помещаться в экран (заказчик, 29.08.2026). */
#pcard-header { border-bottom: 0; align-items: flex-start; gap: 22px; padding-bottom: 0; margin-bottom: 10px; }
#pcard-head-left { flex: 0 0 auto; }
/* Заголовок и кнопка смены эхонавта — одной строкой; цветная полоса набора
   (#pcard-head-left::after) остаётся под ними, поэтому колонка. */
#pcard-head-left { display: flex; flex-direction: column; align-items: flex-start; }
#pcard-title-row { display: flex; align-items: center; gap: 14px; }
/* Кнопка-ссылка: не спорит с «ПОГРУЖЕНИЕ» в шапке станции — та зовёт, эта
   просто стоит рядом с названием раздела. */
#btn-pcard-nav {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 10px; border: 1px solid var(--border-2); border-radius: 3px;
  background: var(--panel-2); color: var(--dim);
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; cursor: pointer;
  transition: color var(--t-tap), border-color var(--t-tap);
}
#btn-pcard-nav .gi { height: 14px; }
#btn-pcard-nav:hover { color: var(--teal-2); border-color: var(--teal); }
#pcard-title {
  font-family: var(--font-head); font-size: 22px; font-weight: 500;
  letter-spacing: 5px; text-transform: uppercase; color: var(--head);
}
#pcard-strips {
  flex: 1 1 auto; min-width: 0;
  display: flex; justify-content: flex-end; padding-top: 2px;
}
.pcard-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  padding: 7px 14px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--r);
}
.pcard-strip-part { display: inline-flex; align-items: center; gap: 12px; }
.pchip { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; color: var(--text); }
/* Значки ресурсов в полтора раза крупнее (заказчик): в 15 px новые силуэты —
   капля, искра, восьмиугольник — сливались в одинаковые пятна. */
.pchip .gi { height: 22px; color: var(--dim); }
.pchip b { font-weight: 600; line-height: 1; }
.pips-n { line-height: 1; }
.pchip.teal   .gi { color: var(--teal); }
.pchip.green  .gi { color: var(--green); }
.pchip.yellow .gi { color: var(--yellow); }
.pchip.red    .gi { color: #e0708a; }
.pchip.gold   .gi { color: var(--gold); }
.pchip.violet .gi { color: #b795f0; }
/* Деления Связности в приборной строке карточки: живые бирюзовые, ПОТЕРЯННОЕ
   красное — как в шапке слоя (.hp-pips .heart.empty). Правило нужно отдельно:
   `.pchip.teal .gi` красит внутри чипа ВСЁ подряд и перебивало цвет пустого
   деления, отчего третья кардиограмма выглядела просто тусклой. */
.pchip .hp-pips .heart.full  .gi { color: var(--teal); }
.pchip .hp-pips .heart.empty .gi { color: rgba(231,76,60,.85); }
.pchip-div { width: 1px; height: 18px; background: var(--border-2); flex: 0 0 auto; }
/* Подсказки шапки всегда упираются в правую кромку окна. */
#pcard-strips .has-tip::after { left: auto; right: 0; transform: none; }
#pcard-head-left::after {
  content: ""; display: flex; width: 160px; height: 3px; margin-top: 9px;
  background: linear-gradient(90deg,
    #63c246 0 16.6%, #d94b6a 16.6% 33.3%, #d99a3a 33.3% 50%,
    #cf3b32 50% 66.6%, #8a5bd6 66.6% 83.3%, #eb9a3a 83.3% 100%);
}
/* ДВЕ колонки, как в макете: кадр эхонавта во всю высоту и справа всё
   остальное. Третьей колонки «вечное» в макете нет — из-за неё слоты были
   зажаты в узкую середину, хотя в макете они идут во всю ширину. Панели
   уровня, статистики, бонусов и премий никуда не делись: они встали ПОД
   слотами, тем же рядом. Кадр 336 px — число из макета (.P2-shot). */
#pcard-body { grid-template-columns: 336px minmax(0, 1fr); }
/* Слоты стали НИЖЕ (заказчик: «сами по себе слоты можно сделать по вертикали
   меньше»). Правило #170 — про ШИРИНУ ряда, чтобы он совпадал с рядом в слое;
   высота им не связана, и здесь ряд не игровой: по нему не кликают в бою.
   Высота задана явно, а не «по содержимому»: иначе слот с картинкой и слот с
   замком выходят разной высоты и ряд гуляет. */
/* 96 px — по САМОМУ ВЫСОКОМУ содержимому: у занятого слота под названием
   стоит ещё строка режима («авто»), и на 88 px её срезало. Высота одна на все
   слоты: разная высота в ряду хуже лишних восьми пикселей. */
#pcard-slots .card-slot { min-height: 0; height: 96px; }
/* Подсказка прибора обязана ВЫЙТИ за карточку: у .card-slot стоит overflow
   hidden (рамка и заливка), и текст обрезался ровно по слоту — читались три
   слова из двадцати. z-index поднимает её над соседними слотами. */
#pcard-slots .card-slot.has-tip-node,
#pcard-rewards .card-slot.has-tip-node { overflow: visible; }
#pcard-slots .card-slot.has-tip-node:hover,
#pcard-rewards .card-slot.has-tip-node:hover { z-index: 20; }
/* ВЕРХНЕМУ РЯДУ подсказка падает ВНИЗ. Вверх ей некуда: #pcard-body
   прокручивается (overflow: auto) и режет всё, что вылезло за его кромку, —
   у первого ряда от подсказки оставалась одна последняя строка, и отказ был
   тихий (в DOM узел целый, на экране обрезок). Сам слот она при этом не
   накрывает — заслоняет соседа снизу, а это и есть то, о чём просили.
   Премий это не касается: они лежат внизу окна, и вверх место есть — там
   подсказка вниз, наоборот, упёрлась бы в подвал. */
#pcard-slots .card-slot:nth-child(-n+4) > .tip-node { bottom: auto; top: calc(100% + 6px); }
/* Крайние слоты: подсказка не должна вылезать за кромку окна. Сетка слотов —
   четыре столбца, премий — два. */
#pcard-slots .card-slot:nth-child(4n+1) > .tip-node { left: 0; transform: none; }
#pcard-slots .card-slot:nth-child(4n)   > .tip-node { left: auto; right: 0; transform: none; }
#pcard-rewards .card-slot:nth-child(2n+1) > .tip-node { left: 0; transform: none; }
#pcard-rewards .card-slot:nth-child(2n)   > .tip-node { left: auto; right: 0; transform: none; }
/* Картинка прибора КРУПНЕЕ, подпись прижата к низу карточки (заказчик):
   в 32 px новые рисунки снаряжения не читались, а имя висело посередине. */
/* #309: картинка предмета крупнее на 13 %, подпись ниже и плотнее — заказчик:
   «увеличь размер картинок предметов процентов на 10–15, подвинь надписи чуть
   вниз, межстрочный интервал между ними снизь, чтобы входило в слоты».
   Нижний отступ карточки ужат на те же пиксели, что прибавила картинка, — иначе
   подпись вылезла бы за 96 px, и ряд поехал бы. */
/* `justify-content` здесь управлял КОЛОНКАМИ, то есть горизонталью: со
   `space-between` единственная колонка вставала к левому краю. Вертикаль
   держат `align-content` и `margin-top: auto` у подписи — они и задумывались. */
#pcard-slots .card-inner { padding: 5px 4px 4px; gap: 0; align-content: space-between; }
#pcard-slots .card-cost { font-size: 9.5px; line-height: 1; }
#pcard-slots .card-art, #pcard-slots .card-art-img { width: 52px; height: 52px; margin: 1px auto 0; }
#pcard-slots .card-name { margin-top: auto; }
#pcard-slots .empty-plus { font-size: 15px; }
#pcard-slots .locked-icon { font-size: 13px; }
#pcard-slots .locked-icon .gi { height: 13px; }
#pcard-slots .pcard-unlock-btn { padding: 2px 6px; font-size: 10px; line-height: 1.1; margin: 0; }
#pcard-slots .empty-label { font-size: 10px; }
/* #301: премия — ТА ЖЕ ПЛИТКА, что слот снаряжения, и той же высоты. Строчная
   раскладка (.rew-fig / .rew-cap / .rew-side) жила ради метки «ЗАБРАТЬ»;
   метки больше нет — щелчок открывает окно с описанием, — и раскладка ушла
   вместе с ней. Внутренности берутся у #pcard-slots строкой ниже. */
#pcard-rewards .card-slot { min-height: 0; height: 96px; }
#pcard-rewards .card-inner { padding: 7px 4px 6px; gap: 0; justify-content: space-between; }
#pcard-rewards .card-art, #pcard-rewards .card-art-img { width: 42px; height: 42px; flex: 0 0 auto; }
#pcard-rewards .card-art { display: none; }
#pcard-rewards .card-name {
  font-size: 11px; letter-spacing: .6px; line-height: 1.15;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
#pcard-rewards .card-cost { font-size: 9.5px; line-height: 1.1; margin: 0; }
/* Знак внутри подписи (например «✦») обязан остаться ЗНАКОМ: без предела по
   высоте он растягивался во всю карточку белой звездой. */
#pcard-rewards .card-name .gi, #pcard-slots .card-name .gi { height: 12px; vertical-align: -1px; }
/* Настройки — ОДНА строка: галочка, режим, версия через разделители. */
#pcard-settings {
  display: flex; align-items: center; flex-wrap: nowrap; gap: 14px;
  padding: 7px 12px;
}
.pcard-set-row {
  display: inline-flex; align-items: center; gap: 8px; margin: 0; padding: 0;
  border: 0; background: none; color: var(--text);
  font-family: var(--font-mono); font-size: 13px; cursor: pointer;
}
.pcard-set-row input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--teal); cursor: pointer; }
.pcard-set-btn {
  padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--font-mono); font-size: 13px; color: var(--text);
}
.pcard-set-btn:hover { color: var(--teal-2); }
#menu-mode-val { color: var(--teal-2); font-weight: 600; }
.pcard-set-div { width: 1px; height: 16px; background: var(--border-2); flex: 0 0 auto; }
.pcard-set-ver { margin-left: auto; font-family: var(--font-mono); font-size: 11px; letter-spacing: 1px; color: var(--dim-2); }
/* «Достижения» — под бонусами, а не в подвале окна во всю ширину. */
#pcard-bonus-sec #btn-pcard-ach { width: 100%; margin-top: 10px; padding: 9px; }
/* Вечное — под погружением, ТРЕМЯ столбцами: уровень, статистика и бонусы
   встают в один ряд, и карточка перестаёт требовать прокрутки (заказчик,
   29.08.2026: «чтобы профиль влезал на один экран»). Двумя столбцами тот же
   набор шёл в два ряда и добавлял окну сотню с лишним пикселей. */
#pcard-meta {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  align-items: start; gap: 12px;
}
/* Настройки и кнопка ящика — во всю ширину ряда. */
#pcard-settings, #pcard-run-open { grid-column: 1 / -1; }
/* #308: «Последние бонусы» — КОЛОНКА НА ДВА РЯДА, вдоль премирования.
   Заказчик: «сейчас есть место снизу незанятое, растяни эту вкладку с бонусами
   вниз, чтобы колонка занимала всё пространство внизу рядом с премированием».
   Премирование при этом уезжает влево на две колонки — четыре плитки в ряд
   там помещаются, потому что сама плитка ужимается вместе с колонкой. */
.pcard-sec-rewards { grid-column: 1 / 3; }
#pcard-bonus-sec   { grid-column: 3; grid-row: 1 / 3; align-self: stretch; display: flex; flex-direction: column; }
/* Кнопка «Достижения» прижата к низу растянутой колонки, а не висит сразу под
   текстом: иначе внизу остаётся та самая пустота, ради которой всё и затеяли. */
#pcard-bonus-sec #btn-pcard-ach { margin-top: auto; }
/* СПИСОК БОНУСОВ ПРОКРУЧИВАЕТСЯ ВНУТРИ СЕБЯ (заказчик, 09.09.2026: «очень
   большой список, и он всё сдвигает вертикально»). К восемнадцатому уровню
   бонусов набирается два десятка, каждый в две-три строки, и колонка тянула
   вниз всю карточку — вместе с портретом и снаряжением, которым расти незачем.
   Потолок в долях экрана, а не в пикселях: на большом мониторе видно больше
   строк, на ноутбуке карточка всё равно остаётся целой.
   Это не спорит с «блок показывается целиком» (09.09.2026): целиком показан
   раздел, а внутри него прокручивается СПИСОК, у которого нет конца. */
#pcard-bonuses { max-height: 35vh; overflow-y: auto; padding-right: 4px; }
/* Раскладку премий задаёт правило ниже (две строки в ряд): четыре в ряд не
   оставляли места ни названию, ни кнопке «ЗАБРАТЬ». */
.pcard-run-top { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
/* Числа НЕ переносятся: «2 / 3» и «Слой 2», разорванные пополам, читаются как
   две разные величины. Настоящий моноширинный шире прежнего системного, и без
   nowrap колонка значений ломалась ровно там, где смысл. Место освобождает
   подпись — она обрезается многоточием, а не число. */
.pcard-rows { font-size: 13px; grid-template-columns: minmax(0, 1fr) auto; }
.pcard-row-key { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcard-row-val { font-weight: 600; white-space: nowrap; }
#pcard-shot {
  position: relative; grid-row: 1 / span 2; align-self: stretch;
  min-height: 380px; overflow: hidden;
  border: 1px solid var(--border-2); border-radius: var(--r); background: #060a12;
}
#pcard-shot #pcard-ava {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 22%;
}
/* Тёмная вуаль по низу кадра: имя набрано светлым, а на кадре внизу бывают
   яркие пятна — без вуали оно там пропадает. */
#pcard-shot-veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,7,13,0) 40%, rgba(4,7,13,.88) 100%);
}
#pcard-shot #pcard-ident { position: absolute; left: 18px; right: 18px; bottom: 20px; }
#pcard-name {
  font-family: var(--font-head); font-size: 30px; font-weight: 500;
  letter-spacing: 3px; text-transform: uppercase; line-height: 1;
}
#pcard-ident-row { display: flex; align-items: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
#pcard-level {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 1.6px; text-transform: uppercase; color: var(--gold);
  border: 1px solid rgba(240,208,96,.45); border-radius: var(--r-s);
  padding: 1px 7px; white-space: nowrap;
}
#pcard-decoded { font-size: 12px; color: var(--dim-2); }
#pcard-shot-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; }
.pcard-sec { background: var(--panel-2); border-color: var(--border); border-radius: var(--r); }
.pcard-sec-title {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 3px; text-transform: uppercase; color: var(--dim);
}
.pcard-sec-title::before {
  content: ""; width: 8px; height: 8px; flex: 0 0 auto;
  background: var(--teal); box-shadow: 0 0 8px rgba(78,205,196,.7);
}
/* Слоты и остальные разделы идут во всю оставшуюся ширину, под двумя верхними. */
.pcard-sec-slots { grid-column: 2 / -1; }

/* Настройки эхонавта набраны ОДНОЙ строкой — правила ниже, в разделе
   «Галереи»: галочка, режим игры и номер сборки через разделители. Тремя
   строками с заголовком они занимали столько же места, сколько статистика. */

@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  /* Телефон: кадр — полоса сверху, а не колонка. Колонка съела бы половину
     экрана, а слоты ужимать нельзя (правило #170). */
  #pcard-body { grid-template-columns: 1fr; }
  #pcard-shot { grid-row: auto; min-height: 132px; height: 132px; }
  #pcard-name { font-size: 22px; }
}

/* Названия оборудования в слотах Профиля бывают в два слова («Датчик слежения»,
   «Резервуар Ксилла»), а слот всё те же 117 px: ряд слотов Профиля ОБЯЗАН
   повторять ряд слотов в слое (правило #170), и расширить его нельзя. Поэтому
   в Профиле имя набирается мельче и в две строки — ряд сетки под него оставлен
   фиксированным, иначе подписи соседних слотов разъехались бы по высоте. */
#pcard-slots .card-name { font-size: 11px; letter-spacing: .8px; line-height: 1; padding-top: 2px; }
/* Раскладку премий (четыре в ряд во всю ширину) задаёт правило выше: раздел
   больше не стоит в узкой колонке, ради которой их ставили по два. */
#pcard-rewards .card-name { font-size: 10px; letter-spacing: .5px; }

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: АТЛАС И АРХИВ  (docs/design/Atlas.html, AtlasLayers.html, Archive.html)
   У Атласа название короткое — «АТЛАС», — а разделы ЭФЕМЕРЫ / СЛОИ встают на ту
   же линию первым уровнем; цветовые фильтры уходят вторым. До этого было три
   строки подряд: название, разделы, фильтры — три ряда управления над одной
   решёткой карточек.
═══════════════════════════════════════════════════════════════════ */
#atlas-header { align-items: center; gap: 22px; border-bottom: 0; }
#atlas-title, #archive-title {
  font-family: var(--font-head); font-size: 22px; font-weight: 500;
  letter-spacing: 5px; text-transform: uppercase; color: var(--head);
  display: flex; align-items: center; gap: 10px; flex: 0 0 auto;
}
/* У Архива под названием стоит полоска набора, поэтому заголовок — колонка. */
#archive-title { display: block; }
#atlas-view-tabs, #atlas-color-tabs, #archive-tabs { display: flex; gap: 6px; }
#atlas-view-tabs { margin: 0; }
#atlas-color-tabs { margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.atlas-view-tab, .atlas-color-tab, .archive-tab {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  padding: 6px 13px; border-radius: var(--r-s);
  border: 1px solid var(--border-2); background: var(--panel-2); color: var(--dim-2);
  cursor: pointer; transition: border-color var(--t-tap), color var(--t-tap), background var(--t-tap);
}
.atlas-view-tab:hover, .atlas-color-tab:hover, .archive-tab:hover { border-color: rgba(78,205,196,.45); color: var(--teal-2); }
.atlas-view-tab.active, .atlas-color-tab.active, .archive-tab.active {
  border-color: rgba(240,208,96,.55); background: rgba(240,208,96,.06); color: var(--gold);
}
#atlas-header-right { margin-left: auto; display: flex; align-items: center; gap: 14px; }
#atlas-progress-col { display: block; text-align: right; font-size: 13px; color: var(--dim); }
/* Уровень — золотом, «открыто N / M» — белым: это две разные величины, и
   раньше они шли одной серой строкой. */
.atlas-prog-1 {
  font-family: var(--font-head); font-size: 15px; font-weight: 500;
  letter-spacing: 2.2px; text-transform: uppercase; color: var(--gold);
}
.atlas-prog-o { color: var(--text); }
#atlas-track {
  width: 240px; height: 4px; margin: 6px 0 0 auto;
  border-radius: 2px; background: rgba(126,168,190,.18); overflow: hidden;
}
#atlas-track > i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--gold), rgba(240,208,96,.35));
  box-shadow: 0 0 8px rgba(240,208,96,.45);
  transition: width var(--t-in);
}
#atlas-progress-note {
  margin-top: 5px; font-size: 11.5px; color: var(--dim);
  display: flex; justify-content: flex-end; gap: 12px;
}
/* Подпись «ЦВЕТ» перед фильтрами: без неё ряд читался как второй ряд разделов. */
.atlas-flab {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 2.4px;
  text-transform: uppercase; color: var(--dim); margin-right: 6px; align-self: center;
}
/* Пояснение про эфемеров — спокойный текст, а не панель с чертой: в макете это
   подпись под управлением, и рамка вокруг неё делала из подписи сообщение. */
#atlas-color-desc {
  margin: 13px 0 15px; padding: 0; border: 0; background: none;
  font-size: 12.5px; line-height: 1.6; color: var(--dim); max-width: 760px;
}
/* Карточка вида — по макету: имя капсами, цвет подписью, фигура в тёмном
   кадре, ступени золотом, кнопка в одну строку. */
.atlas-card-name {
  font-family: var(--font-head); font-size: 17px; font-weight: 500;
  letter-spacing: 2.2px; text-transform: uppercase;
}
.atlas-card-id { font-size: 11px; font-weight: 600; color: var(--dim); }
.atlas-card-color {
  margin-top: 3px; font-family: var(--font-head); font-size: 11px;
  letter-spacing: 1.6px; text-transform: uppercase;
}
.atlas-card-art {
  height: 104px; margin: 11px 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(126,168,190,.12); border-radius: var(--r-s);
  background: #050b13;
}
/* Ступени — ЗОЛОТО и тонкая полоса, как в макете: общая шкала одна на все
   цвета, и красить её цветом семьи незачем — цвет уже стоит в имени и в фигуре. */
.atlas-pip { height: 4px; border: 0; background: rgba(126,168,190,.18); }
.atlas-pip.filled { background: var(--gold); box-shadow: 0 0 7px rgba(240,208,96,.5); }
/* «Не дешифровано» — обычная строка рядом со счётчиком, а не жёлтая плашка:
   свечение от мигания читалось как кнопка. Мигание оставлено (#255), но только
   яркостью. */
#atlas-undeciphered {
  font-size: 11.5px; letter-spacing: 0; font-weight: 400; color: #d8bc63;
  animation: atlas-undec-blink 1.6s ease-in-out infinite;
}
@keyframes atlas-undec-blink { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }
/* Кнопка карточки — капсами и В ОДНУ СТРОКУ. «Расшифровать · 10 записей»
   строчными ломалось надвое: сквозное требование заказчика — ничто в одну
   строку не становится двумя. */
.btn-atlas-decipher, .atlas-deciphered-mark, .btn-atlas-prize {
  font-family: var(--font-head); font-size: 11.5px; font-weight: 500;
  letter-spacing: 1.6px; text-transform: uppercase; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* «РАСШИФРОВАН» — плашка в рамке, как кнопка, которой она была: строкой без
   рамки она читалась как подпись, а не как состояние карточки. */
.atlas-deciphered-mark {
  display: block; text-align: center; padding: 7px 10px;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: var(--panel-2); color: var(--dim);
}

#archive-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px; border-bottom: 0; margin-bottom: 14px;
}
/* Полоска набора эхонавтов под заголовком — как у Организаций и карточки
   эхонавта. У Атласа её в макете нет: там рядом с названием стоят разделы. */
#archive-title::after {
  content: ""; display: block; width: 168px; height: 3px; margin-top: 10px;
  background: linear-gradient(90deg,
    #63c246 0 16.6%, #d94b6a 16.6% 33.3%, #d99a3a 33.3% 50%,
    #cf3b32 50% 66.6%, #8a5bd6 66.6% 83.3%, #eb9a3a 83.3% 100%);
}
#archive-tabs { margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--border); }
.archive-tab .gi { height: 13px; margin-right: 5px; }

/* Карточка Атласа — панель стиля: полупрозрачная, волосяная рамка, радиус 3. */
.atlas-card { background: var(--panel-2); border-color: var(--border); }

/* ─── ПРИБАВЛЕНИЕ В АТЛАСЕ (заказчик, 30.08.2026) ────────────────────
   Возвращаясь из слоя, игрок попадает в Атлас, и новые записи обязаны сами
   себя показать: карточки проявляются ПО ОЧЕРЕДИ (шаг 160 мс по --fresh-i),
   к первой Атлас перематывает. Иначе двух открытых эфемеров среди
   восьмидесяти шести карточек не найти — они просто где-то есть.
   Порядковый номер приходит переменной, а не двадцатью инлайновыми стилями. */
.atlas-fresh {
  animation: atlas-fresh-in 620ms cubic-bezier(.2,.7,.3,1) backwards;
  animation-delay: calc(var(--fresh-i, 0) * 160ms + 220ms);
}
/* Подсветка держится дольше самого появления: она — метка «это новое», а не
   переход. Гаснет сама, чтобы Атлас не остался навсегда в огнях. */
.atlas-fresh::after {
  content: ""; position: absolute; inset: -1px; border-radius: 3px;
  pointer-events: none; border: 1px solid var(--teal);
  animation: atlas-fresh-glow 2.6s ease-out backwards;
  animation-delay: calc(var(--fresh-i, 0) * 160ms + 220ms);
}
.atlas-fresh-more::after { border-color: var(--gold); }
/* Плашка в углу: «НОВАЯ» у карточки, которой в Атласе не было, «+1» у той,
   что пополнилась. Разные вещи — разный знак и разный цвет. */
.atlas-fresh-tag {
  position: absolute; top: -1px; right: -1px; z-index: 2;
  font-family: var(--font-head); font-size: 9.5px; font-weight: 500;
  letter-spacing: 1.6px; text-transform: uppercase;
  padding: 3px 7px; color: #06121a; background: var(--teal);
  border-radius: 0 3px 0 3px;
  animation: atlas-fresh-in 620ms ease backwards;
  animation-delay: calc(var(--fresh-i, 0) * 160ms + 340ms);
}
.atlas-fresh-tag-more { background: var(--gold); }
@keyframes atlas-fresh-in {
  from { opacity: 0; transform: translateY(14px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes atlas-fresh-glow {
  0%   { opacity: 0;   box-shadow: 0 0 0 0 rgba(78,205,196,.55); }
  18%  { opacity: 1;   box-shadow: 0 0 22px 2px rgba(78,205,196,.55); }
  70%  { opacity: .85; box-shadow: 0 0 14px 0 rgba(78,205,196,.30); }
  100% { opacity: 0;   box-shadow: 0 0 0 0 rgba(78,205,196,0); }
}
@media (prefers-reduced-motion: reduce) {
  .atlas-fresh, .atlas-fresh::after, .atlas-fresh-tag { animation-duration: 1ms; }
}

@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  /* ─── ОРГАНИЗАЦИИ НА ТЕЛЕФОНЕ ───────────────────────────────────
     Товар — строка из четырёх колонок, и на 390 px её нельзя оставить как на
     десктопе: колонки «цена» и «кнопка» не сжимаются, и строка выпихивала
     страницу за край экрана (кнопки «КУПИТЬ» уезжали за правую кромку).
     Поэтому на телефоне товар в две строки: значок и название сверху, цена и
     кнопка снизу. Ничто по-прежнему не переносится внутри своей строки. */
  /* ТРИ колонки, а не две: цена стояла в первой (34 px под значок) и своей
     подписью — «×10 кр за штуку» — налезала на кнопку, а страница уезжала за
     правый край экрана (замер: документ 739 px при окне 390). Теперь нижняя
     строка отдана цене целиком, кнопка прижата к правому краю. */
  .shop-item {
    grid-template-columns: 34px minmax(0, 1fr) auto;
    grid-template-areas: "ico name name" "cost cost btn";
    gap: 8px 10px; padding: 8px 10px;
  }
  .shop-item .item-badge, .shop-item .shop-item-art { grid-area: ico; width: 34px; height: 34px; }
  .item-name { grid-area: name; font-size: 13px; }
  .equip-item .equip-lines { grid-area: name; min-width: 0; }
  .equip-item .equip-desc { font-size: 11.5px; }
  .item-cost { grid-area: cost; justify-self: start; align-self: center; }
  .shop-item .btn-shop { grid-area: btn; justify-self: end; }
  /* Строка с картинкой (щит, накопитель, эксклюзивы) идёт ТОЙ ЖЕ сеткой.
     ЗДЕСЬ ЕЁ ПЕРЕБИВАЛА раскладка старого стиля («art name / art hint / art
     cost / btn btn») — она ссылалась на область art, которой в «Галерее» нет,
     и картинка уезжала в неявную строку под товаром. */
  [data-equipment-art="on"] .shop-item:has(.shop-item-art) {
    grid-template-columns: 34px minmax(0, 1fr) auto;
    grid-template-areas: "ico name name" "cost cost btn";
    gap: 8px 10px;
  }
  [data-equipment-art="on"] .shop-item .shop-item-art { width: 34px; height: 34px; }
  .item-win-hint { grid-area: name; align-self: end; }
  /* Кадр ниже, название и вкладки не налезают друг на друга: на 390 px они
     стояли на одной высоте с разных сторон и сходились посередине. */
  .org-shot { height: 104px; }
  .org-panel > .org-title,
  [data-equipment-art="on"] .org-panel > .org-title { left: 12px; top: 40px; font-size: 15px; letter-spacing: 2px; }
  .org-panel > .org-tabs,
  [data-equipment-art="on"] .org-panel > .org-tabs { right: 10px; top: 70px; }
  .org-panel > .shop-items { padding: 10px; }
  .shop-org-tab { padding: 4px 9px 4px 4px; font-size: 11px; letter-spacing: 1px; }
  .shop-org-tab img { width: 30px; height: 22px; }
  #shop-header { flex-direction: column; align-items: flex-start; gap: 8px; margin-bottom: 10px; }
  #shop-title { font-size: 17px; letter-spacing: 3px; }
  #shop-head-left::after { width: 140px; margin-top: 8px; }
  .sres-row-1 { flex-wrap: wrap; gap: 10px 14px; }
  #shop-res { padding: 7px 10px; margin-bottom: 10px; }
  .sres-row-2 { flex-wrap: wrap; gap: 6px 14px; }

  /* Шапка станции на телефоне. Считанная ширина ряда: четыре раздела значками
     (176 px), «Погружение», динамик и «Меню» — с названием слоя в кнопке
     «Погружение» это 450 px при доступных 374, и «Меню» уезжало за край.
     Название слоя убираем: оно и так стоит в самой витрине, а «Меню» — нет. */
  .station-bar { flex-wrap: nowrap; overflow: hidden; }
  .n-dive-w { display: none; }
  .n-dive { padding: 7px 10px; }
  .n-grow { min-width: 0; }
}

/* ─── АТЛАС · СЛОИ (docs/design/AtlasLayers.html) ─────────────────
   Карточка с кадром слоя вместо строки таблицы. Слои, где игрок не был,
   стоят пустыми рамками с номером: сколько их всего — это и был открытый
   вопрос заказчика к макету. */
/* ─── АТЛАС · МЕМБРАНЫ (#304) ─────────────────────── */
/* Та же анатомия, что у карточек слоёв рядом: своя прокрутка внутри окна,
   align-content/grid-auto-rows против схлопывания первой строки (грабля
   #atlas-layers выше — она здесь ровно та же). */
#atlas-mem-desc {
  margin: 13px 0 14px; font-size: 12.5px; line-height: 1.6; color: var(--dim); max-width: 760px;
}
/* flex: 1 1 auto + min-height: 0 — прокручивается САМ раздел, а не окно Атласа:
   без этого список уезжал под кнопку подвала «В МЕНЮ». margin-bottom — тот же
   отступ до подвала, что у #atlas-grid. */
#atlas-membranes { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding-right: 4px; margin-bottom: 16px; }
.atlas-mem-count { font-size: 12px; letter-spacing: 1px; color: var(--dim); margin-bottom: 12px; }
.atlas-mem-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
  align-content: start; grid-auto-rows: min-content;
}
/* Карточки тянутся на всю высоту СВОЕГО РЯДА (align-self: stretch по умолчанию,
   поэтому строки здесь нет): найденная выше закрытой, и при align-self: start
   сетка шла дырами — пустое место посреди ряда читалось как «здесь что-то не
   нарисовалось». */
.atlas-mem-card {
  border: 1px solid var(--border); border-left: 3px solid var(--teal);
  border-radius: var(--r); background: var(--panel-2);
  padding: 10px 12px;
}
/* Ненайденная — пунктир и приглушение: «такая мембрана есть, но вы её не
   встречали». Ни имени, ни эффекта у неё на карточке нет намеренно. */
.atlas-mem-locked {
  border-left-color: rgba(126,168,190,.20);
  border-style: dashed; opacity: .45;
  display: flex; align-items: center;   /* подпись по центру растянутой рамки */
}
.atlas-mem-hd { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.atlas-mem-locked .atlas-mem-hd { margin: 0; }
.atlas-mem-ic { flex: 0 0 auto; display: inline-flex; align-items: center; }
.atlas-mem-ic .mem-ic { width: 20px; height: 20px; }
.atlas-mem-name {
  font-family: var(--font-head); font-size: 13px; letter-spacing: 1.2px;
  text-transform: uppercase; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.atlas-mem-id { margin-left: auto; font-size: 10.5px; letter-spacing: 1px; color: var(--dim-2); flex: 0 0 auto; }
.atlas-mem-effect { font-size: 12px; line-height: 1.5; color: var(--text); margin-bottom: 8px; }
/* #311: лакуна вместо эффекта — приглушена и курсивом, чтобы её не читали как
   само описание. */
.atlas-mem-unknown, .eph-membrane-unknown { color: var(--dim-2); font-style: italic; }
/* Строка про текущее погружение — золотом: она одна здесь меняется от захода
   к заходу, и её обязано быть видно среди накопленного. */
.atlas-mem-run {
  font-size: 11.5px; line-height: 1.4; color: var(--gold);
  padding: 5px 7px; margin-bottom: 8px;
  border-radius: 3px;
  background: rgba(240,208,96,.06); border: 1px solid rgba(240,208,96,.18);
}
.atlas-mem-stats { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 11px; }
.atlas-mem-stat { display: inline-flex; align-items: baseline; gap: 5px; color: var(--dim); }
.atlas-mem-stat b { font-size: 13px; color: var(--text); }
.atlas-mem-stat.ams-ok b   { color: var(--green, #2ecc71); }
.atlas-mem-stat.ams-lost b { color: var(--red, #e74c3c); }
.atlas-mem-empty { font-size: 12.5px; line-height: 1.6; color: var(--dim); max-width: 620px; }
@media (max-width: 999px) { .atlas-mem-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px) { .atlas-mem-grid { grid-template-columns: minmax(0, 1fr); } }

#atlas-layers-desc {
  margin: 13px 0 14px; font-size: 12.5px; line-height: 1.6; color: var(--dim); max-width: 760px;
}
#atlas-layers-legend { display: flex; flex-wrap: wrap; gap: 22px; margin: 0 0 16px; font-size: 12px; color: var(--dim); }
.al-lg { display: flex; align-items: center; gap: 8px; }
.al-sw { width: 13px; height: 13px; border-radius: 2px; border: 1px solid; flex: 0 0 auto; }
.al-sw-done { border-color: rgba(240,208,96,.60); background: rgba(240,208,96,.22); }
.al-sw-open { border-color: rgba(126,168,190,.35); background: rgba(126,168,190,.08); }
.al-sw-void { border-color: rgba(126,168,190,.16); border-style: dashed; }

/* align-content: start и grid-auto-rows: min-content обязательны: у #atlas-layers
   есть своя высота и overflow-y (он прокручивается внутри окна Атласа), и без
   них первая строка сетки схлопывалась в 2 px — карточка была, но её ряду
   доставалась нулевая высота, а overflow: hidden срезал содержимое. Пустые
   карточки при этом стояли правильно: их держал min-height. */
#atlas-layers {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px;
  align-content: start; grid-auto-rows: min-content;
}
.al-card {
  align-self: start;
  overflow: hidden; border: 1px solid var(--border); border-radius: var(--r);
  background: var(--panel-2);
}
.al-done { border-color: rgba(240,208,96,.50); background: rgba(240,208,96,.045); box-shadow: 0 0 0 1px rgba(240,208,96,.14); }
/* #326: карточка МАССИВА в разделе «Слои». Фиолетовая кромка — тот же цвет,
   каким Массив помечен везде: заголовок его комнаты, спина панели, карточка в
   трекере. Игрок должен узнавать Массив в списке слоёв, не читая имени.
   Ставится ПОСЛЕ .al-done: пройденный Массив остаётся Массивом, а не золотым
   слоем. */
.al-card.al-boss { border-color: rgba(155,89,182,.55); background: rgba(155,89,182,.05); }
.al-card.al-boss.al-done { box-shadow: 0 0 0 1px rgba(155,89,182,.2); }
.al-card.al-boss .al-nm { color: #c8a0e0; }
.al-void { min-height: 262px; border-style: dashed; border-color: rgba(126,168,190,.13); background: rgba(126,168,190,.012); }
.al-shot { position: relative; height: 152px; overflow: hidden; background: #050b13; }
.al-void .al-shot { height: 100%; min-height: 262px; }
.al-shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 44%; filter: saturate(.5) brightness(.72); }
.al-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(4,7,13,.20) 0%, rgba(4,7,13,.45) 50%, rgba(4,7,13,.92) 100%); }
.al-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 0 14px 11px; display: flex; align-items: baseline; gap: 9px; }
.al-no {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
  color: #04070d; background: var(--gold); border-radius: 2px; padding: 1px 7px; white-space: nowrap;
}
.al-open .al-no { background: rgba(126,168,190,.30); color: var(--head); }
.al-nm {
  font-family: var(--font-head); font-size: 19px; font-weight: 500;
  letter-spacing: 2.6px; text-transform: uppercase; color: var(--head);
}
/* Слой, где игрок ещё не был: штриховка и номер. Кадра нет — его и не должно
   быть, иначе неоткрытый слой выглядел бы пройденным. */
.al-empty {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 9px; color: #55707f;
  background: repeating-linear-gradient(135deg, rgba(126,168,190,.05) 0 8px, transparent 8px 16px);
}
.al-empty .gi { height: 22px; }
.al-empty-t { font-family: var(--font-head); font-size: 11px; letter-spacing: 2.4px; text-transform: uppercase; }
.al-empty-n { font-family: var(--font-head); font-size: 13px; letter-spacing: 2px; text-transform: uppercase; color: var(--dim); }
/* Кадра у слоя может не быть (сейчас они есть у первых двух): говорим об этом
   вслух, а не подставляем чужой снимок. */
.al-noshot {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 7px; color: #4a6272;
  font-family: var(--font-head); font-size: 10.5px; letter-spacing: 2.2px; text-transform: uppercase;
}
.al-noshot .gi { height: 20px; }
.al-body { padding: 12px 14px 14px; }
.al-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; color: var(--dim); padding: 3px 0; }
.al-v { font-weight: 600; color: var(--text); white-space: nowrap; }
.al-gold { color: var(--gold); }
.al-orden { color: #7fb2ff; }
.al-dim { color: var(--dim); font-weight: 400; }
.al-mark {
  display: flex; align-items: center; gap: 7px; padding: 7px 0 0; margin-top: 8px;
  border-top: 1px solid var(--border);
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase;
}
.al-mark .gi { height: 13px; }
.al-mark-done { color: var(--gold); }
.al-mark-open { color: var(--dim); }
/* Подарок Ордена — в углу кадра, а не отдельной колонкой. */
.al-gift {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 38px; height: 38px; padding: 3px;
  background: rgba(4,7,13,.55); border: 1px solid var(--border-2); border-radius: var(--r-s);
  cursor: pointer;
}
.al-gift img { width: 100%; height: 100%; object-fit: contain; display: block; }

@media (max-width: 999px) { #atlas-layers { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  #atlas-layers { grid-template-columns: 1fr; }
  .al-void { min-height: 170px; }
  .al-void .al-shot { min-height: 170px; }
}

/* ─── АРХИВ: список и колонка «что здесь лежит» ───────────────────── */
#archive-cols {
  display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 18px;
  align-items: start; padding: 0 16px 16px; overflow-y: auto; min-height: 0;
}
#archive-cols #archive-list { padding: 0; overflow: visible; }
#archive-side { position: sticky; top: 0; }
#archive-side .pcard-sec { padding: 15px 16px 17px; }
.arc-srow {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 0; font-size: 12.5px; color: var(--dim);
  border-bottom: 1px solid var(--border);
}
.arc-srow:last-of-type { border-bottom: 0; }
.arc-sv { font-size: 13px; font-weight: 600; color: var(--text); }
.arc-note { margin-top: 12px; font-size: 11.5px; line-height: 1.6; color: var(--dim); }
/* Одна строка вместо трёх десятков лакун «[ЗАСЕКРЕЧЕНО]». */
.arc-locked-rest {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin-top: 4px; padding: 12px;
  border: 1px dashed var(--border); border-radius: var(--r);
  font-family: var(--font-head); font-size: 11px; letter-spacing: 1.8px;
  text-transform: uppercase; color: var(--dim);
}
.arc-locked-rest .gi { height: 13px; }
/* Подпись перед переключателем порядка. */
.arc-sort-lab {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 2.4px;
  text-transform: uppercase; color: var(--dim); margin-right: 4px;
}
@media (max-width: 999px) {
  #archive-cols { grid-template-columns: 1fr; }
  #archive-side { position: static; }
}

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ИТОГ ПОГРУЖЕНИЯ  (docs/design/End.html)
   Наверху — кадр слоя, на нём золотая плашка с номером слоя, его название и
   вердикт. Слой называется ПЕРВЫМ: до этого понять, откуда игрок вышел, можно
   было только по вердикту («Слой 3 очищен»), а у срыва и у выхода его в
   заголовке нет вовсе.
═══════════════════════════════════════════════════════════════════ */
#overlay-box { padding: 0; text-align: left; max-width: 720px; overflow: hidden; border-color: var(--border-2); box-shadow: 0 24px 70px rgba(0,0,0,.6); }
#overlay-head { position: relative; padding: 0; overflow: hidden; }
#overlay-shot {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 42%;
  /* Кадр приглушён: поверх него идут вердикт и имя, и на полном цвете они
     теряются. Саму картинку это не портит — она здесь настроение, а не сюжет. */
  filter: saturate(.34) brightness(.58);
}
#overlay-head::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,7,13,.45) 0%, rgba(4,7,13,.62) 45%, rgba(10,20,31,.96) 100%);
}
#overlay-head-body { position: relative; z-index: 1; padding: 130px 30px 22px; }
#overlay-layer { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
#overlay-layer-no {
  font-family: var(--font-head); font-size: 11px; font-weight: 600;
  letter-spacing: 2px; text-transform: uppercase; color: #1a1400;
  background: var(--gold); border-radius: var(--r-s); padding: 2px 8px;
}
#overlay-layer-name {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 3px; text-transform: uppercase; color: var(--gold);
}
#overlay-title {
  font-family: var(--font-head); font-size: 34px; font-weight: 500;
  letter-spacing: 4px; text-transform: uppercase; margin-bottom: 12px; line-height: 1;
}
/* Вердикт красится тоном исхода: срыв красным, выход бирюзой, победа золотом. */
#overlay-box[data-phase="lost"] #overlay-title      { color: #ef7264; }
#overlay-box[data-phase="escaped"] #overlay-title   { color: var(--teal-2); }
#overlay-box[data-phase="won"] #overlay-title,
#overlay-box[data-phase="boss-won"] #overlay-title  { color: var(--gold); }
#overlay-who { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
#overlay-who .rb-face { width: 24px; height: 24px; }
#overlay-nick {
  font-family: var(--font-head); font-size: 13px; font-weight: 500;
  letter-spacing: 1.8px; text-transform: uppercase;
}
#overlay-sub { color: var(--dim); font-size: 13px; margin: 0; padding-left: 12px; border-left: 1px solid var(--border-2); }
#overlay-head-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; z-index: 2; }
#overlay-stats { margin: 0; padding: 20px 30px 4px; font-size: 14px; color: var(--text); }
.report-section {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2.4px; text-transform: uppercase; color: var(--dim-2);
  border-top: 1px solid var(--border); margin-top: 10px; padding: 10px 0 4px;
}
.report-key { color: var(--dim); }
.report-val { font-weight: 600; }
/* Кнопки итога — РЯДОМ, а не столбиком. Тон кнопки продолжения задаёт игра
   (бирюза — «дальше», фиолетовый — «в петлю»), и раньше он ставился инлайновым
   фоном: инлайн перебивает любой CSS, и кнопка оставалась залитой прямоугольной
   плашкой мимо стиля. Теперь игра ставит КЛАСС тона, а вид — здесь. */
#overlay-box { display: flex; flex-direction: column; }
/* Кнопки итога — В РЯД И ОДНОЙ ШИРИНЫ, во всю панель (макет End.html).
   Прижатые влево и разной ширины, они читались как «главная и две мелких»,
   хотя выбор здесь равноправный: вернуться, нырять снова или выйти.
   Скрытые кнопки из ряда выпадают сами — display: none. */
#overlay-actions {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: 10px; padding: 16px 30px 22px;
}
#btn-overlay-action, #btn-overlay-warp, #btn-overlay-exit {
  font-family: var(--font-head); font-size: 13px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; margin: 0;
  padding: 11px 22px; border-radius: var(--r); cursor: pointer;
  border: 1px solid var(--border-2); background: var(--panel-2); color: var(--dim);
  transition: background var(--t-tap), border-color var(--t-tap), color var(--t-tap);
}
#btn-overlay-action { border: 1px solid rgba(240,208,96,.5); background: rgba(240,208,96,.08); color: var(--gold); }
#btn-overlay-action.ov-teal   { border-color: rgba(78,205,196,.55); background: rgba(78,205,196,.10); color: var(--teal-2); }
#btn-overlay-action.ov-purple { border-color: rgba(155,89,182,.6);  background: rgba(155,89,182,.12); color: #c8a0e0; }
/* На экране срыва главное действие — «Новое погружение», и оно золотое:
   бирюза здесь означала «вернуться», и три бирюзовые кнопки подряд не
   показывали, какая из них главная. */
#btn-overlay-action.ov-gold { border-color: rgba(240,208,96,.55); background: rgba(240,208,96,.10); color: var(--gold); }
#btn-overlay-action:hover { opacity: 1; filter: brightness(1.25); }
#btn-overlay-warp {
  /* Ширина во всю строку осталась от столбика кнопок: в ряду она выталкивала
     соседей на следующую строку. */
  display: flex; align-items: center; justify-content: center; width: auto; margin: 0;
  border-color: rgba(155,89,182,.5); color: #c8a0e0; background: rgba(155,89,182,.08);
}
#btn-overlay-exit:hover, #btn-overlay-warp:hover { filter: brightness(1.25); }
/* Кадра у этого слоя нет — полосу не растим впустую. */
#overlay-head:has(#overlay-shot.hidden) #overlay-head-body { padding-top: 24px; }

@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  #overlay-head-body { padding: 84px 16px 16px; }
  #overlay-title { font-size: 22px; letter-spacing: 2px; }
  #overlay-stats { padding: 14px 16px 4px; }
  #overlay-actions { padding: 12px 16px 18px; gap: 8px; grid-auto-flow: row; grid-auto-columns: auto; }
  #btn-overlay-action, #btn-overlay-warp, #btn-overlay-exit { padding: 10px 16px; font-size: 12px; letter-spacing: 1px; }
}

/* Рейтинг — панель с чертой слева и КРУПНЫМ числом справа, как в макете.
   Обычной строкой отчёта он терялся среди двух десятков таких же. */
/* Нижней рамки у панели НЕТ: под ней всегда идёт строка разбора («55 кр + 23
   записи …») в такой же рамке без верхней, и две кромки рисовали черту поперёк
   панели — заказчик про неё и написал (29.08.2026). */
.report-row.report-score {
  align-items: center; margin-top: 6px; padding: 12px 14px;
  border: 1px solid var(--border); border-bottom: 0; border-left: 3px solid var(--red);
  border-radius: var(--r) var(--r) 0 0; background: var(--panel-2);
}
.report-row.report-score .report-key { font-family: var(--font-head); font-size: 12px;
  font-weight: 500; letter-spacing: 2px; text-transform: uppercase; color: var(--dim); }
.ov-score { font-size: 34px; font-weight: 600; line-height: 1; color: var(--gold); }
.ov-score.orden-num { color: #7fb2ff; }
.report-row.report-score-why { margin-top: -6px; padding: 0 14px 10px;
  border: 1px solid var(--border); border-top: 0; border-left: 3px solid var(--red);
  border-radius: 0 0 var(--r) var(--r); background: var(--panel-2); }
/* Значок в строке отчёта — ростом со строку и на своём месте слева. */
.report-key .txt-ic { margin-right: 7px; }

/* Счётчик вскрытых секторов на линии заголовка слоя. Приглушён: рейтинг
   слева — цель, а это фон, по которому видно, сколько поля уже прочитано. */
/* #320: счётчик вскрытых секторов. Знак поля перед числом отличает его от двух
   рейтингов на той же линии — один из них тоже «из сотни», и без знака третья
   дробь читалась третьим рейтингом. Значок в em: он стоит среди цифр. */
.lt-cells { margin-left: 16px; color: var(--dim); display: inline-flex; align-items: center; gap: 4px; }
/* Размер знаку задаёт .gi (высота 1em, ширина auto) — здесь только приглушение:
   счётчик секторов не должен спорить яркостью с рейтингами рядом. */
.lt-cells-ic { opacity: .75; }
.lt-cells-n { color: var(--dim); }
.lt-cells-all { color: var(--dim-2); }

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: КОМНАТА МАССИВА  (docs/design/Boss.html)
   Тот же слой, но фиолетовый: спина заголовка, враждебные секторы, подсветка
   поля. Красным в игре помечается урон, и красное поле спорило с красными
   записями журнала — тревога переставала читаться. Глаза остаются золотыми.
═══════════════════════════════════════════════════════════════════ */
#layer-title.lt-boss, #layer-title-mobile.lt-boss { border-left-color: var(--purple); border-color: var(--purple); }
#layer-title.lt-boss .lt-name, #layer-title-mobile.lt-boss .lt-name { color: #c8a0e0; }
/* #322: ЗАРАЖЁННЫЙ СЕКТОР — КРАСНЫЙ, а не фиолетовый. Фиолетовым тут была
   мысль «цвет самого Массива, а не „здесь больно“» — и она не сработала:
   заражение легло тем же цветом, что и тело Массива с его сегментами, и на
   поле два разных смысла слились в одно пятно (заказчик 02.09.2026: «этот
   фиолет сливается с цветом эфемера»). Красный в игре и значит «здесь больно»,
   а заражённый сектор — ровно про это.
   Сектор сплошной тёмный, а не полупрозрачная плёнка: на почти чёрном поле
   .06 не отличалось от закрытого сектора. Череп берёт цвет отсюда:
   ICONS.skull нарисован currentColor.

   04.09.2026: ВСЕ ДЕВЯТЬ СЕКТОРОВ КВАДРАТА ОДИНАКОВЫ (заказчик). Центр стоял
   ярче — заливка .22, рамка .60, своё свечение с пульсом, — и по нему читалось,
   откуда растёт очаг. Теперь у него вид зоны помех, и правило одно на оба
   класса: два набора правил про одно разошлись бы при первой правке. */
.cell-hostile,
.cell-hostile-neighbor {
  background: #2a1210 !important;
  border-color: #4d211c !important;
  color: rgba(231,76,60,.62) !important;
  box-shadow: none;
}
/* ─── «ТУМАН»: ЗАРАЖЕНИЕ ГАСНЕТ НА ГЛАЗАХ (задание №23) ───────────
   Заказчик: «только произошло заражение — черепа яркие и большие, потом они
   поблеклее и поменьше... мы видим, что здесь заражение скоро пройдёт».
   Ступень ставит fogSkullStage, и ставит её ВСЕМ ДЕВЯТИ секторам квадрата: по
   разной яркости центра и зоны читалось бы, где очаг (#348).

   Меняем и размер черепа, и его прозрачность, и заливку сектора: одной
   прозрачности мало — на тёмном поле разница между .62 и .40 не видна, пока
   секторы не стоят рядом. Порядок правил важен: .cell-hostile выше уже ставит
   заливку с !important, поэтому ступени тоже с ним. */
.cell-hostile.fog-age-1, .cell-hostile-neighbor.fog-age-1 {
  background: #38140f !important;
  border-color: #6a2a22 !important;
  color: rgba(231, 76, 60, .92) !important;
}
.cell-hostile.fog-age-1 .gi, .cell-hostile-neighbor.fog-age-1 .gi {
  height: 66%; opacity: .92;
}
.cell-hostile.fog-age-2, .cell-hostile-neighbor.fog-age-2 {
  background: #26110e !important;
  border-color: #4a201b !important;
  color: rgba(231, 76, 60, .55) !important;
}
.cell-hostile.fog-age-2 .gi, .cell-hostile-neighbor.fog-age-2 .gi {
  height: 52%; opacity: .55;
}
/* Последний такт: заражение почти сошло — сектор еле отличается от закрытого,
   и это ровно та подсказка, которую просили. Совсем убирать знак нельзя: Зонд
   здесь ещё не работает, и пустой сектор соврал бы. */
.cell-hostile.fog-age-3, .cell-hostile-neighbor.fog-age-3 {
  background: #180c0b !important;
  border-color: #331715 !important;
  color: rgba(231, 76, 60, .3) !important;
}
.cell-hostile.fog-age-3 .gi, .cell-hostile-neighbor.fog-age-3 .gi {
  height: 40%; opacity: .3;
}
/* ОБЕЩАННАЯ ЗОНА — ТОЛЬКО РАМКА, без заливки и без знака: сектор ещё чист, и
   красить его как заражённый значило бы отнять у игрока те два такта, ради
   которых рамка и заведена. Пунктир отличает «будет» от «есть»: сплошную рамку
   в игре уже носят подсветки приборов. */
.cell-fog-plan {
  border-color: rgba(231, 76, 60, .55) !important;
  border-style: dashed !important;
  animation: fog-plan-warn 1.6s ease-in-out infinite;
}
@keyframes fog-plan-warn {
  0%, 100% { border-color: rgba(231, 76, 60, .34); }
  50%      { border-color: rgba(231, 76, 60, .72); }
}
@keyframes neighbor-warn { 0%,100%{border-color:#4d211c} 50%{border-color:rgba(231,76,60,.45)} }
/* Имя Массива — крупно и фиолетовым: это не строка списка, а название комнаты. */
.eph-card.boss-eph .eph-name {
  font-family: var(--font-head); font-size: 22px; font-weight: 500;
  letter-spacing: 2.4px; color: #c8a0e0;
}
.boss-sub { margin-top: 3px; font-size: 11.5px; color: var(--dim); }
/* Ряд Глаз: сами Глаза в линию (#374). Главная величина комнаты — она и должна
   быть видна первой, а не строкой мелкого моно среди прочего. */
.boss-eyes {
  display: flex; align-items: center; gap: 10px;
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);
}
/* Кадр Массива ниже: правая колонка ровно по высоте центральной, и всё, что
   не влезло, обрезается. С кадром 16:9 полоса Глаз и подсказка «Сканируй
   Эхолучом» уезжали за нижнюю кромку панели — то есть их не было. */
.boss-eph .boss-portrait { aspect-ratio: 21 / 9; }
.eph-card.boss-eph { gap: 6px; padding: 9px; }
.boss-eyes-lab {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 2.2px;
  text-transform: uppercase; color: var(--dim);
}
/* #374: САМИ ГЛАЗА В ЛИНИЮ вместо ламп, шкалы и дроби. Значок тот же, что на
   секторе поля, — размер в em, а не в пикселях: рядом стоит подпись «ГЛАЗА», и
   в пикселях они разъехались бы при другом кегле (та же грабля, что была с
   эмодзи ресурсов). */
.boss-eyes-row { display: flex; align-items: center; gap: 8px; }
.boss-eye {
  position: relative; display: inline-flex; width: 1.7em; height: 1.7em;
  color: var(--gold); filter: drop-shadow(0 0 5px rgba(240,208,96,.5));
}
.boss-eye > svg { width: 100%; height: 100%; display: block; }
/* ПОГАШЕННЫЙ ГЛАЗ: приглушён и перечёркнут крестом. Крест рисуем фоном самого
   гнезда, а не символом поверх: символ садился бы на базовую линию и съезжал
   с глазом, а два градиента держатся его рамки при любом размере. */
.boss-eye-out {
  color: var(--dim); filter: none; opacity: .85;
}
.boss-eye-out::after {
  content: ''; position: absolute; inset: -1px; pointer-events: none;
  background:
    linear-gradient(to bottom right, transparent calc(50% - 1px), #e74c3c calc(50% - 1px), #e74c3c calc(50% + 1px), transparent calc(50% + 1px)),
    linear-gradient(to bottom left,  transparent calc(50% - 1px), #e74c3c calc(50% - 1px), #e74c3c calc(50% + 1px), transparent calc(50% + 1px));
}

/* ─── КАРТОЧКА «БЕГАЮЩИХ ГЛАЗ» (задание №20) ───────────────────────
   Точки тела, замок, активный Глаз и его ближайшее действие. */

/* ТОЧКИ ТЕЛА. Ряд ПЕРЕНОСИТСЯ (flex-wrap), а не жмётся: сегментов бывает
   тридцать, а точка мельче трёх пикселей перестаёт читаться — считать по ней
   уже нечего. Замок держится в конце ряда своим flex-порядком, а не отступом:
   при переносе он должен уехать вместе с последней точкой, а не остаться
   висеть в первой строке. */
.boss-segdots {
  display: flex; align-items: center; gap: 8px;
  margin-top: 6px;
}
/* Ряд НЕ растягивается на всю ширину: замок должен стоять вплотную к последней
   точке («рядом с этими точками, с крайней правой»), а не уезжать к краю
   карточки. Поэтому shrink-only, а свободное место остаётся справа от замка. */
.bsd-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; flex: 0 1 auto; }
/* #405: ряды квадратов друг под другом. Столбец, а не перенос по ширине: при
   переносе 36 квадратов делились как придётся — 22 и 14, — и ряд читался как
   ошибка вёрстки. Теперь ряды ровные, пополам. */
.bsd-rows { display: inline-flex; flex-direction: column; gap: 3px; flex: 0 1 auto; }
/* КВАДРАТ, А НЕ КРУЖОК, и ФИОЛЕТОВЫЙ (поправка 09.09.2026): «у них же всё-таки
   сегменты квадратные... квадрат фиолетовый, так как у нас фиолетовый же у него
   сегменты тела». Ряд читается как то же тело, только сбоку. */
.bsd-dot {
  width: 8px; height: 8px; border-radius: 1px;
  background: var(--purple);
  box-shadow: 0 0 5px rgba(155,89,182,.5);
  transition: background var(--t-tap) ease, box-shadow var(--t-tap) ease;
}
/* Погасший квадрат = разобранный сегмент. Не убираем его из ряда: длина ряда —
   это размер тела, и укорачиваясь он врал бы о том, сколько было. */
.bsd-dot.off {
  background: rgba(126,168,190,.16);
  box-shadow: none;
}
/* Остаток числом — впереди ряда, потому что читают его первым: «вначале
   поставить, сколько осталось». Всего — мельче и приглушённо: это справка,
   а меняется по ходу боя только левое число. */
.bsd-count {
  flex: 0 0 auto;
  font-family: var(--font-mono); font-size: 13px; font-weight: bold;
  color: var(--purple); font-variant-numeric: tabular-nums;
}
.bsd-count-total { font-size: 11px; font-weight: normal; color: var(--dim); }
.bsd-lock {
  display: inline-flex; align-items: center; flex: 0 0 auto;
  width: 1.15em; height: 1.15em; color: #e74c3c;
}
.bsd-lock.open { color: var(--green); }
.bsd-lock .gi { width: 100%; height: 100%; }
.bsd-lock .gi > svg { width: auto; height: 100%; display: block; }

/* АКТИВНЫЙ ГЛАЗ — тот, чья очередь тянуть в следующий заход. Обводка, а не
   другой цвет: цветом уже сказано «погашен», и третий оттенок на том же значке
   читался бы как третье состояние органа, а не как «сейчас его ход». */
.boss-eye-act {
  border-radius: 3px;
  outline: 1px solid var(--teal);
  outline-offset: 2px;
  filter: drop-shadow(0 0 7px rgba(100,220,220,.65));
}

/* ЧТО ДАДУТ И ЧТО СДЕЛАЮТ — справа от ряда Глаз. Прижато вправо, чтобы ряд
   значков не разъезжался при смене подписи с «тянет» на «движение». */
.boss-eyes-act {
  margin-left: auto; display: inline-flex; align-items: center; gap: 12px;
  font-family: var(--font-mono); font-size: 12px;
  white-space: nowrap;
}
/* Пара «подпись — значение». Подпись мелкая и приглушённая, значение крупнее:
   заказчик про прежний размер значка — «она какая-то совсем мелкая». */
.bea-pair { display: inline-flex; align-items: center; gap: 4px; }
.bea-lab {
  font-family: var(--font-head); font-size: 10px; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--dim);
}
.bea-res { display: inline-flex; align-items: center; gap: 2px; font-weight: bold; font-size: 13px; }
.bea-res .gi { width: 1.35em; height: 1.35em; }
.bea-res .gi > svg { width: auto; height: 100%; display: block; }
.bea-give  { color: var(--green); }
.bea-steal { color: #e74c3c; }
.bea-empty { color: var(--dim); font-weight: normal; }
.bea-act {
  letter-spacing: 1px; text-transform: uppercase;
  font-size: 11px; color: var(--dim);
}
/* Перемещение — событие, а не состояние: оно случится в этот заход и должно
   поймать взгляд. Мигание тем же приёмом, что у тревоги Сканера. */
.bea-move .bea-lab, .bea-move .bea-res { color: var(--gold); }
.bea-move { animation: boss-scan-move 1.1s steps(1) infinite; }

/* ЗНАК ВОПРОСА У РЯДА ГЛАЗ (заказчик, 09.09.2026). Кружок мельче значка Глаза:
   это справка, а не орган, и путать их нельзя. Размер в em — рядом стоит
   подпись «ГЛАЗА», и в пикселях они разъехались бы при другом кегле. */
/* СПРАВА ОТ ЗНАЧКОВ, БЛЕКЛЫЙ, БЕЗ ЗАЛИВКИ (заказчик, 09.09.2026). Прошли две
   крайности: 13×13 серым его не находили вовсе, бирюзовый с заливкой спорил с
   самими Глазами за внимание. Справка не должна выглядеть частью боя — она
   проступает при наведении. */
.boss-eyes-help {
  flex: 0 0 auto;
  width: 17px; height: 17px; margin-left: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--dim);
  border: 1px solid var(--border-2); border-radius: 50%;
  font-family: var(--font-mono); font-size: 12px; line-height: 1;
  cursor: pointer; padding: 0;
  transition: color var(--t-tap) ease, border-color var(--t-tap) ease;
}
.boss-eyes-help:hover { color: var(--teal); border-color: rgba(78,205,196,.7); }

/* САМОРАЗРУШЕНИЕ (поправка 09.09.2026). Пока Массив ест своё — та же строка,
   только золото сменилось тревожным янтарём; дошёл до контура — красное и
   мигает. Мигание тем же приёмом, что у тревоги Сканера: строка появляется на
   один такт и должна поймать взгляд, ничего не сдвинув. */
.boss-decay .boss-store-lab { color: var(--gold); }
.boss-decay .boss-store-num { color: var(--gold); }
.boss-decay-loud .boss-store-lab,
.boss-decay-loud .boss-store-num {
  color: #e74c3c;
  animation: boss-scan-alarm 1.4s steps(1) infinite;
}
/* «Его трясёт» — прямое слово заказчика. Смещение крошечное и без поворота:
   карточка стоит в потоке панели, и поворот сдвинул бы соседей. */
@keyframes boss-eph-shake {
  0%, 100% { transform: translate(0, 0); }
  20%      { transform: translate(-1px, 1px); }
  40%      { transform: translate(1px, -1px); }
  60%      { transform: translate(-1px, -1px); }
  80%      { transform: translate(1px, 1px); }
}
.boss-eph-shake { animation: boss-eph-shake 0.42s steps(1) infinite; }
/* Тряска отключается вместе с прочей анимацией — правило доступности уже есть
   в проекте, и новая анимация обязана его слушаться. */
@media (prefers-reduced-motion: reduce) {
  .boss-eph-shake { animation: none; }
}

/* СКЛАД ЧИСЛОМ (задание №20): у «Бегающих глаз» порога нет, заполнять нечего. */
.boss-store-num {
  display: inline-flex; align-items: center; gap: 3px;
  font-family: var(--font-mono); font-size: 13px; color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.boss-store-num .gi { width: 1.05em; height: 1.05em; }
.boss-store-num .gi > svg { width: auto; height: 100%; display: block; }

/* ПОКАЗАНИЯ ПОГЛОЩЕНИЯ — УГОЛ КАРТОЧКИ (#369). Слово, а за ним дробь
   «срок / молнии»: сколько тактов и сколько заберут. Стоит абсолютом поверх
   кадра, у правого верхнего угла, — там пусто, и число не отодвигает ни имя,
   ни полосу Глаз.
   Подложка полупрозрачная: под ней кадр Массива, и без неё цифра тонет.
   ОТСТУП СЧИТАЕТСЯ ОТ КАРТОЧКИ, А КРАЙ — У КАДРА. У карточки padding 9px, и
   значок с отступом 6px вставал ВЫШЕ и ПРАВЕЕ кадра, наполовину на рамке.
   Поэтому 9 + 7: значок целиком внутри рисунка и кромки не касается. */
.boss-eph { position: relative; }
/* СЕЛЕКТОР ИЗ ДВУХ КЛАССОВ, И ЭТО НЕ ПЕРЕСТРАХОВКА. У значка есть `has-tip`, а
   правило `.has-tip { position: relative }` стоит ниже по файлу и перебивало
   абсолют: значок молча вставал в поток и уезжал к левому краю. Отказ тихий —
   в разметке всё верно, видно только замером. Специфичность из двух классов
   выигрывает у одного независимо от порядка правил. */
.boss-eph .boss-absorb-badge {
  position: absolute; top: 16px; right: 16px; z-index: 2;
  display: flex; align-items: center; gap: 1px;
  padding: 2px 6px; border-radius: 3px;
  background: rgba(3, 8, 15, .78); border: 1px solid var(--border-2);
  font-family: var(--font-head); font-size: 12px; line-height: 1;
  color: var(--gold);
}
.boss-eph .boss-absorb-badge b { font-size: 13px; font-weight: 700; }
/* Слово мельче и тусклее числа: подписывает показания, а не спорит с ними. */
.bab-lab {
  margin-right: 4px; font-size: 10px; letter-spacing: 1.4px; color: var(--dim);
}
.bab-slash { color: var(--dim); margin: 0 2px; }
.boss-eph .boss-absorb-badge svg { width: 11px; height: 11px; }

/* ЛАМПЫ СКЛАДА МАССИВА (#361). Геометрия — та же, что у полосы Глаз: два ряда
   кружков на одной карточке обязаны читаться как один прибор с двумя шкалами, а
   не как две разные полосы. Цвет разный по смыслу: Глаза золотые (цель), склад
   бирюзовый (заряд) — тем же цветом Зонд показывает свою серию в #combo-lamps.
   Вспышку при начислении берём готовыми кадрами xyll-pip-pop: у них ровно та же
   задача, а вторые кадры про одно разошлись бы с первыми. */
/* #362: МАССИВ ЗАКРЫТ ДО ПЕРВОГО ЭХОЛУЧА. Вместо кадра — тёмное пятно с
   помехами, вместо имени — дрожащий #ERR. Пятно рисуем полосами, а не картинкой:
   лишний файл ради заглушки не нужен, а полосы честно читаются как сорванный
   сигнал. Движение медленное: карточка стоит рядом с полем, и быстрая рябь на
   ней отвлекала бы от хода. */
.boss-noise {
  background:
    repeating-linear-gradient(0deg, rgba(126,168,190,.10) 0 2px, transparent 2px 4px),
    radial-gradient(circle at 50% 45%, rgba(126,168,190,.10), rgba(3,8,15,.96) 70%);
  animation: boss-noise-roll 2.4s linear infinite;
}
@keyframes boss-noise-roll {
  0%   { background-position: 0 0, 0 0; }
  100% { background-position: 0 12px, 0 0; }
}
.eph-name-hidden { color: var(--dim); letter-spacing: 3px; animation: boss-noise-flicker 3.1s steps(1) infinite; }
@keyframes boss-noise-flicker {
  0%, 84%, 90%, 100% { opacity: 1; }
  86%, 88%           { opacity: .35; }
}

/* СКАНЕР ОТКЛИКА (#367). Строка панели «ОТКЛИК МАССИВА», под полосой Глаз и
   лампами склада — тот же ряд подписей, что у них, чтобы карточка читалась одним
   прибором. Слово «загрузка» мигает, пока прибор не настроен (#366): это
   единственное движение на карточке, и оно обещает, что скоро появится смысл. */
.boss-scan { display: flex; align-items: baseline; gap: 10px; padding-top: 6px; }
.boss-scan-lab {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 2.2px;
  text-transform: uppercase; color: var(--dim); white-space: nowrap;
}
.boss-scan-val { font-size: 12.5px; font-weight: 600; color: var(--teal); }
.boss-scan-loading .boss-scan-val { color: var(--dim); animation: boss-scan-blink 1.6s ease-in-out infinite; }
/* ГРОЗЯЩАЯ ПОТЕРЯ МИГАЕТ КРАСНЫМ (заказчик, 07.09.2026). Мигает ЦВЕТ, а не
   прозрачность: гаснущая строка читается как «прибор барахлит», а перекраска —
   как предупреждение. Такт медленный (1.4 с): строка стоит рядом с полем, и
   частая пульсация спорила бы с ходом.
   Значок ресурса внутри строки красится вместе с текстом — он нарисован
   currentColor, поэтому отдельного правила ему не нужно. */
.boss-scan-alarm .boss-scan-val { animation: boss-scan-alarm 1.4s steps(1) infinite; }
@keyframes boss-scan-alarm {
  0%, 49%   { color: var(--text); }
  50%, 100% { color: var(--red); }
}
@keyframes boss-scan-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
/* «ДВИЖЕНИЕ ГЛАЗА» — вторая строка прибора на тестовом стенде (задача №18,
   п.12). Мигает золотом: это не потеря и не добыча, а предупреждение о ходе
   Массива, и красный здесь спорил бы с тревогой Сканера строкой выше. Подписи у
   строки нет — надпись и есть сообщение, а лишнее слово сдвинуло бы карточку. */
.boss-scan-move { padding-top: 2px; }
.boss-scan-move .boss-scan-val {
  color: var(--gold); letter-spacing: 1.4px;
  animation: boss-scan-move 1.1s steps(1) infinite;
}
@keyframes boss-scan-move {
  0%, 54%   { opacity: 1; }
  55%, 100% { opacity: .28; }
}
/* «УДАР ПО КОНТУРУ» / «ПОТЕРЯ СВЯЗНОСТИ» — второй стенд (задача №19, п.9). Та же
   строка-предупреждение, но красная: здесь речь о прямой потере, а не о
   перестройке тела, и цвет должен различать их с одного взгляда. Мигает ЦВЕТОМ,
   как тревога Сканера строкой выше, — гаснущая строка читается как «прибор
   барахлит», а перекраска как предупреждение. */
.boss-scan-threat { padding-top: 2px; }
.boss-scan-threat .boss-scan-val {
  color: var(--red); letter-spacing: 1.4px; font-weight: bold;
  animation: boss-scan-threat 1s steps(1) infinite;
}
@keyframes boss-scan-threat {
  0%, 49%   { color: var(--red); }
  50%, 100% { color: var(--text); }
}

/* ПОГАШЕННЫЙ ГЛАЗ — тот же знак, но потухший (заказчик, 07.09.2026). Он должен
   читаться как «этот уже сделан», а не как живая цель: цвет уходит в приглушённый,
   свечения нет. Форма остаётся прежней — по ней игрок и узнаёт, что погасил
   именно Глаз, а не выжег обычный сегмент. */
.cell-eye-out .eye-ic { color: var(--dim); opacity: .75; filter: none; }

.boss-store { display: flex; align-items: center; gap: 10px; padding-top: 6px; }
.boss-store-lab {
  font-family: var(--font-head); font-size: 11px; letter-spacing: 2.2px;
  text-transform: uppercase; color: var(--dim);
}
.boss-store-pips { display: flex; gap: 4px; }
.boss-store-pips i {
  width: 9px; height: 9px; border-radius: 50%;
  background: rgba(126,168,190,.18); border: 1px solid var(--border-2);
  transition: background var(--t-tap) ease, box-shadow var(--t-tap) ease;
}
.boss-store-pips i.on { background: var(--teal); border-color: var(--teal); box-shadow: 0 0 7px rgba(78,205,196,.6); }
.boss-store-pips i.pop { animation: xyll-pip-pop var(--t-in) ease-out 2; }
/* Строка боя внутри карточки Массива: без своей рамки, отделена волосяной
   линией — двойная рамка внутри панели читалась как вложенное окно. */
#boss-bar {
  margin-top: 10px; padding: 9px 0 0; width: auto;
  background: none; border: 0; border-top: 1px solid var(--border);
  border-radius: 0; justify-content: flex-start; gap: 6px 16px;
  font-family: var(--font-mono); font-size: 12.5px; letter-spacing: 0;
}

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ДОПУСК К ЭФИРУ  (docs/design/Gate.html)
   Экрана в таком виде не было. Код разложен на пять окошек, фоном — шестёрка
   эхонавтов на треть яркости.
═══════════════════════════════════════════════════════════════════ */
#invite-overlay { background: var(--bg); }
/* Шестёрка стоит ПОЛОСОЙ посреди экрана, а не во всю высоту: сверху и снизу
   чистый фон, иначе лица упираются в кромки и экран становится коллажем.
   Числа взяты из макета (docs/design/Gate.html, .G-crew). */
#invite-bg {
  position: absolute; left: 0; right: 0; top: 18.7%; height: 62.7%;
  pointer-events: none;
  display: grid; grid-template-columns: repeat(6, 1fr);
}
/* Каждый кадр своей полосой и по cover: одним фоном из шести слоёв кадры
   растягивались по высоте — лица вытягивались в столбы. */
/* Лица ВИДНО. Прежние .34/.46/.30 вместе с заслонкой ниже съедали их почти
   насухо: за окном угадывались пятна, а не шестёрка эхонавтов. Приглушены —
   да, но узнаваемы: за этим окном ждут именно они, и это работает только если
   их видно. */
#invite-bg > i {
  display: block; background-position: center 24%; background-size: cover; background-repeat: no-repeat;
  filter: saturate(.46) brightness(.72);
  opacity: .52;
  animation: invite-nav-glow 24s ease-in-out infinite;
}
/* Шестёрка перекликается по кругу: каждые 4 с один кадр разгорается ярче
   остальных и гаснет обратно. Шесть кадров × 4 с = круг 24 с, поэтому у всех
   одна анимация и разная задержка — своей раскладки на каждого не нужно.
   Медленно намеренно: это дыхание фона, а не мигание, спорящее с полем кода. */
@keyframes invite-nav-glow {
  0%,  100% { opacity: .52; filter: saturate(.46) brightness(.72); }
  4%        { opacity: .88; filter: saturate(.85) brightness(1.04); }
  12%       { opacity: .88; filter: saturate(.85) brightness(1.04); }
  17%       { opacity: .52; filter: saturate(.46) brightness(.72); }
}
#invite-bg > i:nth-child(1) { animation-delay:  0s; }
#invite-bg > i:nth-child(2) { animation-delay:  4s; }
#invite-bg > i:nth-child(3) { animation-delay:  8s; }
#invite-bg > i:nth-child(4) { animation-delay: 12s; }
#invite-bg > i:nth-child(5) { animation-delay: 16s; }
#invite-bg > i:nth-child(6) { animation-delay: 20s; }
@media (prefers-reduced-motion: reduce) {
  #invite-bg > i { animation: none; }
}
/* Заслонка поверх кадров: тёмное пятно ПОД САМИМ ОКНОМ и растворение к краям.
   Раньше на этом месте стояла МАСКА на самих кадрах — она гасила края и
   оставляла центр самым ярким, то есть ровно наоборот. Пятно ужато до размера
   окна: прежние 46 % × 52 % при 0.92 в центре накрывали всю шестёрку целиком. */
#invite-overlay::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 34% 44% at 50% 50%, rgba(4,7,13,.90) 0%, rgba(4,7,13,.74) 45%, rgba(4,7,13,.30) 78%, rgba(4,7,13,.10) 100%),
    linear-gradient(180deg, #04070d 0%, rgba(4,7,13,.06) 22%, rgba(4,7,13,.06) 78%, #04070d 100%);
}
#invite-bg > i:nth-child(1) { background-image: url('img/navs/nav-green.webp'); }
#invite-bg > i:nth-child(2) { background-image: url('img/navs/nav-magenta.webp'); }
#invite-bg > i:nth-child(3) { background-image: url('img/navs/nav-amber.webp'); }
#invite-bg > i:nth-child(4) { background-image: url('img/navs/nav-red.webp'); }
#invite-bg > i:nth-child(5) { background-image: url('img/navs/nav-violet.webp'); }
#invite-bg > i:nth-child(6) { background-image: url('img/navs/nav-gold.webp'); }
#invite-box {
  position: relative; z-index: 1;
  background: var(--panel); border: 1px solid var(--border-2);
  box-shadow: 0 24px 70px rgba(0,0,0,.6); padding: 30px 30px 24px;
}
#invite-title {
  font-family: var(--font-head); font-size: 22px; font-weight: 500;
  letter-spacing: 5px; text-transform: uppercase; color: var(--head); text-shadow: none;
}
/* Полоска набора эхонавтов под названием — та же, что на других экранах. */
#invite-title::after {
  content: ""; display: block; width: 200px; height: 3px; margin: 12px auto 0;
  background: linear-gradient(90deg,
    #63c246 0 16.6%, #d94b6a 16.6% 33.3%, #d99a3a 33.3% 50%,
    #cf3b32 50% 66.6%, #8a5bd6 66.6% 83.3%, #eb9a3a 83.3% 100%);
}
#invite-sub { color: var(--dim); font-size: 13px; line-height: 1.6; }
/* Окошки кода и невидимое поле поверх них. Поле обязано остаться настоящим:
   на телефоне оно поднимает клавиатуру, и подделка окошками дала бы экран,
   в который нечем печатать. */
#invite-code-wrap { position: relative; margin-top: 18px; }
#invite-code { display: flex; justify-content: center; gap: 9px; }
#invite-code i {
  width: 58px; height: 68px; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(126,168,190,.28); border-radius: var(--r);
  background: #050d17; color: var(--gold);
  font-family: var(--font-head); font-style: normal;
  font-size: 32px; font-weight: 500; letter-spacing: 2px;
}
#invite-code i.ic-on  { border-color: rgba(240,208,96,.65); box-shadow: 0 0 0 1px rgba(240,208,96,.18), 0 0 22px rgba(240,208,96,.14); }
#invite-code i.ic-now { border-color: rgba(78,205,196,.75); box-shadow: inset 0 0 0 1px rgba(78,205,196,.25); }
#invite-code i.ic-now::after {
  content: ""; width: 2px; height: 34px; background: var(--teal);
  box-shadow: 0 0 10px rgba(78,205,196,.8);
  animation: gate-caret 1.1s steps(2, start) infinite;
}
@keyframes gate-caret { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }
/* Само поле прозрачно и лежит НА окошках АБСОЛЮТОМ: курсор, выделение и текст
   скрыты, видно только то, что рисуют окошки. Прежде оно поднималось
   отрицательным отступом и оставляло за собой полосу пустоты между кодом и
   подписью — на макете её нет. */
#invite-input {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0;
  margin: 0; border: 0; background: none; padding: 0; letter-spacing: 44px;
  caret-color: transparent;
}
#btn-invite-ok {
  font-family: var(--font-head); font-size: 14px; font-weight: 500;
  letter-spacing: 4px; text-transform: uppercase; padding: 13px;
  margin-top: 0;
  background: rgba(240,208,96,.07); border: 1px solid rgba(240,208,96,.5); color: var(--gold);
}
#btn-invite-ok:hover { background: rgba(240,208,96,.16); }
/* Строка ошибки стоит НАД кнопкой и место занимает всегда: текст отказа не
   должен двигать кнопку под курсором. */
#invite-error { margin: 14px 0 8px; }
#invite-foot { margin-top: 18px; font-size: 11.5px; color: var(--dim); }

@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  #invite-code { gap: 6px; }
  #invite-code i { width: 48px; height: 58px; font-size: 26px; }
}

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: ЭКРАН ЭХОНАВТОВ  (docs/design/Main.html, MainPhone.html)
   Слот эхонавта стал ШИРОКИМ КАДРОМ: портрет во всю карточку, текст на
   затемнённой половине, имя сигнальным цветом, полоса того же цвета снизу.
   Раньше это была строка с аватаркой 56 px — по ней эхонавты не различались
   ничем, кроме имени.
═══════════════════════════════════════════════════════════════════ */
/* Экран, а не окно: панели тут нет вовсе. Слева — кто вы и чем открыт
   аккаунт, справа — эхонавты кадрами во всю высоту. Одной колонкой в окне
   620 px карточка выходила вдвое ниже макетной, и портрет в ней не читался. */
#profile-overlay { background: var(--bg); padding: 0; align-items: stretch; }
/* Подсветка углов — та же, что в макете: бирюза сверху справа, золото снизу
   слева. На чистом фоне экран без неё выглядит листом бумаги. */
#profile-overlay::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 60% 40% at 74% 8%, rgba(78,205,196,.07) 0%, transparent 70%),
    radial-gradient(ellipse 50% 50% at 8% 92%, rgba(240,208,96,.045) 0%, transparent 70%);
}
#profile-box {
  position: relative;
  width: 100%; max-width: 1248px; max-height: none; height: 100%;
  margin: 0 auto; padding: 96px;
  display: flex; align-items: stretch; gap: 48px;
  background: none; border: 0; box-shadow: none; border-radius: 0;
  text-align: left; overflow: visible;
}
#profile-side { width: 396px; flex: 0 0 auto; display: flex; flex-direction: column; }
#profile-side-grow { flex: 1; }
#profile-title {
  font-family: var(--font-head); font-size: 74px; font-weight: 600;
  line-height: .94; letter-spacing: 3px; text-transform: uppercase;
  color: #eef8fc; text-shadow: 0 0 40px rgba(78,205,196,.20);
}
#profile-title::after {
  content: ""; display: block; width: 300px; height: 4px; margin: 22px 0 24px;
  background: linear-gradient(90deg,
    #63c246 0 16.6%, #d94b6a 16.6% 33.3%, #d99a3a 33.3% 50%,
    #cf3b32 50% 66.6%, #8a5bd6 66.6% 83.3%, #eb9a3a 83.3% 100%);
}
/* Карточки тянутся на всю высоту колонки и делят её поровну: три слота, три
   равные полосы. Высота в пикселях здесь была бы ложью — слотов может быть и
   один, и три. */
#profile-list { flex: 1; min-width: 0; gap: 16px; }
#profile-list > * { flex: 1 1 0; min-height: 0; }
.profile-item {
  position: relative; overflow: hidden;
  display: block; padding: 0; height: auto;
  background: #060a12; border: 1px solid var(--border-2); border-radius: var(--r);
  transition: border-color var(--t-tap), filter var(--t-tap);
}
.profile-item-ava {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 24%;
  border: 0; border-radius: 0;
  transition: filter var(--t-in);
}
/* Затемнённая половина под текст. Градиент, а не сплошная плашка: у кадра слева
   бывает светлый фон, и на резкой границе плашка читалась как наклейка. */
.profile-item::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(90deg, rgba(4,7,13,.95) 0%, rgba(4,7,13,.86) 38%, rgba(4,7,13,.05) 88%);
}
/* Полоса сигнального цвета по низу карточки — «спина» эхонавта. */
.profile-item::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 2;
  background: linear-gradient(90deg, var(--sig, var(--teal)), transparent);
}
.profile-item:hover { border-color: rgba(126,168,190,.45); background: #060a12; }
.profile-item:hover .profile-item-ava { filter: brightness(1.14); }
.profile-item.profile-active { border-color: var(--sig, var(--gold)); }
.profile-item-main { position: relative; z-index: 2; padding: 0 34px; height: 100%;
  display: flex; flex-direction: column; justify-content: center; gap: 7px; }
.profile-item-name {
  font-family: var(--font-head); font-size: 38px; font-weight: 500;
  letter-spacing: 2.5px; text-transform: uppercase; line-height: 1;
}
/* Уровень и рекорд — капсами: это подпись под именем, а не фраза. */
.profile-item-level {
  font-size: 12.5px; color: #C7DEEB; letter-spacing: 1.6px; text-transform: uppercase;
}
.profile-item-sub { font-size: 11.5px; color: var(--dim); }
.profile-item-acts { position: absolute; top: 10px; right: 10px; z-index: 3; display: flex; gap: 6px; }
.profile-act {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: rgba(10,20,31,.75); color: var(--dim);
}
.profile-act:hover { border-color: rgba(78,205,196,.5); color: var(--teal-2); }
.profile-act-del:hover { border-color: rgba(231,76,60,.6); color: #ef7264; }
.profile-act .gi { height: 15px; }
.profile-item-star { top: 10px; left: 10px; right: auto; z-index: 3; color: var(--gold); }
.profile-item-star .gi { height: 16px; }
/* ─── ФОРМА СЛОТА: имя ВНИЗУ, лицо листается стрелками ──────────────
   Поле стояло по центру карточки и приходилось ровно на глаза портрета —
   единственное место кадра, которое нельзя закрывать. Ушло в нижнюю треть,
   к той же кромке, где у соседних карточек стоит имя. */
.profile-item-form .profile-item-main {
  justify-content: flex-end; padding-bottom: 26px;
}
/* Стрелки — по краям кадра, вертикально по центру. Поверх затемнения (z-index
   выше ::before), иначе правая тонет в светлой половине портрета. */
.profile-ava-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 4;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 54px; padding: 0; cursor: pointer;
  border: 1px solid var(--border-2); border-radius: var(--r-s);
  background: rgba(4,7,13,.72); color: var(--dim);
  transition: border-color var(--t-tap), color var(--t-tap), background var(--t-tap);
}
.profile-ava-arrow:hover { border-color: rgba(78,205,196,.55); color: var(--teal-2); background: rgba(4,7,13,.86); }
.profile-ava-arrow .gi { height: 20px; }
.profile-ava-prev { left: 12px; }
.profile-ava-next { right: 12px; }
/* Пустой слот — рамка с уголками-засечками, как в макете: место, а не карточка.
   Засечки внутри рамки (9 px от края), а не снаружи: слот стоит вплотную к
   соседям, и вынесенные наружу они наезжали бы на чужую карточку. */
.profile-slot-empty {
  position: relative;
  min-height: 96px; border: 1px dashed rgba(126,168,190,.26); background: rgba(126,168,190,.022);
  color: var(--dim); font-family: var(--font-head); font-size: 19px; font-weight: 400;
  letter-spacing: 5px; text-transform: uppercase; border-radius: 0;
  display: flex; align-items: center; justify-content: center; gap: 13px;
}
.profile-slot-empty::before {
  content: ""; position: absolute; inset: 9px; pointer-events: none;
  --tick: rgba(78,205,196,.45);
  background:
    linear-gradient(var(--tick), var(--tick)) 0    0    / 12px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 0    / 12px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    100% / 12px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 100% / 12px 1px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    0    / 1px 12px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 0    / 1px 12px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 0    100% / 1px 12px no-repeat,
    linear-gradient(var(--tick), var(--tick)) 100% 100% / 1px 12px no-repeat;
}
.profile-slot-empty:hover { border-color: rgba(78,205,196,.5); color: var(--teal-2); background: rgba(78,205,196,.03); }
.pse-plus { font-size: 22px; line-height: 1; font-weight: 300; }
#profile-sub {
  margin: 0; max-width: 320px;
  font-size: 12.5px; font-weight: 300; line-height: 1.8; color: var(--dim);
}
/* Код доступа — плашка с золотой спиной: это логин, и его диктуют вслух. */
#profile-account {
  margin: 34px 0 0; width: fit-content;
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 13px 16px;
  border: 1px solid rgba(240,208,96,.26); border-left: 3px solid var(--gold);
  background: rgba(240,208,96,.04);
  color: var(--dim);
}
.pacc-label { font-size: 9.5px; letter-spacing: 3.4px; color: var(--dim); }
#profile-code {
  font-family: var(--font-head); font-size: 24px; font-weight: 500;
  letter-spacing: 6px; color: var(--gold);
  text-shadow: 0 0 22px rgba(240,208,96,.40);
}
#profile-sync { margin: 0; font-size: 11px; letter-spacing: .4px; }

/* Экран узкий — колонки складываются в одну (макет MainPhone.html). Порог
   выше телефонного: две колонки по 396 + 48 + карточки требуют ~1100 px. */
@media (max-width: 1099px) {
  #profile-box { flex-direction: column; gap: 26px; padding: 40px 24px; height: auto; overflow-y: auto; }
  #profile-side { width: auto; }
  #profile-side-grow { display: none; }
  #profile-title { font-size: 44px; }
  #profile-title::after { width: 220px; margin: 16px 0 18px; }
  #profile-account { margin-top: 20px; }
  #profile-list > * { flex: 0 0 auto; min-height: 132px; }
}
@media (max-width: 599px), (pointer: coarse) and (max-width: 900px) {
  /* Телефон: карточка ниже, но по-прежнему кадр. Текст в 390 px помещается на
     затемнённой половине только при меньшем кегле имени. */
  #profile-box { padding: 28px 16px; }
  #profile-title { font-size: 34px; letter-spacing: 2px; }
  #profile-list > * { min-height: 104px; }
  .profile-item-name { font-size: 22px; letter-spacing: 1.6px; }
  .profile-item-main { padding: 0 14px; gap: 4px; }
  .profile-item-ava { width: 100%; height: 100%; }
  .profile-slot-empty { font-size: 14px; letter-spacing: 3px; }
}

/* ═══════════════════════════════════════════════════════════════════
   «ГАЛЕРЕЯ»: СООБЩЕНИЯ  (docs/design/Messages.html)
   Анатомия ОДНА на все тоны: шапка «отправитель | протокол» мелкими
   прописными, заголовок цветом тона, текст, подвал с галочкой «больше не
   показывать» слева и кнопками справа. Тонов пять, и у каждого своя работа:
     красный    — сбой, потеря, атака: только когда уже случилось;
     жёлтый     — предупреждение о том, что ещё можно исправить;
     зелёный    — удача, награда названа числом;
     бирюзовый  — голос Эхо-Камеры: правила, инструктаж, лор;
     фиолетовый — аномалия: Искажение, Массив, Отзвук.
   Янтарный «засекречено» оставлен как был: это не тон сообщения, а гриф
   допуска, и в списке пяти его нет по построению.
═══════════════════════════════════════════════════════════════════ */
.hint-box { border-radius: var(--r); box-shadow: 0 24px 70px rgba(0,0,0,.6); }
.hint-header { padding: 13px 22px 11px; }
.hint-header-top {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2.6px; margin-bottom: 7px;
}
#hint-label, #mem-label, .hint-box .hint-label {
  font-family: var(--font-head); font-size: 19px; font-weight: 500;
  letter-spacing: 3px; line-height: 1.1;
}
.hint-footer { font-family: var(--font-head); font-size: 11px; letter-spacing: 2px; }
#hint-close, #mem-close, .hint-box button {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; border-radius: var(--r-s);
}
/* Сообщение ВЪЕЗЖАЕТ снизу, затемнение фона появляется отдельно и быстрее:
   вместе они читаются как «экран отступил, и на него положили лист». */
#hint-overlay:not(.hidden), #mem-overlay:not(.hidden), #generic-confirm-overlay:not(.hidden) {
  animation: msg-veil 200ms ease both;
}
#hint-overlay:not(.hidden) .hint-box,
#mem-overlay:not(.hidden) .hint-box,
#generic-confirm-overlay:not(.hidden) > * {
  animation: msg-rise var(--t-in) cubic-bezier(.2,.7,.3,1) both;
}
@keyframes msg-veil { from { opacity: 0 } to { opacity: 1 } }
@keyframes msg-rise { from { opacity: 0; transform: translateY(18px) } to { opacity: 1; transform: none } }

/* Пять тонов. Класс вешается на .hint-box рядом с hint-normal / hint-classified
   / hint-glitch — те три остаются, это их же вид под новыми токенами. */
.hint-tone { background: var(--panel); border: 1px solid var(--tone-line, var(--border-2)); color: var(--text); }
.hint-tone .hint-header     { border-color: var(--tone-line); background: var(--tone-fill); }
.hint-tone .hint-header-top { color: var(--tone-dim); }
.hint-tone #hint-label      { color: var(--tone); }
.hint-tone .hint-footer     { border-color: var(--tone-line); color: var(--dim-2); }
.hint-tone #hint-close      { border-color: var(--tone-line); color: var(--tone); background: var(--tone-fill); }
.hint-tone #hint-close:hover { filter: brightness(1.3); }
.tone-red    { --tone: #ef7264; --tone-line: rgba(231,76,60,.55);  --tone-fill: rgba(231,76,60,.06);  --tone-dim: rgba(231,76,60,.75); }
.tone-yellow { --tone: #f2a93b; --tone-line: rgba(243,156,18,.55); --tone-fill: rgba(243,156,18,.06); --tone-dim: rgba(243,156,18,.75); }
.tone-green  { --tone: #55d98a; --tone-line: rgba(46,204,113,.55); --tone-fill: rgba(46,204,113,.06); --tone-dim: rgba(46,204,113,.75); }
.tone-teal   { --tone: var(--teal); --tone-line: rgba(78,205,196,.55); --tone-fill: rgba(78,205,196,.06); --tone-dim: rgba(78,205,196,.75); }
.tone-purple { --tone: #b795f0; --tone-line: rgba(155,89,182,.6);  --tone-fill: rgba(155,89,182,.08); --tone-dim: rgba(155,89,182,.8); }

/* Связность в приборной строке — кардиограммами, как в слое. */
.hp-pips { display: inline-flex; align-items: center; gap: 4px; }
.hp-pips .heart { font-size: 0; }
.hp-pips .heart .gi { height: 15px; }
.hp-pips .heart.full  { color: var(--teal); }
.hp-pips .heart.empty { color: rgba(231,76,60,.75); }
/* Контур — цвета вертикальной батареи слоя: запас бирюзовый, предпоследнее
   деление оранжевое, последнее красное. */
.pips-bat i.bat-pip { border: 1px solid rgba(78,205,196,.45); background: none; opacity: 1; }
.pips-bat i.bat-pip.full     { background: var(--teal); border-color: var(--teal); }
.pips-bat i.bat-pip.warn-mid { background: #f39c12; border-color: #f39c12; }
.pips-bat i.bat-pip.warn     { background: #e74c3c; border-color: #e74c3c; }

/* ─── ДЕЛЕНИЯ: СКОЛЬКО ИЗ СКОЛЬКИХ ───────────────────────────────
   Связность, контур и слоты показаны полосой делений, а не только числом
   (заказчик, 29.08.2026). Величины разные, вопрос один, поэтому разметка одна:
   заполненные деления цветом величины, пустые — рамкой. */
.pips { display: inline-flex; gap: 2px; align-items: center; vertical-align: middle; }
.pips i {
  display: block; width: 7px; height: 13px;
  border: 1px solid currentColor; border-radius: 1px;
  opacity: .32;
}
.pips i.on { background: currentColor; opacity: 1; }
/* Контур — «батарея»: деления шире и лежат вплотную, как ячейки. */
.pips-bat i { width: 9px; }
/* Слоты — квадратики: слот либо занят, либо нет, «наполовину» не бывает. */
.pips-slot i { width: 11px; height: 11px; }
.pips-n { margin-left: 8px; font-weight: 600; }

/* ─── ПОДСКАЗКА ПРИ НАВЕДЕНИИ ────────────────────────────────────
   Появляется через 450 мс УДЕРЖАНИЯ, проявляется 150 мс, исчезает сразу.
   Задержка — это и есть смысл: без неё подсказки вспыхивали у каждого значка,
   мимо которого проехал курсор. Сделано задержкой перехода, а не таймером в
   JS: у ухода задержка нулевая, поэтому подсказка гаснет мгновенно.

   Класс `.has-tip` — та же подсказка для ЛЮБОГО элемента: раньше механизм был
   привязан к `.res-item` и работал только в шапке слоя. Заказчик просил читать
   по наведению про оборудование и про непонятные счётчики — им нужен тот же
   приём, а не второй. */
.has-tip { position: relative; }
.res-item[data-tip]::after,
.has-tip[data-tip]::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%);
  background: #0e1c2a; border: 1px solid rgba(126,168,190,.34); border-radius: var(--r);
  box-shadow: 0 14px 34px rgba(0,0,0,.55);
  padding: 7px 11px; font-size: 12px; color: var(--text);
  white-space: nowrap; pointer-events: none; z-index: 50;
  opacity: 0; visibility: hidden;
  transition: opacity 150ms ease 0ms, visibility 0s linear 150ms;
}
.res-item[data-tip]:hover::after,
.has-tip[data-tip]:hover::after {
  opacity: 1; visibility: visible;
  transition: opacity 150ms ease 450ms, visibility 0s linear 450ms;
}
/* Длинную подсказку переносим по словам: у оборудования это две-три строки,
   а не ярлык. `pre-line` — чтобы перевод строки в каталоге тоже работал. */
.has-tip[data-tip]::after {
  white-space: pre-line; max-width: 320px; width: max-content;
  line-height: 1.5; text-align: left; font-family: var(--font-mono);
  /* Подсказку читают поверх карточек и портрета, поэтому фон ПЛОТНЫЙ и с
     тенью: полупрозрачная подложка пропускала рисунок под собой, и текст
     разбирался с трудом (заказчик, 29.08.2026). */
  background: #0b1018; border-color: rgba(126,168,190,.5);
  box-shadow: 0 18px 46px rgba(0,0,0,.75), 0 0 0 1px rgba(4,7,13,.9);
  padding: 9px 13px;
}
/* У крайних правых элементов подсказка упиралась бы в кромку окна. */
.has-tip.tip-right::after { left: auto; right: 0; transform: none; }
.has-tip.tip-left::after  { left: 0; right: auto; transform: none; }
/* Шапка стоит у верхней кромки экрана — её подсказка падает ВНИЗ, иначе
   уезжает за край и не читается вовсе. Это относится и к ресурсам: они живут
   в той же строке, и их подсказка обрезалась ровно так же. */
.has-tip.tip-below::after { bottom: auto; top: calc(100% + 6px); }
#res-bar .res-item[data-tip]::after {
  bottom: auto; top: calc(100% + 6px);
  white-space: pre-line; width: max-content; max-width: 300px;
  line-height: 1.5; text-align: left;
  background: #0b1018; border-color: rgba(126,168,190,.5);
  box-shadow: 0 18px 46px rgba(0,0,0,.75), 0 0 0 1px rgba(4,7,13,.9);
  padding: 9px 13px;
}
/* Колонка контура прижата к левому краю окна: подсказка уходит ВПРАВО от неё. */
.has-tip.tip-side::after {
  bottom: auto; top: 8px; left: calc(100% + 8px); right: auto; transform: none;
}
/* Подсказка обязана лежать ПОВЕРХ соседей: у карточек слотов и панелей свои
   слои, и без этого её срезало по кромке соседней карточки. */
.has-tip { z-index: 0; }
.has-tip:hover { z-index: 30; }
/* ─── ПОДСКАЗКА ОТДЕЛЬНЫМ УЗЛОМ (.tip-node) ──────────────────────
   Там, где оба псевдоэлемента заняты — а у карточки слота это так: ::after
   держит блик по кромке, ::before подсветку выбранного инструмента, — подсказка
   рисуется настоящим узлом. Поведение то же: 450 мс удержания, проявление
   150 мс, мгновенный уход. */
.tip-node {
  position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%);
  background: #0b1018; border: 1px solid rgba(126,168,190,.5); border-radius: var(--r);
  box-shadow: 0 18px 46px rgba(0,0,0,.75), 0 0 0 1px rgba(4,7,13,.9);
  /* Крупнее и просторнее (заказчик, 29.08.2026: «модалка должна быть больше»):
     подсказку читают поверх портрета и карточек, и в 12 px с тесными полями
     текст сливался с тем, что под ним. */
  padding: 13px 16px; font-size: 13.5px; line-height: 1.6; color: var(--text);
  font-family: var(--font-mono); letter-spacing: 0; text-transform: none; text-align: left;
  white-space: pre-line; width: max-content; max-width: 360px;
  pointer-events: none; z-index: 60;
  opacity: 0; visibility: hidden;
  transition: opacity 150ms ease 0ms, visibility 0s linear 150ms;
}
.has-tip-node:hover > .tip-node {
  opacity: 1; visibility: visible;
  transition: opacity 150ms ease 450ms, visibility 0s linear 450ms;
}
/* Карточке нужен выход за рамку и подъём над соседями: слоты стоят вплотную. */
#tool-section .card-slot.has-tip-node { overflow: visible; }
#tool-section .card-slot.has-tip-node:hover { z-index: 40; }
/* Крайние слоты: подсказка не должна вылезать за кромку окна. */
#tool-section .card-slot:first-child > .tip-node { left: 0; transform: none; }
#tool-section .card-slot:nth-child(4n) > .tip-node { left: auto; right: 0; transform: none; }

/* ─── МЕНЮ: РАЗДЕЛЫ ──────────────────────────────────────────────── */
#settings-links { display: flex; flex-direction: column; margin: 4px 0 10px; }
.settings-link {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; border: 0; border-radius: var(--r-s);
  background: none; color: var(--text); cursor: pointer; text-align: left;
  font-family: var(--font-mono); font-size: 14px;
  transition: background var(--t-tap), color var(--t-tap);
}
.settings-link:hover { background: var(--panel-2); color: var(--teal-2); }
.settings-link .gi { height: 16px; color: var(--dim); }
.settings-link:hover .gi { color: var(--teal-2); }
.settings-link b { margin-left: auto; font-weight: 600; color: var(--gold); letter-spacing: 2px; }
/* Значение справа у строки-переключателя. Выключенное — тусклое: золотой у
   «ВЫКЛ» читался бы как достижение, а это отказ от помощи. */
.settings-link b.set-val-off { color: var(--dim-2); }
/* Выход — такая же строка меню, как остальные, только красная: рамка вокруг
   неё делала из неё главное действие меню, каким она не является. */
.settings-link-quit { color: #ef7264; margin-top: 6px; border-top: 1px solid var(--border); border-radius: 0; }
.settings-link-quit .gi { color: rgba(231,76,60,.75); }
.settings-link-quit:hover { background: rgba(231,76,60,.08); color: #ff8f80; }
.settings-link-quit:hover .gi { color: #ff8f80; }
.settings-label {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2.4px; text-transform: uppercase; color: var(--dim-2);
}
.settings-val { font-family: var(--font-mono); font-size: 12px; color: var(--dim); }
#settings-title {
  font-family: var(--font-head); font-size: 20px; font-weight: 500;
  letter-spacing: 4px; text-transform: uppercase; color: var(--head);
}

/* Универсальное окно сообщения: та же анатомия, что у подсказок — шапка с
   отправителем, заголовок тоном, текст, подвал с кнопками. Анатомия ОДНА на
   все окна (макет Messages.html): раньше шапка была только у тех вызовов, что
   сами её задали, а два десятка прочих приходили голым текстом по центру. */
#generic-confirm-box.gc-tone {
  padding: 0; overflow: hidden; text-align: left;
  /* Рамка и тень — тона сообщения. У окна свой id, и правило .hint-tone его не
     перебивает: повторяем здесь. */
  background: var(--panel); border: 1px solid var(--tone-line);
  box-shadow: 0 24px 70px rgba(0,0,0,.6);
}
#generic-confirm-head { padding: 13px 22px 11px; border-bottom: 1px solid var(--tone-line); background: var(--tone-fill); }
#generic-confirm-from {
  font-family: var(--font-head); font-size: 11px; font-weight: 500;
  letter-spacing: 2.6px; text-transform: uppercase; color: var(--tone-dim); margin-bottom: 7px;
}
#generic-confirm-label {
  font-family: var(--font-head); font-size: 19px; font-weight: 500;
  letter-spacing: 3px; text-transform: uppercase; color: var(--tone); line-height: 1.1;
}
#generic-confirm-box.gc-tone #generic-confirm-text { padding: 20px 22px 6px; font-size: 14px; line-height: 1.6; }
#generic-confirm-box.gc-tone #generic-confirm-nomore { padding: 0 22px; }
#generic-confirm-box.gc-tone #generic-confirm-btns {
  padding: 14px 22px 18px; justify-content: flex-end; gap: 10px;
}
#generic-confirm-box.gc-tone #generic-confirm-btns button {
  font-family: var(--font-head); font-size: 12px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; border-radius: var(--r-s);
}
/* «Безопасная слева»: остаться на станции — левая кнопка и нейтральная,
   погрузиться всё равно — правая и в тоне предупреждения. */
#generic-confirm-box.gc-tone #btn-generic-no  { order: -1; border-color: var(--border-2); color: var(--dim); background: var(--panel-2); }
#generic-confirm-box.gc-tone #btn-generic-yes { border-color: var(--tone-line); color: var(--tone); background: var(--tone-fill); }

/* ═══════════════════════════════════════════════════════════════════
   #327: РАЗДЕЛ «МАССИВЫ» В АТЛАСЕ
   Карточка того же строя, что у слоя, но с двумя изображениями сразу:
   портрет образца и СХЕМА ТЕЛА. Схема здесь главная — по ней Массив узнают
   в поле. Позиции Глаз на ней НЕТ (#336): они переезжают после каждой победы,
   а их поиск и есть слой Массива. Сколько их — сказано строкой рядом.
   Сетка та же, что у слоёв: `align-content: start` и `grid-auto-rows`
   обязательны — контейнер прокручивается внутри окна, и без них первая
   строка получает нулевую высоту (на этом уже обжигались, #222).
═══════════════════════════════════════════════════════════════════ */
#atlas-bosses {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px;
  align-content: start; grid-auto-rows: min-content;
}
.ab-card {
  align-self: start; overflow: hidden;
  border: 1px solid rgba(155,89,182,.4); border-radius: var(--r);
  background: rgba(155,89,182,.04);
}
.ab-card.ab-done { border-color: rgba(155,89,182,.7); box-shadow: 0 0 0 1px rgba(155,89,182,.18); }
/* Невстреченный — закрытая рамка, как ненайденная мембрана. Ни формы, ни числа
   Глаз: это ровно та подсказка, ради поиска которой слой Массива и существует. */
.ab-void {
  min-height: 190px; border-style: dashed; border-color: rgba(126,168,190,.16);
  background: rgba(126,168,190,.015);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
}
.ab-lock  { font-size: 26px; color: var(--dim-2); }
.ab-void-t { font-size: 12.5px; color: var(--dim-2); letter-spacing: .04em; }

.ab-top {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; background: #050b13;
  border-bottom: 1px solid rgba(155,89,182,.22);
}
.ab-art   { width: 96px; height: 96px; object-fit: cover; border-radius: 3px; flex: 0 0 auto; }
.ab-noart { width: 96px; height: 96px; display: flex; align-items: center; justify-content: center;
            color: var(--dim-2); font-size: 22px; border: 1px dashed rgba(126,168,190,.18); border-radius: 3px; flex: 0 0 auto; }

/* СХЕМА ТЕЛА. Клетки квадратные и одинаковые при любой форме: ширину столбца
   задаёт grid, а высоту держит aspect-ratio — при 8×5 у Угнетателя и 10×6 у
   Колокола-13 сетка иначе поехала бы по вертикали. */
.ab-shape { display: grid; gap: 2px; flex: 1 1 auto; max-width: 168px; }
.ab-shape i { aspect-ratio: 1; border-radius: 1px; background: transparent; }
.ab-shape i.on  { background: rgba(155,89,182,.30); box-shadow: inset 0 0 0 1px rgba(155,89,182,.5); }
/* Правила для класса .eye здесь БЫЛО и снято вместе с самой пометкой (#336):
   схема показывает только форму тела, позиция Глаз — не её дело. */

.ab-body { padding: 12px 14px 14px; }
.ab-name { font-family: var(--font-head); font-size: 16px; font-weight: 500; letter-spacing: 1px; color: #c8a0e0; }
.ab-sub  { font-size: 11.5px; color: var(--dim); margin-top: 2px; }
.ab-rows { margin: 10px 0 10px; display: flex; flex-direction: column; gap: 3px; }

/* Плашка эффектов переворачивается тем же классом, что бонусы эфемеров, —
   анимация и вид достаются ей даром. Своё здесь только окраска по стороне. */
.ab-eff { margin-top: 0; }
.ab-eff-inf  { border-color: rgba(231,76,60,.35); }
.ab-eff-emi  { border-color: rgba(243,156,18,.35); }
.ab-eff-none { border-color: rgba(78,205,196,.3); }

@media (max-width: 720px) {
  #atlas-bosses { grid-template-columns: 1fr; }
}
/* Непройденный МАССИВ в разделе «Слои»: та же пустая рамка, но фиолетовая —
   строение погружения видно, содержимое нет (#326). */
.al-void.al-void-boss { border-color: rgba(155,89,182,.28); background: rgba(155,89,182,.02); }

/* ═══════════════════════════════════════════════════════════════════
   #343: ВТОРАЯ МОЛНИЯ — РАБОТАЕТ КАРТА ЗАРЯДА
   Стоит над шкалой контура, тем же значком, что и сама шкала. Зовёт ровно
   так же, как кнопка «ПОГРУЖЕНИЕ» (см. dive-call): медленный перелив за
   3.2 с, один проход яркости. Не мигание — мигание в слое читается как
   тревога, а тревога у контура своя (.battery-warn, красные деления), и
   спутать их нельзя. Здесь наоборот: «сейчас заряда приходит больше».
   Цвет золотой — цвет заряда во всей игре.
═══════════════════════════════════════════════════════════════════ */
#bat-map-flag {
  color: var(--gold);
  line-height: 0;
  margin-bottom: 2px;
  animation: bat-map-call 3.2s ease-in-out infinite;
}
#bat-map-flag .gi { height: 16px; }
@keyframes bat-map-call {
  0%, 62%, 100% { opacity: .38; filter: none; }
  80%           { opacity: 1;   filter: drop-shadow(0 0 6px rgba(240,208,96,.75)); }
}
@media (prefers-reduced-motion: reduce) {
  #bat-map-flag { animation: none; opacity: 1; }
}

/* ─── КОНТЕЙНЕР КСИЛЛА В СЛОТЕ (заказчик, 16.09.2026) ───────────────────────
   Слот кристаллов отличается от соседей ФОНОМ, а не устройством: картинка,
   имя и строка внизу стоят там же, где у всего снаряжения. Синий — цвет самого
   Ксилла (#4fd8e8), тот же, что у заполненных ячеек значка.
   Счётчик мигает тройной вспышкой раз в восемь секунд: контейнер надо замечать
   краем глаза, не отрываясь от поля, а постоянное свечение на таком слоте
   сливалось бы с подсветкой выбранного прибора. */
.card-slot.xyll-slot {
  border-color: rgba(79,216,232,.55);
  background: linear-gradient(180deg, rgba(79,216,232,.12), rgba(79,216,232,.04));
}
.card-slot.xyll-slot:hover { border-color: rgba(79,216,232,.85); }
.card-slot.xyll-slot-filled {
  border-color: #4fd8e8;
  box-shadow: 0 0 14px rgba(79,216,232,.35);
  background: linear-gradient(180deg, rgba(79,216,232,.20), rgba(79,216,232,.06));
}
.card-cost.xyll-count {
  color: #7fe8f4;
  font-weight: bold;
  /* Свойствами по отдельности, а не сокращением: в сокращении со ступенчатой
     функцией правило отбрасывалось целиком, и счётчик стоял неподвижно. */
  animation-name: xyll-count-blink;
  animation-duration: 8s;
  animation-iteration-count: infinite;
  animation-timing-function: steps(1, end);
}
/* Три вспышки подряд, дальше семь секунд покоя. Шаги в процентах от восьми
   секунд: 0.4 с на вспышку, между ними столько же. */
@keyframes xyll-count-blink {
  0%, 100%   { opacity: 1; }
  2%,  7%    { opacity: .25; }
  4.5%, 9.5% { opacity: 1; }
  12%        { opacity: .25; }
  14.5%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .card-cost.xyll-count { animation: none; }
}

/* ─── КАРТОЧКА ФИНАЛЬНОГО МАССИВА (задание №31) ─────────────────────────────
   Карточка у него общая с Эталоном — два ряда квадратиков по телу, счётчик
   заражения в углу, — но сам он СИНИЙ, и квадраты тела обязаны читаться его
   цветом: фиолетовый на синей карточке выглядел как чужая деталь. */
.boss-eph-blue .bsd-dot        { background: #4fd8e8; box-shadow: 0 0 5px rgba(79,216,232,.45); }
.boss-eph-blue .bsd-dot.off    { background: rgba(79,216,232,.20); box-shadow: none; }
.boss-eph-blue .bsd-count      { color: #7fe8f4; }
/* Сканер в финале не работает: строка стоит ровно, не мигает «загрузкой». */
.boss-scan.boss-scan-fail .boss-scan-val { color: #e07a5f; letter-spacing: .5px; }
/* Окно мембраны-заглушки: строки ошибок, первая — паническая. */
.mem-final-line  { margin: 0 0 10px; color: #a8c4d4; letter-spacing: .4px; }
.mem-final-panic { color: #e74c3c; font-weight: bold; }
