/* css/orbit.css — FABRIKO ORBIT: цех-космос одним кадром.
   Слои: канвас (fixed, z 0) → станции трека (z 2, панели поверх) → HUD (z 10)
   → шапка (z 30) → интро-гейт (z 60). Скролл не лочится: канвасу отдан
   touch-action: pan-y, панели не перехватывают свайпы. */

:root {
  --fabriko-bg: #0e1013;
  --fabriko-bg-2: #12151a;
  --fabriko-panel: rgba(18, 21, 26, 0.82);
  --fabriko-line: rgba(233, 224, 209, 0.12);
  --fabriko-hot: #d98e4a;
  --fabriko-hot-strong: #eda45f;
  --fabriko-cold: #8fb7d9;
  --fabriko-text: #ece7dd;
  --fabriko-dim: #a8a49a;
  --fabriko-mono: "JetBrains Mono", "Cascadia Mono", ui-monospace, monospace;
  --orbit-span: 1600vh;
}

/* ── сцена ─────────────────────────────────────────────────────────────── */

.orbit-stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  background:
    radial-gradient(1300px 700px at 78% -8%, rgba(217, 142, 74, 0.07), transparent 60%),
    radial-gradient(1100px 640px at 12% 30%, rgba(143, 183, 217, 0.06), transparent 62%),
    var(--fabriko-bg);
}

.orbit-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: pan-y; /* инвариант 7: палец всегда скроллит страницу */
}

.orbit-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* фикс B8 (BUGLIST 22.10): нижняя вуаль 0.82 → 0.45 — нижняя половина кадра
     больше не тонет в чёрном (вуаль — слой затемнения DOM поверх рендера) */
  background:
    linear-gradient(180deg, rgba(14, 16, 19, 0.72) 0%, rgba(14, 16, 19, 0) 22%, rgba(14, 16, 19, 0) 66%, rgba(14, 16, 19, 0.45) 100%);
}

/* ITER8 — фокус «Разбор-лаборатории»: при разборке стены приглушаются
   в самой сцене (src/hero/hero-scene.js), а этот слой доготавливает мягкую
   виньетку поверх кадра — панели в фокусе. Только opacity (compositor). */
.orbit-shade::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 92% at 50% 42%, rgba(10, 12, 16, 0) 40%, rgba(10, 12, 16, 0.52) 100%);
  opacity: 0;
  transition: opacity 0.7s ease;
  pointer-events: none;
}
body[data-station="explode-lab"] .orbit-shade::after { opacity: 0.7; }

/* финал-петля: кроссфейд логотипа (идея судьи, DEVLOG фаза 6 «не внедрены»
   → внедрено 18.10) — на станции «Пилот» водяной знак FABRIKO проявляется
   поверх кадра (медленный облёт камеры добавляет src/hero/hero-scene.js) */
.orbit-stage::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: url("../assets/logo-f.svg") center 40% / min(300px, 46vw) no-repeat;
  opacity: 0;
  transition: opacity 1.4s ease 0.3s;
}
body[data-station="pilot"] .orbit-stage::after { opacity: 0.85; }

.explode-labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.explode-label {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(-200px, -200px);
  font-family: var(--fabriko-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--fabriko-hot-strong);
  background: rgba(14, 16, 19, 0.78);
  border: 1px solid rgba(217, 142, 74, 0.45);
  border-radius: 6px;
  padding: 3px 8px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.25s;
  will-change: transform;
}

/* ITER8: золотые выноски-пороги «Разбор-лаборатории» — стиль референса
   (кадр 2): тонкая золотая линия + точка на панели + текст с данными
   карточки модуля. Позиция/прозрачность пишет js (transform/opacity). */
.explode-callout {
  position: absolute;
  top: 0;
  left: 0;
  font-family: var(--fabriko-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: #e8cd93;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.25s;
  will-change: transform;
  pointer-events: none;
  z-index: 3;
}
.explode-callout .c-dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #c8a24b;
  box-shadow: 0 0 0 2px rgba(200, 162, 75, 0.28);
  transform: translate(-3px, -3px);
}
.explode-callout .c-line {
  position: absolute;
  left: 0;
  top: 0;
  width: 54px;
  height: 1px;
  background: linear-gradient(90deg, #c8a24b, rgba(200, 162, 75, 0.3));
  transform-origin: 0 50%;
  transform: rotate(-38deg);
}
.explode-callout .c-text {
  position: absolute;
  left: 42px;
  top: -34px;
  padding: 3px 8px;
  background: rgba(14, 16, 19, 0.78);
  border: 1px solid rgba(200, 162, 75, 0.45);
  border-radius: 6px;
}

/* ── трек и станции ────────────────────────────────────────────────────── */

.orbit-track {
  position: relative;
  z-index: 2;
}

.station {
  position: relative;
  pointer-events: none;
}

.station > .pin {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  padding: calc(var(--header-h, 72px) + 22px) 0 24px;
}

/* высоты секций = сырые доли таймлайна (бэнды ×3 учтены планом трека).
   P2 критика 2026-10-20 (темп пинов): «Разбор-лаборатория» держала экран
   ~20 кадров на 375, «Карта раскроя» ~14 на 1366/1920 — статики провисали.
   Обе скраб-зоны ужаты ~26% (0.30 → 0.22, 0.2625 → 0.195): таймлайн камеры
   читается с DOM-секций (scroll-timeline._progressFromDom), так что камера
   и подписи станций остаются согласованными. */
.st-hero { height: max(calc(var(--orbit-span) * 0.1125), 165vh); }
.st-studio { height: max(calc(var(--orbit-span) * 0.125), 165vh); }
.st-explode { height: calc(var(--orbit-span) * 0.22); }
.st-cut { height: calc(var(--orbit-span) * 0.195); }
.st-estimate { height: max(calc(var(--orbit-span) * 0.0625), 110vh); }
.st-ctor { height: max(calc(var(--orbit-span) * 0.075), 130vh); }
.st-pilot { height: max(calc(var(--orbit-span) * 0.0625), 120vh); }

/* ── стыковый переход станций: световой срез по кадру (дуэль 2026-10-20,
   паритет кино-переходов эталона; только transform+opacity — работает и на
   софт-растре). Шейдерный хрома-вайп героя остаётся верхним слоем. ── */
.station-flash {
  position: fixed; inset: -12%; z-index: 5; pointer-events: none;
  background: linear-gradient(105deg,
    transparent 40%,
    rgba(238, 168, 95, 0.13) 48.5%,
    rgba(233, 224, 209, 0.20) 50%,
    rgba(238, 168, 95, 0.13) 51.5%,
    transparent 62%);
  transform: translate3d(-62%, 0, 0);
  opacity: 0;
}
.station-flash.go { animation: stationSweep 0.85s cubic-bezier(0.3, 0.6, 0.2, 1) 1; }
@keyframes stationSweep {
  0%   { transform: translate3d(-62%, 0, 0); opacity: 0; }
  16%  { opacity: 1; }
  100% { transform: translate3d(62%, 0, 0); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .station-flash { display: none; }
}

/* ── панели глав: видимость = пин секции + скраб скролла (B2/C1, ghostUI) ──
   История: выключатель body[data-station] с кроссфейдом 0.5 с держал на стыке
   секций ОБЕ панели полупрозрачными (призрачный двойной UI, B2), а уходящая
   доезжала до зоны шапки (C1). Затем пришли классы js/orbit-ui.js
   (updatePinState): pin-live — пин прилип; pin-in — приходящая едет к
   прилипанию. Но тайм-фейд прихода (0.4 с) не детерминирован против
   геометрической середины перехода: на кадре flip панель успевала
   проявиться выше порога видимости ВМЕСТЕ с док-оболочкой (гейт ghostUI
   насчитывал 2 видимых панели, pass2 tr-4) или не успевала вовсе (0).
   Теперь (фикс ghostUI pass2):
   • .panel-dock — ДОК-оболочка панели станции (флекс-рамка .wrap 1180px):
     сам никогда не виден (visibility:hidden) и прибором ghostUI не
     считается; видимой частью станции является .panel-card внутри;
   • .panel (герой и пилот — контент без карточки) и .panel-dock .panel-card —
     фейд-юниты: opacity/transform им пишет js/orbit-ui.js ПРОПОРЦИОНАЛЬНО
     СКРОЛЛУ, а не времени: в окне подхода секции [top−vh, top) панель
     контр-трансформом держит положение экрана (то, где окажется к пину) и
     проявляется на первых 45% окна → на середине перехода (flip = top−vh/2)
     видима ровно одна панель — приходящая, при любом темпе скролла;
   • после отлипания пина панель гаснет на первых ~8% vh скролла — в шапку
     не доезжает (C1), к середине перехода уже невидима;
   • visibility остаётся выключателем кликов (задержка 0.15 с на прятанье —
     успевает доиграть скраб-фейд ухода). */
.panel,
.panel-dock .panel-card {
  opacity: 0;
  transform: translateY(26px);
}

.panel {
  pointer-events: none;
  /* visibility гасит и клики по невидимым кнопкам панели (pointer-events:auto
     у детей иначе пробивал бы скрытую панель) */
  visibility: hidden;
  transition: visibility 0s linear 0.15s;
  width: 100%;
}

/* док — невидимая флекс-рамка панели станции; карточку пробивает собственное
   visibility у .panel-card (visibility не наследуется сквозь собственное
   значение элемента) */
.panel-dock {
  pointer-events: none;
  visibility: hidden;
  width: 100%;
}

.panel-dock .panel-card {
  visibility: hidden;
  transition: visibility 0s linear 0.15s;
}

.station.pin-live .panel,
.station.pin-in .panel,
.station.pin-out .panel,
.station.pin-live .panel-dock .panel-card,
.station.pin-in .panel-dock .panel-card,
.station.pin-out .panel-dock .panel-card {
  visibility: visible;
  transition: visibility 0s;
}

/* хвост 4 (волна хвостов 06.11, гейт G4): правило выше убивало фейд копии
   героя — .station.pin-live .panel несёт специфичность (0,3,0) и грузится
   ПОЗЖЕ .station .hero-copy-orbit из landing.css:1447 (0,2,0), шорткат
   transition: visibility 0s сбрасывал объявленный там opacity-фейд 0.45s.
   Ступень инлайновой opacity от снапа случается ИМЕННО на пине — фейд
   умирал ровно в нужный момент (гейт: max |Δopacity| по rAF 0.525,
   computed transition = «visibility 0s»). Дублируем фейд той же
   специфичностью и позже по каскаду, сохраняя мгновенный visibility пина. */
.station.pin-live .hero-copy-orbit,
.station.pin-in .hero-copy-orbit,
.station.pin-out .hero-copy-orbit {
  transition: opacity 0.45s ease-out, visibility 0s;
}

/* B2: ленивый iframe живого конструктора не рисуется вне своей станции
   (раньше не прятался вовсе и светился в переходах; visibility, не display —
   раскладка панели не прыгает) */
body:not(.orbit-static) .st-ctor iframe[data-ctor-frame] { visibility: hidden; }
body:not(.orbit-static) .st-ctor.pin-in iframe[data-ctor-frame],
body:not(.orbit-static) .st-ctor.pin-live iframe[data-ctor-frame],
body:not(.orbit-static) .st-ctor.pin-out iframe[data-ctor-frame] { visibility: visible; }

/* интерактивные элементы панели всегда кликабельны */
.panel a, .panel button, .panel input, .panel select,
.panel .cut-part, .panel [data-decor] {
  pointer-events: auto;
}

.panel-card {
  pointer-events: auto;
  background: var(--fabriko-panel);
  border: 1px solid var(--fabriko-line);
  border-radius: 18px;
  padding: 22px 24px;
  backdrop-filter: blur(10px);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}

/* ── герой (станция 1) ─────────────────────────────────────────────────── */

.hero-copy-orbit .kicker { color: var(--fabriko-hot-strong); }
.hero-copy-orbit .hero-display {
  font-family: "Unbounded", var(--font-display);
  font-weight: 500;
  font-size: clamp(30px, 4.6vw, 58px);
  letter-spacing: -0.01em;
}
.hero-copy-orbit .hero-display em {
  font-style: normal;
  color: var(--fabriko-hot-strong);
}
.hero-copy-orbit .display { font-family: "Unbounded", var(--font-display); font-weight: 500; }
.hero-copy-orbit h3 { font-family: "Unbounded", var(--font-display); font-weight: 500; letter-spacing: 0; }

.hero-hint-orbit {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--fabriko-dim);
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.hero-hint-orbit i {
  display: block;
  width: 1px;
  height: 44px;
  background: linear-gradient(180deg, var(--fabriko-hot), transparent);
  animation: hintPulse 2.2s ease-in-out infinite;
}
@keyframes hintPulse {
  0%, 100% { transform: scaleY(0.55); opacity: 0.4; }
  50% { transform: scaleY(1); opacity: 1; }
}

/* карточка модуля (тап по стапелю/фасаду) */
.staple-card {
  position: absolute;
  right: 32px;
  bottom: 110px;
  width: 300px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.35s, transform 0.35s;
}
.staple-card.show { opacity: 1; transform: none; }
.staple-card .t { font-family: var(--fabriko-mono); color: var(--fabriko-hot-strong); font-size: 13px; letter-spacing: 0.06em; }
.staple-card .d { display: block; margin: 8px 0 4px; color: var(--fabriko-text); font-weight: 600; }
.staple-card .m { display: block; color: var(--fabriko-dim); font-size: 13.5px; line-height: 1.5; }
.staple-card button {
  margin-top: 12px;
  background: none;
  border: 1px solid var(--fabriko-line);
  color: var(--fabriko-dim);
  border-radius: 8px;
  padding: 6px 14px;
  cursor: pointer;
}
.staple-card button:hover { color: var(--fabriko-text); border-color: var(--fabriko-hot); }

/* ── HUD-режиссёра ─────────────────────────────────────────────────────── */

.hud {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  font-family: var(--fabriko-mono);
  opacity: 0;
  transition: opacity 0.6s 0.2s;
}
body.orbit-live .hud { opacity: 1; }

.hud-top {
  position: absolute;
  top: calc(var(--header-h, 72px) + 14px);
  left: 24px;
  right: 24px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
}

.hud-station {
  color: var(--fabriko-hot-strong);
  font-size: 12.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  min-height: 18px;
}
.hud-kicker {
  display: block;
  color: var(--fabriko-dim);
  font-size: 10px;
  letter-spacing: 0.22em;
  margin-bottom: 6px;
}

.hud-coords {
  color: var(--fabriko-cold);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  background: rgba(14, 16, 19, 0.55);
  border: 1px solid var(--fabriko-line);
  padding: 5px 10px;
  border-radius: 8px;
}

.hud-snd {
  pointer-events: auto;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(14, 16, 19, 0.55);
  border: 1px solid var(--fabriko-line);
  color: var(--fabriko-dim);
  border-radius: 8px;
  padding: 5px 10px;
  font-family: var(--fabriko-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
}
.hud-snd b { font-weight: 600; color: inherit; }
.hud-snd i {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #3a3f47;
  transition: background 0.2s, box-shadow 0.2s;
}
.hud-snd.on i { background: var(--fabriko-hot); box-shadow: 0 0 10px rgba(217, 142, 74, 0.8); }

.hud-bottom {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 22px;
  display: flex;
  align-items: center;
  gap: 18px;
}

.hud-count {
  color: var(--fabriko-dim);
  font-size: 11.5px;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

.hud-rail {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: auto;
}
.hud-node {
  appearance: none;
  background: none;
  border: none;
  padding: 8px 2px;
  cursor: pointer;
  position: relative;
  flex: 1;
  max-width: 56px;
}
.hud-node::before {
  content: "";
  display: block;
  height: 3px;
  border-radius: 2px;
  background: rgba(233, 224, 209, 0.14);
  transition: background 0.3s, box-shadow 0.3s;
}
.hud-node:hover::before { background: rgba(233, 224, 209, 0.35); }
.hud-node.active::before { background: var(--fabriko-hot); box-shadow: 0 0 12px rgba(217, 142, 74, 0.7); }
.hud-node.passed::before { background: rgba(217, 142, 74, 0.45); }

.hud-bar-wrap {
  flex: 3.2;
  height: 3px;
  border-radius: 2px;
  background: rgba(233, 224, 209, 0.10);
  overflow: hidden;
}
.hud-bar {
  display: block;
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--fabriko-hot), var(--fabriko-hot-strong));
  box-shadow: 0 0 12px rgba(217, 142, 74, 0.6);
}

/* ── студия материалов ─────────────────────────────────────────────────── */

.st-studio .panel-dock { display: flex; justify-content: flex-end; }
.studio-panel {
  width: min(400px, 92vw);
  max-height: calc(100vh - 190px);
  overflow: auto;
}
.studio-panel .display { font-size: 22px; margin-bottom: 6px; }
.studio-panel .lead { font-size: 13.5px; color: var(--fabriko-dim); margin-bottom: 14px; }

.decor-wheel {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 7px;
  margin: 12px 0;
}
/* ПОРУЧЕНИЕ владельца 05.11 (мини-проход, п.4): grace-период сразу после
   появления панели — колесо в состоянии «пробуждения»: чипы приглушены,
   курсор wait; реальные клики в это окно декор не меняют (js/orbit-ui.js,
   capture-фаза, 900 мс). Появление панели становится предсказуемым: сначала
   «пробуждение», потом выбор. */
.decor-wheel.is-arming { opacity: 0.55; }
.decor-wheel.is-arming .decor-swatch { cursor: progress; }
.decor-swatch {
  appearance: none;
  border: 1px solid rgba(233, 224, 209, 0.16);
  border-radius: 8px;
  aspect-ratio: 1;
  cursor: pointer;
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.14), rgba(0, 0, 0, 0.22)),
    var(--sw, #888);
  transition: transform 0.16s, box-shadow 0.16s, border-color 0.16s;
  padding: 0;
}
.decor-swatch:hover { transform: translateY(-2px) scale(1.06); }
.decor-swatch.active {
  border-color: var(--fabriko-hot);
  box-shadow: 0 0 0 2px rgba(217, 142, 74, 0.4), 0 4px 14px rgba(217, 142, 74, 0.25);
}
.decor-swatch:focus-visible { outline: 2px solid var(--fabriko-cold); outline-offset: 1px; }

.decor-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  border-top: 1px solid var(--fabriko-line);
  padding-top: 12px;
}
.decor-name { font-weight: 700; color: var(--fabriko-text); }
.decor-price { font-family: var(--fabriko-mono); font-size: 11.5px; color: var(--fabriko-cold); }

.studio-est {
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px dashed rgba(217, 142, 74, 0.4);
  border-radius: 12px;
}
.studio-est .k { display: block; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--fabriko-dim); }
.studio-est .v { font-size: 21px; font-weight: 700; color: var(--fabriko-text); }
.studio-est .delta { margin-left: 10px; font-size: 12.5px; font-family: var(--fabriko-mono); }
.studio-est .delta.up { color: #d86a5c; }
.studio-est .delta.down { color: #9dc08b; }

/* ── разбор-лаб ────────────────────────────────────────────────────────── */

.st-explode .panel-dock { display: flex; align-items: flex-end; }
.explode-panel { width: min(380px, 92vw); }
.explode-panel .display { font-size: 22px; margin-bottom: 6px; }
.explode-panel .lead { font-size: 13.5px; color: var(--fabriko-dim); }
.explode-name { font-family: var(--fabriko-mono); color: var(--fabriko-hot-strong); font-size: 13px; }
.explode-dims { display: block; font-family: var(--fabriko-mono); font-size: 15px; color: var(--fabriko-text); margin: 4px 0 12px; }

.explode-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
.explode-actions select {
  background: var(--fabriko-bg-2);
  color: var(--fabriko-text);
  border: 1px solid var(--fabriko-line);
  border-radius: 10px;
  padding: 8px 10px;
  font-family: inherit;
  max-width: 100%;
}
.btn-hot {
  background: linear-gradient(180deg, var(--fabriko-hot-strong), var(--fabriko-hot));
  color: #241407;
  border: none;
  border-radius: 12px;
  padding: 10px 18px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.15s, box-shadow 0.15s;
}
.btn-hot:hover { transform: translateY(-1px); box-shadow: 0 8px 22px rgba(217, 142, 74, 0.35); }
.btn-ghosty {
  background: none;
  color: var(--fabriko-dim);
  border: 1px solid var(--fabriko-line);
  border-radius: 12px;
  padding: 10px 16px;
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}
.btn-ghosty:hover { color: var(--fabriko-text); border-color: var(--fabriko-hot); }

.explode-job { font-size: 12.5px; color: var(--fabriko-dim); line-height: 1.5; display: block; }
.explode-hint { margin-top: 10px; font-size: 11px; color: var(--fabriko-dim); letter-spacing: 0.06em; }

/* ── раскрой ───────────────────────────────────────────────────────────── */

.st-cut .panel-dock { display: flex; justify-content: center; }
/* ПОРУЧЕНИЕ владельца 08.11 (жалоба №1, фикс 4): «слева над панелью серое
   размытое пятно». Диагноз (qa/probe-owner3-confirm.cjs, кадры 6→7): пятно —
   не подложка/видео/анимация, а 3D-сцена за ПОЛУПРОЗРАЧНОЙ панелью: ярко
   освещённая капитоне-стена (тема 'chocolate', src/hero/hero-scene.js:2121 —
   единая стена по решению владельца 06.11) просвечивает через
   --fabriko-panel rgba(18,21,26,0.82) + backdrop-blur(10px) и читается как
   серый размазанный массив. Убирается ЛОКАЛЬНО на этой панели: почти
   непрозрачная подложка + глубокий блюр — стекло, бордер, тень и радиус
   карточки сохранены, сцена больше не «мажет» сквозь панель. Другие станции
   не тронуты: за их карточками кухня/цех читаются как замысел. */
.cutgame-panel {
  width: min(1060px, 94vw); max-height: calc(100vh - 170px); overflow: auto;
  background: rgba(16, 19, 24, 0.94);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
}
/* ── LDSP-VIDBG (смена плана владельца 08.11): живой луп производства ЛДСП —
   призрачный фон ПАНЕЛИ раскроя, не стены 3D-сцены. Слои: .cut-vidbg
   (object-fit:cover, весь фон панели) → .cut-vidbg-shade (тёмный шоколадный
   градиент, «призрак» ~30-45% видимости: ярче к центру, глубже к низу) →
   контент панели (z-index:2 — заголовок, карта, выноски, метрики читаются
   как раньше). Видео pointer-events:none — drag деталей и скролл панели не
   задет; overflow:auto обрезает слои по радиусу карточки; под скроллбаром
   слои не заходят (padding-box). Play/pause — js/cut-game.js (IO +
   visibilitychange; пауза вне вьюпорта, на скрытой вкладке, в perf-eco и
   при prefers-reduced-motion — там честный постер-кадр). */
.cutgame-panel { position: relative; }
.cut-vidbg, .cut-vidbg-shade {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
}
/* ГРЕЙД ВЛАДЕЛЬЦА 08.11 («в светлые моменты лупа панель не то»): видео гасим
   в бренд-шоколад — brightness 0.5 + сатурация вниз + сепия-тинт; ЛЮБОЙ кадр
   лупа (включая светлый дуб крупным планом) остаётся тёмной призрачной
   фактурой, панель никогда не светлеет. */
.cut-vidbg { z-index: 0; object-fit: cover; filter: brightness(0.5) saturate(0.62) contrast(1.06) sepia(0.18); }
.cut-vidbg-shade {
  z-index: 1;
  background: linear-gradient(180deg,
    rgba(13, 14, 18, 0.68) 0%,
    rgba(24, 14, 8, 0.6) 42%,
    rgba(11, 12, 15, 0.72) 100%);
}
.cutgame-panel > :not(.cut-vidbg):not(.cut-vidbg-shade) { position: relative; z-index: 2; }
/* Подложка зоны карты: svg-лист почти прозрачен (cg-sheet 0.03, клетки 0.16) —
   без неё видео просвечивало бы сквозь карту на ~97% и подписи деталей
   сливались с движущимися кадрами. Тёмная подложка .cut-viewport гасит видео
   под картой до ~20% (поверх общего градиента), карта и «2440/1830» читаются
   как раньше, фактура остаётся призрачной. */
.cutgame-panel .cut-viewport { background: rgba(14, 16, 20, 0.68); border-radius: 8px; }
/* Нижняя полоса метрик — своя тёмная подложка (как у карты): полоса идёт по
   самому яркому нижнему краю градиента, видео под ней гасится до ~15% —
   цифры/кнопки читаются при любом кадре лупа (замер qa/shoot-vidbg.cjs). */
.cutgame-panel .cut-meta { background: rgba(11, 12, 15, 0.68); border-radius: 8px; }
.cut-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.cut-title { font-family: var(--fabriko-mono); font-size: 13px; color: var(--fabriko-text); letter-spacing: 0.02em; }
.cut-actions { display: flex; gap: 10px; }

/* ПОЛИРОЛ-2 (мокап 6-raskroy.png): em-акцент заголовка РАСКРОЙ сдвинут к
   тёплому мокапному золоту. Сэмплы заголовка мокапа (пиксельный разбор
   6-raskroy.png): средний #c6a86a, верхний квартиль #d8bc7a; якорь спектра
   из задачи — #e0a44a (тот же тёплый латунный hue ~36°). Брендово
   последовательно (латунная семья FABRIKO), ЛОКАЛЬНО для станции РАСКРОЙ:
   остальные станции и hero остаются на --brass-strong (landing.css h1/h2 em). */
.st-cut .cutgame-panel h2.display em { color: #e0a44a; }
/* ПОЛИРОЛ-2: заголовок панели РАСКРОЯ компактнее общестоционного .display
   (54px на 1366 давал перенос на 2 строки ≈ 130px) — на 1366×900 одна
   строка ~48px; низ листа + story + метрики с кнопками влезают в первый
   кадр стадии «Зачем» без доверска. Станции explode/studio уже на 22px. */
.cutgame-panel .display { font-size: clamp(26px, 3vw, 40px); }

/* фикс P2 (4-й раунд): на 1920 лист 802px + метка + пояснение + статус
   не влезали в панель (метка резалась на 9px). Лист вписывается по высоте
   на ВСЕХ размерах, рамка обжимает его, всё центрировано.
   W2.3: -360 → -440 — в панели появились h2.display + p.lead (~80px),
   высота вписки листа ужата, чтобы панель не вылезала за max-height. */
/* OWNER-2 (08.11, точка 1): базовая вписка −440 не покрывала большие экраны —
   на 1920×1080 панель переполнялась (scrollH 1003 / clientH 908) и полоса
   метрик с кнопками «Оптимизировать/Разбросать» (.cut-meta — низ кадра на
   мокапе 6-raskroy.png) уходила ЗА низ панели и экрана (meta y1022–1080 при
   панели до 1029; проба owner2, qa/owner2-probe.json). Выравниваю базу
   (>1500w И >940h) на проверенный коэффициент полирола-3 −556px (media
   орб.856 для 1366): 375 (≤760 — width 100%/height auto) и ≤940h не затронуты. */
.cut-viewport { border: 1px solid var(--fabriko-line); border-radius: 12px; overflow: hidden; background: rgba(10, 12, 15, 0.6); width: fit-content; max-width: 100%; margin: 0 auto; }
.cut-svg { display: block; width: auto; height: calc(100vh - 556px); max-width: 100%; }

/* ── W2.3 (мокап 6-raskroy.png): штамп стадии «Что это» + полоса-нарратив
   стадии «Зачем». Opacity обоих ведёт js/cut-game.js по окнам стадий
   (transition сознательно нет — скраб должен быть мгновенным, как детали). */
.cg-stamp {
  fill: rgba(232, 205, 147, 0.88);
  font-family: var(--fabriko-mono);
  font-size: 42px;
  letter-spacing: 0.3em;
  opacity: 0;
  pointer-events: none;
}
.cut-story {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
  gap: 6px 10px; margin: 10px auto 0; max-width: 100%;
  font-family: var(--fabriko-mono); font-size: 12.5px; letter-spacing: 0.03em;
  color: var(--fabriko-text); text-align: center;
  opacity: 0; pointer-events: none;
}
.cutgame-panel .cut-story { flex-shrink: 0; }

.cg-sheet rect { fill: rgba(233, 224, 209, 0.03); stroke: rgba(233, 224, 209, 0.22); stroke-width: 2; }
.cg-sheet line { stroke: rgba(233, 224, 209, 0.10); stroke-width: 1; }
.cg-dim { fill: #6f7680; font-family: var(--fabriko-mono); font-size: 34px; letter-spacing: 0.08em; }

/* вето владельца 21.10: жест, начатый на детали, ловит деталь, а не скролл
   панели. touch-action: none обещан комментарием js/cut-game.js («на rect»),
   но в CSS никогда не появлялся; при этом Chromium вообще не чтит
   touch-action на SVG-элементах — дубль-страховка в js/cut-game.js
   (preventDefault на touchstart детали). Правило оставлено по спецификации
   (браузеры, где SVG touch-action работает). Поведенческая каскадность
   touch-action (пересечение по цепочке предков) накрывает rect и text.
   Фон листа и сама панель скроллятся как раньше — инвариант 7 не тронут. */
.cut-part { cursor: grab; touch-action: none; }
.cut-part.drag { cursor: grabbing; filter: drop-shadow(0 18px 26px rgba(0, 0, 0, 0.55)); }
.cut-part.drag rect { fill: rgba(217, 142, 74, 0.40); stroke-width: 3.2; }
/* пунктир честного места посадки при drag (ставит js/cut-game.js) */
.cg-drophint {
  fill: rgba(143, 183, 217, 0.10);
  stroke: var(--fabriko-cold);
  stroke-width: 3;
  stroke-dasharray: 16 12;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.cg-drophint.on { opacity: 1; }
.cut-part rect {
  fill: rgba(217, 142, 74, 0.16);
  stroke: var(--fabriko-hot);
  stroke-width: 2.4;
  transition: fill 0.2s;
}
.cut-part:hover rect { fill: rgba(217, 142, 74, 0.30); }
.cut-part:focus-visible { outline: none; }
.cut-part:focus rect { stroke: var(--fabriko-cold); stroke-width: 3.4; }
.cut-part text {
  fill: #cfc8ba;
  font-family: var(--fabriko-mono);
  font-size: 34px;
  letter-spacing: 0.04em;
  pointer-events: none;
}
/* drag не выделяет текст деталей и меток листа */
.cut-svg { user-select: none; -webkit-user-select: none; }

/* ── ITER9 «Раскрой-шоу»: скролл = прохождение реза ───────────────────────
   Золотая линия реза + след керфа + дозированный глоу (только у самой
   линии) + опилки. Вся группа pointer-events: none — скролл, drag и
   панель живут как раньше (инвариант 7 не тронут). */
.cg-cut { pointer-events: none; }
.cg-kerf { stroke: #191009; stroke-width: 4; opacity: 0.5; }            /* след 4 мм = керф, в щели карты */
.cg-glow { stroke: #e8cd93; stroke-width: 9; opacity: 0.4; filter: blur(3px); } /* глоу — хвост ~170 мм у линии */
.cg-core { stroke: #f2ddad; stroke-width: 2.6; stroke-linecap: round; }
.cg-head { fill: #ffe9b8; stroke: rgba(232, 205, 147, 0.85); stroke-width: 1.5; }
.cg-dust { fill: #3a2b1d; }                                             /* опилки — тёмные, только в тени щели */
.cg-cutline { fill: none; stroke: #e8cd93; stroke-width: 2.2; opacity: 0; } /* контур отделившейся детали */
.cg-cutshadow { fill: rgba(8, 6, 4, 0.62); opacity: 0; }                  /* тень приподнятой детали (тёмная, под деталью) */
/* тап по детали — подсветка её на листе (ITER9); :not() — не задевать
   золотой контур и тень отделившейся детали */
.cut-part.sel > rect:not(.cg-cutline):not(.cg-cutshadow) { stroke: #e8cd93; stroke-width: 3.4; fill: rgba(232, 205, 147, 0.22); }
/* выноски-пороги: стиль выносок iter 8 (.explode-callout) — точка +
   линия 1px + моно-текст на тёмной плашке; позицию/opacity пишет js. */
.cut-viewport { position: relative; }
.cut-callout {
  position: absolute;
  top: 0;
  left: 0;
  font-family: var(--fabriko-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: #e8cd93;
  white-space: nowrap;
  opacity: 0;
  will-change: transform, opacity;
  pointer-events: none;
  z-index: 3;
}
.cut-callout .c-dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #c8a24b;
  box-shadow: 0 0 0 2px rgba(200, 162, 75, 0.28);
  transform: translate(-3px, -3px);
}
.cut-callout .c-line {
  position: absolute;
  left: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(90deg, #c8a24b, rgba(200, 162, 75, 0.3));
  transform-origin: 0 50%;
}
.cut-callout .c-text {
  position: absolute;
  padding: 3px 8px;
  background: rgba(14, 16, 19, 0.82);
  border: 1px solid rgba(200, 162, 75, 0.26);
  border-radius: 6px;
  /* Читаемость r2 критика (08.11): p92 фона в боксе .c-text формировали не
     подложки, а СОБСТВЕННАЯ латунная кайма плашки (0.45 → композит ~86-90)
     и AA-кромка глифов (90-129; на 375 компакт-плашке давала p92 до 102).
     Кайма приглушена 0.45→0.26 (композит ~60), тексту дана тёмная 1px-тень:
     AA-кромка уходит вниз распределения, worst-case p92 ≤ ~70, латунь 207
     даёт ≥ 6.0 против порога 4.5. Цвет латунного текста не тронут. */
  text-shadow: 0 1px 2px rgba(10, 11, 14, 0.9);
}
/* P1 критика (раунд 2): компакт-перегенерация выносок — класс ставит
   js/cut-game.js placeCallouts() одним ретраем, когда штатный кегль не развёл
   6 плашек на плотной карте (1366×900, вьюпорт 457×346, при широких метриках
   текста — фолбэк-моно без вебшрифта). Кегль/паддинг как в r11-блоке ≤800h и
   на мобильных: −18% площади пузыря, анти-коллизия DFS возвращается
   (пересечений 0 и с метками деталей). Ставится ТОЛЬКО при неудаче первого
   прохода и держится вместе с применённой раскладкой. */
/* ВАЖНО: абсолютные значения ПО СРЕДАМ (0.85em считался бы от родителя 16px
   = 13.6px — крупнее базы; ловилось пробой р2 на 375). −15% от базы каждой
   среды: десктоп 11→9.35, ≤800h 10→8.5, мобилка 9.5→8.1. */
.cut-callouts-compact .cut-callout { font-size: 9.35px; letter-spacing: 0.02em; }
.cut-callouts-compact .cut-callout .c-text { padding: 1px 5px; border-radius: 5px; }
@media (min-width: 761px) and (max-height: 800px) {
  .cut-callouts-compact .cut-callout { font-size: 8.5px; }
}
@media (max-width: 760px) {
  .cut-callouts-compact .cut-callout { font-size: 8.1px; }
}
/* BONUS iter10 r1 (критик: вьюпорт раскроя 302×229 на 375 — текст выносок
   11px + паддинги не оставляли места анти-коллизии): мельче текст и плашка */
@media (max-width: 760px) {
  .cut-callout { font-size: 9.5px; letter-spacing: 0.02em; }
  .cut-callout .c-text { padding: 2px 6px; border-radius: 5px; }
}
@media (prefers-reduced-motion: reduce) {
  .cut-callout { transition: none; }
}

.cut-meta {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 12px;
  flex-wrap: wrap;
  font-size: 13.5px;
  /* Читаемость r2 критика (08.11): метки (Заполнение/Отходы/остаток/Деталей)
     на --fabriko-dim (luma 164) давали 4.03-4.10 против worst-case p92 фона
     65-66 (яркие выбросы лупа сквозь подложку 0.68, потолок ~90) — ниже
     порога 4.5 на всех трёх вьюпортах. Тон поднят до #e2dcd0 (luma ~220,
     светлый тёплый, бренд-крем семья) → ≥ 5.0 на потолке, ~7.4 на замере.
     Прецедент тона — landing.css:1540. Значения .cut-meta b (крем 231),
     кнопки (.btn-hot/.btn-ghosty — свои цвета) и .cut-metanote (свой
     --fabriko-dim) не задеты. */
  color: #e2dcd0;
}
.cut-meta b { color: var(--fabriko-text); }
.cut-fillmeter { flex: 1; min-width: 120px; height: 4px; border-radius: 2px; background: rgba(233, 224, 209, 0.1); overflow: hidden; }
.cut-fillmeter i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--fabriko-hot), var(--fabriko-hot-strong)); }
/* ПОЛИРОЛ-2 (мокап 6-raskroy.png): «всё в нижней панели» — кнопки в одной
   строке с метриками, прижаты вправо; компактнее, чем шапочные (шапка
   хранит только технический титул листа). На 1366×900 метрики и кнопки
   в одной зоне. */
.cut-meta .cut-actions { display: flex; gap: 8px; margin-left: auto; flex: none; }
.cut-meta .cut-actions .btn-hot,
.cut-meta .cut-actions .btn-ghosty { padding: 7px 14px; border-radius: 10px; font-size: 12.5px; }
.cut-status { font-family: var(--fabriko-mono); font-size: 11.5px; color: var(--fabriko-cold); min-height: 18px; }
/* пояснение метрик листа (P2, 3-й раунд): сумма столбцов не обязана быть 100% */
.cut-metanote { display: block; margin-top: 2px; font-size: 11.5px; color: var(--fabriko-dim); opacity: 0.85; }

/* фикс P2 критика (18.10): на 1366×768 нижняя строка карты раскроя
   (Заполнение/Отходы/остаток/Деталей) уходила за фолд — панель выше,
   чем viewport (лист 2440×1830 в пропорции 1.32 от ширины 1060px ≈ 802px).
   На коротких/узких вьюпортах: (1) строка меты под заголовком — ключевые
   цифры видны без прокрутки; (2) ДОрисано по 2-му раунду критика: лист
   вписывается по ВЫСОТЕ (высота = vh - 320px), рамка листа обжимается
   fit-content — нижний ряд деталей и строка статуса видны целиком
   (st1366_cut.png == fix_cutmeta_1366.png — одного порядка элементов было
   мало). 1920×1080 не затронут (OR-условие, всё входило и так).

   ПОЛИРОЛ-2 (мокап 6-raskroy.png + задача стадии «Зачем»): порядок
   flex-колонки переведён на мокапную компоновку «всё в нижней панели» —
   лист → нарратив-полоса → строка метрик С КНОПКАМИ; высота вписки листа
   ужата (-480 → -540), чтобы на 1366×900 НИЗ листа (выноска
   «Остаток 4,4%»), полоса .cut-story и метрики с кнопками целиком
   попадали в первый кадр стадии p≈0.85 без доверска (замер до:
   viewport bottom 936 / story 942 при vh 900 — overflow панели 161px). */
@media (max-width: 1500px), (max-height: 940px) {
  .cutgame-panel { display: flex; flex-direction: column; }
  /* фикс P1 (5-й раунд): flex-сжатие вьюпорта клипало лист на 57px
     (svg 428 в вьюпорте 371) — детям панели запрещено сжиматься,
     высота листа = остаток панели за вычетом хрома (176px) */
  .cutgame-panel .cut-head,
  .cutgame-panel .cut-meta,
  .cutgame-panel .cut-metanote,
  .cutgame-panel .cut-viewport,
  .cutgame-panel .cut-story,
  .cutgame-panel .cut-status { flex-shrink: 0; }
  .cutgame-panel .cut-head { order: 1; }
  .cutgame-panel .cut-viewport { order: 2; width: fit-content; max-width: 100%; margin: 0 auto; }
  .cutgame-panel .cut-story { order: 3; margin: 6px auto 0; }
  .cutgame-panel .cut-meta { order: 4; margin-top: 8px; }
  .cutgame-panel .cut-metanote { order: 5; margin: 2px 0 0; }
  .cutgame-panel .cut-status { order: 6; margin-top: 6px; }
  /* W2.3: -400 → -480 — h2.display + p.lead + cut-story ужали вписку листа;
     ПОЛИРОЛ-2: -480 → -540 — в нижней зоне панели появились кнопки
     (мета стала выше), низ листа + story должны быть в первом кадре;
     ПОЛИРОЛ-3 (хвост волны 2): после -540 панель стадии «Зачем» всё ещё
     давала внутренний overflow 11px (diag-stage85-polish2.cjs: panel
     scrollHeight 739 / clientHeight 728 при 1366×900; константа — та же 11
     на 1366×768, overflow не зависит от vh внутри этого media) — нижние
     11px контента (статус + нижний паддинг) вылезали за панель
     (overflow: auto орбит.css:622). -540 → -556: минус 16px (11 + 5px
     запаса) на ВСЕХ высотах media, лист меньше на 4.4% — порядок и
     композиция полирола-2 не тронуты. */
  .cutgame-panel .cut-svg { width: auto; height: calc(100vh - 556px); max-width: 100%; }
}
/* мобайл: лист обратно по ширине (высота-вписка на узком экране даёт
   пустые поля внутри рамки), панель скроллится штатно */
@media (max-width: 760px) {
  .cutgame-panel .cut-svg { width: 100%; height: auto; }
  .cutgame-panel .cut-viewport { width: auto; }
}

/* P1 критик р11 (1366-пересечения выносок, раунд 1 из 4): на 1366 при
   РЕАЛЬНОЙ высоте браузера (~620-660 CSS px) карте доставалось
   calc(100vh - 556px) = 84px — анти-коллизии негде было развести плашки,
   выноски пересекали метки деталей (замер qa/probe-owner3-r1.cjs: 13
   проблемных позиций на 1366×640; на 1366×768/900 — чисто). Починка по
   предложению критика — «сжатие хрома + пол высоты карты»:
   • хром панели ужимается (паддинги, h2, lead, отступы рядов);
   • карте — пол 240px (max(240px, 100vh - 470px)): при 640 карта 240px
     вместо 84; панель при этом слегка скроллится (overflow:auto —
     орбит.css:622, штатное поведение);
   • плашки компактнее (10px, паддинг 2×6) — плотнее упаковка;
   порог media 800px: на 768 карте 298px вместо 212 (пояса слотов
   помещаются с запасом). 1366×900 и 1920 не затронуты (гейт стадий гоняется на 900). */
@media (min-width: 761px) and (max-height: 800px) {
  .cutgame-panel { padding: 14px 18px; }
  .cutgame-panel h2.display { font-size: clamp(24px, 3vw, 36px); }
  .cutgame-panel .lead { margin-top: 8px; font-size: 14.5px; }
  .cutgame-panel .cut-head { margin-bottom: 6px; }
  .cutgame-panel .cut-story { margin-top: 5px; font-size: 11.5px; }
  .cutgame-panel .cut-meta { margin-top: 6px; gap: 10px; }
  .cutgame-panel .cut-svg { width: auto; height: max(240px, calc(100vh - 470px)); }
  .cut-callout { font-size: 10px; letter-spacing: 0.02em; }
  .cut-callout .c-text { padding: 2px 6px; border-radius: 5px; }
}

/* ── смета-принтер ─────────────────────────────────────────────────────── */

.st-estimate .panel-dock { display: flex; justify-content: flex-end; }
.est-panel { width: min(430px, 92vw); }
.est-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; color: var(--fabriko-text); font-weight: 600; }
/* раунд 5: symbol без fill/stroke рисовался чёрным блоком (P2 критика №5) */
.est-head svg { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; color: var(--fabriko-hot-strong); }
.est-lines { list-style: none; margin: 0; padding: 0; }
.est-line {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 10px;
  border-radius: 8px;
  font-size: 13.5px;
  color: var(--fabriko-dim);
  opacity: 0;
  transform: translateX(10px);
  cursor: pointer;
  transition: opacity 0.4s, transform 0.4s, background 0.2s;
}
.est-line.on { opacity: 1; transform: none; }
.est-line:hover, .est-line.picked { background: rgba(217, 142, 74, 0.10); color: var(--fabriko-text); }
.est-line .sum { font-family: var(--fabriko-mono); color: var(--fabriko-cold); }
/* себестоимость = сумма строк; «Итого» = она же × коэффициент (обе видны) */
.est-cost-row {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  margin-bottom: 12px; /* P2 r1: зазор под штамп — верх штампа не достаёт до цифр себестоимости */
  padding-top: 10px;
  font-size: 12.5px;
  color: var(--fabriko-dim);
  border-top: 1px dashed var(--fabriko-line);
}
.est-cost-row .v { font-family: var(--fabriko-mono); opacity: 0; transition: opacity 0.4s; }
.est-cost-row .v.on { opacity: 1; }
.est-coeff {
  margin-left: 8px;
  font-family: var(--fabriko-mono);
  font-size: 11px;
  font-weight: 400;
  color: var(--fabriko-cold);
  border: 1px solid rgba(143, 183, 217, 0.35);
  border-radius: 6px;
  padding: 2px 7px;
  white-space: nowrap;
}
.est-total-row {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid var(--fabriko-line);
  margin-top: 10px;
  padding-top: 12px;
  font-weight: 700;
  color: var(--fabriko-text);
}
.est-total-row .v { font-family: var(--fabriko-mono); color: var(--fabriko-hot-strong); opacity: 0; transition: opacity 0.5s; white-space: nowrap; }
.est-total-row .v.on { opacity: 1; }
.est-note { display: block; margin-top: 10px; font-size: 11.5px; color: var(--fabriko-dim); opacity: 0.8; }
.est-hint { font-size: 11px; color: var(--fabriko-cold); letter-spacing: 0.06em; }

/* ── ITER10 «Смета-принтер»: чек-лента, штамп, золотые нити ────────────── */

/* моноширинные цифры чека: количество — той же сеткой, что суммы
   (ровная сетка референса; имя строки — текстовый шрифт, как было) */
.est-line .qty { font-family: var(--fabriko-mono); font-size: 12px; opacity: 0.85; flex: none; }

/* золотой штамп «×1,85 демо-наценка»: припечатывается с ударом на пороге
   скраба (класс .on вешает js на EST_STAMP_AT). Только transform/opacity:
   анимация scale+rotate, никакого layout. Текст пишет js из данных
   (коэффициент × словарь est.coeff). Живёт на строке «Итого» — перекрывает
   её угол как настоящий штамп. P2 r1 (критик: на top:-17px штамп накрывал
   значение себестоимости «361 842 сум» на всех ВП): зазор cost→total
   увеличен до 12px, штамп опущен (top:-10px) — верх штампа не достаёт до
   цифр себестоимости, хинт и пометка «суммы условные» свободны. */
.est-stamp {
  position: absolute;
  right: -12px;
  top: -10px;
  padding: 4px 11px;
  font-family: var(--fabriko-mono);
  font-size: 12.5px;
  letter-spacing: 0.05em;
  color: #d9a05b;
  border: 2px solid rgba(217, 160, 91, 0.85);
  border-radius: 8px;
  background: rgba(14, 16, 19, 0.55);
  transform: rotate(var(--stamp-tilt, -7deg)) scale(1);
  opacity: 0;
  pointer-events: none;
  white-space: nowrap;
  will-change: transform, opacity;
}
/* P2 (поручение владельца 04.11, штамп ×1,85 на 375): на узких ВП панель
   занимает весь экран — штамп 12.5px на right:-12px перекрывал «Итого по
   фрагменту»/цифры и стартовым scale(2.1) вылетал за правый край в момент
   удара. Замер на 360 (порученные рецепты проверены честным семплированием
   повернутого прямоугольника): штамп 154×24 при 11px НЕ помещается в зазор
   cost→total (12px) ни при top:-10, ни при top:-16 — «Итого»/цифры/цифры
   себестоимости накрыты в любом варианте. Поэтому:
   • 481–760px: кегль 11px, right:-6px, кламп стартового скейла 1.3 через
     --stamp-hit-from (вся анимация внутри ВП: при 760 right bbox 754 ≤ 760);
   • ≤480px (телефоны, напр. 375): оверлей-штамп display:none — коэффициент
     в кадре несёт инлайн-чип .est-coeff (данные те же, текст из словаря
     est.coeff), opacity возвращён !important против инлайна js. Накрытий
     «Итого по фрагменту»/цифр — ноль, правый край свободен.
     Десктоп (>760) не тронут: панель пристыкована слева, старт 2.1 не
     достаёт до правого края ВП. */
.est-stamp {
  --stamp-hit-from: 2.1;
  --stamp-tilt: -7deg;      /* осевший штамп */
  --stamp-tilt-hit: -13deg; /* кадр удара 0% */
  --stamp-tilt-mid: -6deg;  /* кадр 62% (осадка) */
}
/* P2 фикс-раунд 1 (критик 04.11, штамп-1366): осевший штамп нижним краем
   (BL-угол при −7°) заходил в верхнюю половину значения «669 408 сум»
   (замер: край на +9.6px внутрь value на 1366). Фактическая полоса на 1366:
   низ cost-цифр «361 842 сум» rowTop−12 … верх value rowTop+13 = 25px —
   в неё должен лечь bbox повернутого штампа целиком (поднять якорь выше
   нельзя — cost-цифры). ≤1499px: кегль 10.5px, line-height 1.05
   (h0 27.5→19px), паддинг 2/8, tilt −1° (bbox ≈ 21.5px), top:-10.5px —
   bbox 8436.4..8457.4 внутри полосы 8435.7..8460.7 (зазоры 0.7/3.3px),
   семплирование повернутого прямоугольника на 1366 с РЕАЛЬНЫМИ суммами
   «361 842 сум»/«669 408 сум»: пересечений 0. Осевший штамп почти прямой —
   «припечатан» без крена на 1366; 1920 (принятая композиция, tilt −7°)
   и 375 (штамп скрыт) не тронуты. */
@media (max-width: 1499px) {
  .est-stamp {
    font-size: 10.5px;
    line-height: 1.05;
    padding: 2px 8px;
    top: -10.5px;
    right: -10px;
    --stamp-tilt: -1deg;
    --stamp-tilt-hit: -8deg;
    --stamp-tilt-mid: -0.5deg;
  }
}
@media (max-width: 760px) {
  .est-stamp {
    font-size: 11px;
    right: -6px;
    --stamp-hit-from: 1.3;
  }
}
@media (max-width: 480px) {
  .est-stamp { display: none; }
  .est-coeff { opacity: 1 !important; }
}
.est-total-row { position: relative; } /* якорь абсолютного штампа */
/* P2 r1 (критик: дубль смысла — чип ×1,85 у «Итого» и штамп видны вместе):
   при штампе чип гасит js (opacity 0) — один носитель коэффициента в кадре.
   P3 фикс-раунда 1 (критик: 2-3 кадра после удара чип ещё виден — 0.3s фейд
   дольше разгона штампа): 0.3s → 0.15s, транзиентный дубль схлопывается. */
.est-coeff { transition: opacity 0.15s; }
.est-stamp.on { animation: est-stamp-hit 0.42s cubic-bezier(0.2, 1.4, 0.3, 1) both; }
@keyframes est-stamp-hit {
  /* старт/углы через var: клампятся на ≤1499/≤760px (--stamp-hit-from,
     --stamp-tilt-*), десктоп ≥1500 сохраняет прежний размах 2.1 / −13° */
  0% { transform: rotate(var(--stamp-tilt-hit, -13deg)) scale(var(--stamp-hit-from, 2.1)); opacity: 0; }
  45% { opacity: 1; }
  62% { transform: rotate(var(--stamp-tilt-mid, -6deg)) scale(0.93); opacity: 1; }
  100% { transform: rotate(var(--stamp-tilt, -7deg)) scale(1); opacity: 1; }
}

/* золотая нить-выноска строки сметы: рисует сцена (hero-scene.js
   updateLabels), слой [data-explode-labels] — под панелью станции
   (.orbit-track выше .orbit-stage). Корень — точка на строке чека,
   линия — 100px заготовка (длина = scaleX, без layout в кадре),
   конец — кольцо на детали в цеху. */
.est-thread {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  z-index: 3;
}
.est-thread .t-dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #c8a24b;
  box-shadow: 0 0 0 2px rgba(200, 162, 75, 0.3);
  transform: translate(-3px, -3px);
}
.est-thread .t-line {
  position: absolute;
  left: 0;
  top: 0;
  width: 100px;
  height: 1.5px;
  background: linear-gradient(90deg, rgba(217, 160, 91, 0.95), rgba(217, 160, 91, 0.45));
  transform-origin: 0 50%;
  will-change: transform;
}
.est-thread .t-end {
  position: absolute;
  left: 0;
  top: 0;
  width: 9px;
  height: 9px;
  border: 1.5px solid #d9a05b;
  border-radius: 50%;
  background: rgba(217, 160, 91, 0.22);
  transform: translate(-4.5px, -4.5px);
}

/* печать чек-ленты и штамп — мгновенно без анимаций (ТЗ п.5); видимость
   штампа в статике ведёт класс .on (js), не CSS */
@media (prefers-reduced-motion: reduce) {
  .est-line { transition: none; }
  .est-stamp, .est-stamp.on { animation: none; }
  .est-thread { transition: none; }
}

/* ── конструктор и пилот: переиспользуют классы landing.css ────────────── */

/* раунд 5: мок конструктора выше контентной зоны пина — на 1366 верх уезжал
   под шапку (y=63.9 при шапке 72), на 1920 низ уходил под HUD (1054.9 при
   1031.6). Карточка тянется по доступной высоте, рамка мока сжимается. */
.st-ctor .panel-card { padding: 14px; display: flex; flex-direction: column; height: calc(100dvh - 186px); }
.st-ctor .panel-card .browser { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.st-ctor .browser-frame { flex: 1 1 auto; min-height: 0; height: auto; }
.st-ctor .browser { box-shadow: none; }
.st-ctor .section-head { display: none; }

/* ── ПОРУЧЕНИЕ владельца 08.11 (точка 4): HUD клиентской прогулки ─────────
   Станция «Конструктор» читается как место, где клиенту кидают ссылку и он
   ходит как в игре (спека МОДАЛ 2 «Ходить внутри комнаты»; фразы HUD — из
   реализации walk-режима qa/sandbox/walk-v1). HUD включается классом
   .is-walk на .browser (js/landing.js, после «Смотреть как клиент») —
   поверх живого интерьера iframe; на тизере-постере его нет (честность
   офлайна: статичный постер не «ходит»). Плашки-подсказки (WASD на
   десктопе / джойстик на таче — текст выбирает landing.js по matchMedia).
   pointer-events: none — управление идёт в iframe движка.
   ТОЧКА ВЛАДЕЛЬЦА 09.11: CS-прицел по центру убран («это же не шутер»)
   — вместо него НИЧЕГО: настоящий HUD клиентской ссылки (viewer.js)
   ретикля в центре не имеет; станции достаточно бейджа и подсказки. */
.ctor-walk-hud { display: none; }
.browser.is-walk .ctor-walk-hud { display: block; position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.ctor-walk-hud .cwh-badge,
.ctor-walk-hud .cwh-hint {
  position: absolute; left: 50%; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--fabriko-mono, ui-monospace, monospace);
  color: rgba(232, 198, 140, 0.92);
  background: rgba(14, 16, 19, 0.66);
  border: 1px solid rgba(217, 142, 74, 0.35);
  border-radius: 999px; padding: 7px 14px;
  letter-spacing: 0.05em; white-space: nowrap;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
.ctor-walk-hud .cwh-badge { top: 14px; font-size: 11px; }
.ctor-walk-hud .cwh-badge svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 1.8; }
/* подсказка поднята над зоной тулбара демо-движка (~90px снизу): на
   старт-экране движка плашка не наезжает на «Отправить клиенту» (замер
   qa/shots/owner3/16 → перегон 17); в клиентской прогулке (тулбара нет)
   читается как нижний HUD игры. */
.ctor-walk-hud .cwh-hint { bottom: 96px; font-size: 12px; }
@media (max-width: 760px) {
  .ctor-walk-hud .cwh-hint { font-size: 11px; max-width: calc(100% - 24px); white-space: normal; text-align: center; border-radius: 14px; }
}
.st-ctor .ctor-note, .st-ctor .ctor-offline { display: none; }

.st-pilot .panel { position: relative; }
.confetti-host { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.confetti-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

.st-pilot .cta-card { background: rgba(18, 21, 26, 0.86); }
/* раунд 9: на «Пилоте» координату показывает ЧПУ-карточка; HUD-координаты
   в этот момент дублируют её в другой системе — убираем дубль.
   ПОРУЧЕНИЕ владельца 08.11 (точка 2г): источник «штампа-подписи габаритов
   “Х 4300…”» над панелями — ЧИП МАШИННЫХ КООРДИНАТ .hud-coords
   (js/orbit-ui.js:399-406): «X:» + поза камеры-крана на рельсе в «мм»
   (pose.x*1000, src/core/camera-rail.js:18 — ключ x:4.3 м → ровно «X:4300»),
   читался владельцем как сломанный штамп габаритов. ОТЗЕРКАЛИВАНИЕ не
   воспроизведено: ни один transform лендинга (orbit.css/landing.css/
   effects.js/orbit-ui.js/pilot-cnc.js) не вращает/не отражает текст; чип в
   DOM горизонтален (кадры qa/shots/owner3/3-pilot-1920.png). Починка по
   смыслу жалобы: машинные координаты — вкус «стойки оператора» ТОЛЬКО на
   стартовой станции; на всех следующих станциях чип скрыт (раньше скрывался
   только на pilot — orbit.css:1129). */
body[data-station]:not([data-station="hero-assembly"]) .hud-coords { display: none; }

/* ── пост-orbit (обычный поток после кадра) ────────────────────────────── */

.after-orbit {
  position: relative;
  z-index: 2;
  background: var(--bg);
}

/* ── интро-гейт ────────────────────────────────────────────────────────── */

/* ГЛАВА 2 (приказ 21.10 «слишком тёмная… дофамин и вау», эталон тона —
   Терра EVO v3: тёмный кадр, который СВЕТИТСЯ изнутри). Гейт больше не
   глухой холодный колпак (--fabriko-bg #0e1013 давал luma 0.07 — «чёрный
   экран» при тёплом шоуруме 0.22). Теперь это тёплая карамельная вуаль:
   • живая сцена читается за лого с первой отрисовки (вуаль полупрозрачна);
   • пока канвас ещё не рисует, тёплая «заглушка с прогрессом» (.gate::before)
     сама держит свет — лоадер никогда не чёрный экран;
   • .gate::after — дыхательный тёплый отсвет («сцена жива»), только
     compositor-анимация opacity/transform, без backdrop-filter (перф). */
.gate {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  overflow: hidden;
  background:
    radial-gradient(1150px 620px at 68% 16%, rgba(255, 196, 128, 0.28), transparent 62%),
    radial-gradient(950px 540px at 16% 84%, rgba(217, 142, 74, 0.18), transparent 64%),
    linear-gradient(180deg, rgba(64, 42, 25, 0.40), rgba(50, 33, 20, 0.38) 46%, rgba(38, 25, 15, 0.44));
  transition: opacity 0.85s ease, visibility 0.85s;
}
/* тёплая заглушка под вуалью: пока канвас героя не начал рисовать, она
   полностью прячет контент страницы под гейтом (двойного UI в кадре нет) —
   лоадер никогда не чёрный экран. Тает (0.7s), когда js/landing.js ставит
   body.gate-live по факту отрисованных кадров сцены — дальше за лого
   читается живая тёплая сцена (вуаль полупрозрачна). */
.gate::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(1400px 780px at 50% 32%, rgba(255, 208, 148, 0.22), transparent 66%),
    linear-gradient(180deg, #46311d, #3a2818 46%, #2c1e13);
  opacity: 1;
  transition: opacity 0.7s ease;
  pointer-events: none;
}
body.gate-live .gate::before { opacity: 0; }
/* дыхательный тёплый отсвет над лого (сторона key-света сцены) */
.gate::after {
  content: "";
  position: absolute;
  inset: -12%;
  z-index: -1;
  background: radial-gradient(46% 36% at 63% 28%, rgba(255, 186, 112, 0.15), transparent 70%);
  animation: gateBreathe 5.6s ease-in-out infinite;
  pointer-events: none;
}
@keyframes gateBreathe {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.05); }
}
.gate[hidden] { display: flex; }
.gate.gate-out { opacity: 0; visibility: hidden; pointer-events: none; }

.gate-logo { width: min(320px, 70vw); height: auto; opacity: 0.96; animation: gateGlow 3.2s ease-in-out infinite; }

/* ITER8 (P2 семёрки): шумовое зерно живой сцены за полупрозрачной вуалью
   гейта не пачкает вордмарк FABRIKO — тёмное гало-«паспарту» вокруг знака
   глушит фон (прозрачность сцены под лого читается ровной). */
.gate-logo { filter: drop-shadow(0 2px 16px rgba(22, 13, 6, 0.9)) drop-shadow(0 0 44px rgba(26, 16, 8, 0.65)); }
/* волна 6: новый знак F — заливка, не штрих; проявляется фейдом (штрих-драу
   pathLength на него не действует — у пути нет stroke) */
.gate-logo .gate-mark { animation: gateMarkIn 0.9s ease-out 0.1s both; }
@keyframes gateMarkIn { from { opacity: 0; } to { opacity: 1; } }
/* GAP (лоадер уровня эталона edolus): знак рисуется проходом «фрезы» —
   каждый штрих pathLength=1, dasharray 1, смещение 1 → 0 со стаггером */
.gate-logo [pathLength] {
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  animation: gateDraw 1.1s ease-out forwards;
  animation-delay: calc(0.15s + var(--i, 0) * 0.11s);
}
@keyframes gateDraw { to { stroke-dashoffset: 0; } }
.gate-logo-sub { opacity: 0; animation: gateSub 0.9s ease forwards 1.5s; }
@keyframes gateSub { to { opacity: 1; } }
@keyframes gateGlow {
  0%, 100% { filter: drop-shadow(0 0 16px rgba(217, 142, 74, 0.2)); }
  50% { filter: drop-shadow(0 0 30px rgba(217, 142, 74, 0.45)); }
}

.gate-meter {
  width: min(420px, 76vw);
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--fabriko-mono);
}
.gate-meter-track { flex: 1; height: 3px; border-radius: 2px; background: rgba(233, 224, 209, 0.18); overflow: hidden; }
.gate-meter-bar { display: block; height: 100%; width: 0%; background: linear-gradient(90deg, var(--fabriko-hot), var(--fabriko-hot-strong)); box-shadow: 0 0 14px rgba(217, 142, 74, 0.55); }
.gate-pct { color: var(--fabriko-hot-strong); font-size: 13px; min-width: 44px; text-align: right; text-shadow: 0 1px 8px rgba(26, 16, 8, 0.6); }

.gate-status {
  color: var(--fabriko-dim);
  font-family: var(--fabriko-mono);
  font-size: 11.5px;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  min-height: 18px;
  /* читаемость статуса над живой сценой (вуаль полупрозрачна) */
  text-shadow: 0 1px 10px rgba(26, 16, 8, 0.65);
  /* фикс P2 (5-й раунд): длинный статус («Статичный кадр: анимации
     выключены…») обрезался на 375 */
  max-width: min(520px, 88vw);
  text-align: center;
  line-height: 1.7;
}

/* ГЛАВА 2: CTA входа — тёплая латунная кнопка (дофамин-фокус кадра),
   в неготовом состоянии — призрачный контур той же формы */
.gate-enter {
  appearance: none;
  border: 1px solid rgba(255, 214, 160, 0.5);
  background: linear-gradient(180deg, rgba(237, 164, 95, 0.16), rgba(217, 142, 74, 0.10));
  color: var(--fabriko-hot-strong);
  font-family: "Unbounded", var(--font-display);
  font-size: 15px;
  letter-spacing: 0.14em;
  padding: 15px 34px;
  border-radius: 999px;
  cursor: pointer;
  opacity: 0.35;
  transition: opacity 0.3s, background 0.3s, box-shadow 0.3s, transform 0.15s;
}
.gate-enter.is-ready {
  opacity: 1;
  border-color: rgba(255, 226, 180, 0.8);
  background: linear-gradient(180deg, #f0b072, #d98e4a 58%, #c07a38);
  color: var(--ink-on-brass, #241407);
  box-shadow:
    0 14px 44px rgba(217, 142, 74, 0.38),
    inset 0 2px 0 rgba(255, 240, 214, 0.4);
}
.gate-enter.is-ready:hover {
  background: linear-gradient(180deg, #f6bd85, #e39a54 58%, #c8823e);
  box-shadow:
    0 18px 56px rgba(237, 164, 95, 0.5),
    inset 0 2px 0 rgba(255, 240, 214, 0.45);
  transform: translateY(-1px);
}
.gate-enter:focus-visible { outline: 2px solid var(--fabriko-cold); outline-offset: 3px; }

/* галочка «Со звуком» (дуэль 2026-10-20: аудио-слой включается жестом
   пользователя прямо на гейте — политика автоплея уважается) */
.gate-snd {
  display: inline-flex; align-items: center; gap: 9px;
  color: var(--fabriko-dim); font-size: 12.5px; letter-spacing: 0.08em;
  text-shadow: 0 1px 8px rgba(26, 16, 8, 0.6);
  cursor: pointer; user-select: none;
}
.gate-snd input {
  appearance: none; width: 17px; height: 17px; margin: 0;
  border: 1px solid rgba(217, 142, 74, 0.6); border-radius: 4px;
  background: rgba(217, 142, 74, 0.08); cursor: pointer; position: relative;
}
.gate-snd input:checked { background: rgba(217, 142, 74, 0.32); }
.gate-snd input:checked::after {
  content: ""; position: absolute; left: 4.5px; top: 1.5px; width: 5px; height: 9px;
  border: solid var(--fabriko-hot-strong); border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.gate-snd:hover span { color: var(--fabriko-text); }

/* фикс B4: статичный дубль хинта убран из разметки — правило не нужно
   (хинт живёт в .gate-status, js/orbit-ui.js setStatus(t('gate.hint'), true)) */

/* ── курсор-оператор ───────────────────────────────────────────────────── */

body.cursor-on, body.cursor-on a, body.cursor-on button { cursor: none; }
/* хвост 1 (волна хвостов 06.11): панель AI-менеджера .agent-root
   (agent/agent-widget.css:11) несёт тот же z-index 90 и аппендится позже
   (agent/agent-widget.js:129 против js/cursor.js:21) — при равных z-index
   панель рисовалась поверх кольца/точки и указатель над ней пропадал.
   200 — выше всех оверлеев страницы (максимум 90: .agent-root; gate 60 —
   orbit.css:1054; хедер 60 — landing.css:129); вне диапазона стены/сцены. */
.fabriko-cursor, .fabriko-cursor-dot {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  pointer-events: none;
  display: none;
}
body.cursor-on .fabriko-cursor, body.cursor-on .fabriko-cursor-dot { display: block; }
.fabriko-cursor {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1.5px solid rgba(217, 142, 74, 0.85);
  border-radius: 50%;
  transition: width 0.18s, height 0.18s, margin 0.18s, border-color 0.18s, opacity 0.2s;
}
.fabriko-cursor[data-mode="orbit"] { width: 52px; height: 52px; margin: -26px 0 0 -26px; border-color: var(--fabriko-cold); }
.fabriko-cursor[data-mode="tap"] { width: 20px; height: 20px; margin: -10px 0 0 -10px; }
.fabriko-cursor.press { width: 16px; height: 16px; margin: -8px 0 0 -8px; }
.fabriko-cursor-dot {
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  background: var(--fabriko-hot-strong);
  border-radius: 50%;
}

/* ── статичный режим (reduced-motion / ?static=1 / no-WebGL / soft) ────── */

.orbit-static-marker { display: none; }
.orbit-static .station { height: auto !important; min-height: 100vh; pointer-events: auto; }
.orbit-static .station > .pin { position: relative; height: auto; min-height: 100vh; padding: 110px 0 40px; }
/* фикс P1 критика (4-й раунд): снимки кадра рельса для станций 2/3/5 —
   реальный 3D за панелями (hero-scene.snapshotStations), панель поверх */
.orbit-static-snap {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -1; pointer-events: none; opacity: 0.96;
}
/* фикс P1 (5-й раунд, регрессия раунда 4): .wrap не позиционируем — иначе
   flex сжимал второй .wrap героя до 36px, скрытая .staple-card (right:32
   в 36px-контейнере) вылезала вправо до 449px → h-scroll 74px на 375.
   Порядок поверхностей: снимок с отрицательным z-индексом за контентом пина,
   .wrap остаются статичными (staple-card якорится к .station, без вылета). */
.orbit-static .staple-card:not(.show) { display: none; }
.orbit-static .panel { opacity: 1; transform: none; visibility: visible; }
.orbit-static .panel-dock { visibility: visible; }
.orbit-static .panel-dock .panel-card { opacity: 1; transform: none; visibility: visible; }
/* станции статичного потока не должны выглядеть пустыми: мягкие радиальные
   акценты бренда + центрированные панели (живой канвас остаётся только в герое) */
.orbit-static .station {
  background:
    radial-gradient(980px 520px at 74% 16%, rgba(217, 142, 74, 0.06), transparent 62%),
    radial-gradient(820px 460px at 16% 84%, rgba(143, 183, 217, 0.05), transparent 62%);
}
.orbit-static .st-studio .panel-dock,
.orbit-static .st-explode .panel-dock,
.orbit-static .st-estimate .panel-dock { justify-content: center; }
.orbit-static .st-cut .panel-dock { justify-content: center; }
/* кадр-постер живёт в герое и уезжает со скроллом: фиксированный канвас
   на CPU-растра стоил странице ~4 fps композитинга (гейт 1920).
   HUD при этом ОСТАЁТСЯ fixed (фикс P2 критика 18.10: position:absolute
   без позиционированного предка ронял HUD в поток страницы — станция,
   рельс-навигация и тумблер звука были недоступны на главах 2–7;
   HUD — чистый DOM без канваса, фикс-слой его не удорожает). */
.orbit-static .orbit-stage { position: absolute; inset: 0 0 auto 0; height: 100vh; }
/* фикс P2 критика (2-й раунд): селектор требовал .no-webgl ВНУТРИ .orbit-static,
   а оба класса вешаются на один body — правило не совпадало никогда */
.orbit-static.no-webgl .orbit-canvas { display: none; }
/* фикс P2: HUD не должен продолжаться в SEO-секциях после кадра
   (f1920_026: «СТАНЦИЯ ПИЛОТ» над «Библиотекой») — класс вешает
   js/orbit-ui.js по позиции трека */
body.hud-past .hud { opacity: 0; pointer-events: none; }
/* копия героя не тонет на светлом кадре кухни (замечание критика, мобайл).
   Фикс P1 критика (2-й раунд, 18.10): margin:-24px перебивал auto-маргины
   .wrap { margin:0 auto } (элемент сам несёт класс .wrap) — копия героя
   прижималась к левому краю на ВСЕХ ширинах (кикер обрезан кромкой).
   margin:-24px auto сохраняет подложку-вылет И центрирование. */
.orbit-static .st-hero .hero-copy-orbit {
  background: radial-gradient(120% 120% at 24% 40%, rgba(14, 16, 19, 0.82) 0%, rgba(14, 16, 19, 0.55) 55%, rgba(14, 16, 19, 0) 100%);
  margin: -24px auto;
  padding: 24px;
  border-radius: 20px;
}

/* ── мобайл ────────────────────────────────────────────────────────────── */

@media (max-width: 760px) {
  :root { --orbit-span: 1250vh; }
  .hud-top { left: 14px; right: 14px; }
  .hud-bottom { left: 14px; right: 14px; bottom: 14px; gap: 8px; }
  /* волна 6: на телефоне дорожка станций сжималась до 4 px — палец не попадает.
     Тонкий прогресс-бар в нижнем баре уступает место узлам, у них минимальная
     ширина; активная точка и так показывает место. */
  .hud-bottom .hud-bar-wrap { display: none; }
  .hud-rail { gap: 3px; flex: 1 1 auto; }
  /* раунд 5: узел сжимался флексом до 18 px — фиксируем ширину касания */
  .hud-node { flex: 0 0 24px; min-width: 24px; padding: 10px 3px; }
  /* кикер «СТАНЦИЯ» на телефоне съедал ширину дорожки — оставляем имя станции */
  .hud-bottom .hud-kicker { display: none; }
  .hud-coords { display: none; }
  /* фикс P1 (2-й раунд) → доработка P2 (3-й раунд): пилюля с фоном не
     решала наложения на ПЕРЕХОДАХ между станциями — блок станции теперь
     переносится js/orbit-ui.js в НИЖНИЙ бар (перед счётчиком деталей);
     верх экрана свободен целиком. Стили станции — компактно в строке. */
  .hud-bottom .hud-station-box {
    display: inline-flex;
    background: rgba(14, 16, 19, 0.72);
    border: 1px solid var(--fabriko-line);
    border-radius: 8px;
    padding: 4px 8px;
    white-space: nowrap;
  }
  .hud-bottom .hud-station { font-size: 10.5px; min-height: 0; }
  .studio-panel, .est-panel { max-height: calc(100vh - 300px); }
  .staple-card { right: 12px; left: 12px; width: auto; bottom: 90px; }
  /* волна 6 раунд 4: на телефоне карточки студии/раскроя/сметы выше экрана —
     верх уходил под шапку; ограничиваем высоту и даём внутренний скролл */
  .st-studio .panel-card, .st-cut .panel-card, .st-estimate .panel-card {
    max-height: calc(100dvh - 132px);
    overflow-y: auto;
    /* верхний HUD (звук/счётчик) висит над карточкой: резервируем полосу,
       иначе заголовок «Карта раскроя» уходил под «ЗВУК ВЫКЛ» */
    padding-top: 52px;
  }
  .hud-top { justify-content: flex-end; }
  .st-studio .panel-dock, .st-estimate .panel-dock { justify-content: center; }
  .studio-panel, .est-panel { width: min(430px, 94vw); }
  .panel-card { padding: 16px; border-radius: 14px; }
  .decor-wheel { grid-template-columns: repeat(8, 1fr); }
  .cut-part text { font-size: 46px; }
  .cg-dim { font-size: 44px; }
  .explode-label { font-size: 10px; }
  /* ITER8 (P2 семёрки): герой 375 — сцена не прячется за копией. Копия
     компактнее/ниже: мелоче типографика, плотнее отступы, «стекло» статичного
     кадра — только за строками, а не на пол-экрана (3D-кадр виден сверху). */
  .st-hero .hero-copy-orbit .kicker { font-size: 10px; letter-spacing: 0.1em; margin-bottom: 8px; }
  .st-hero .hero-copy-orbit .hero-display { font-size: clamp(23px, 6.8vw, 29px); }
  .st-hero .hero-copy-orbit .lead { font-size: 12.5px; line-height: 1.45; margin: 8px 0 12px; }
  .st-hero .hero-actions { gap: 8px; }
  .st-hero .hero-actions .btn { padding: 10px 13px; font-size: 12.5px; }
  /* дубль подсказки HUD «листайте» на телефоне не нужен — минус строка кадра */
  .st-hero .hero-hint-orbit { display: none; }
  .st-hero .hero-copy-orbit .hero-display { font-size: clamp(20px, 5.9vw, 24px); }
  .st-hero .hero-actions { flex-wrap: nowrap; }
  .st-hero .hero-actions .btn { padding: 9px 11px; font-size: 12px; }
  .orbit-static .st-hero .hero-copy-orbit {
    background: linear-gradient(180deg, rgba(14, 16, 19, 0.8) 0%, rgba(14, 16, 19, 0.55) 55%, rgba(14, 16, 19, 0.12) 100%);
    padding: 14px 16px;
    margin: -12px auto;
    border-radius: 14px;
  }
  /* выноски на телефоне — компактнее (точка+линия те же) */
  .explode-callout { font-size: 10px; }
  .explode-callout .c-text { left: 34px; top: -30px; }
  .st-hero .panel { align-items: flex-end; padding-bottom: 64px; }
  /* раунд 5: карточка раскроя центрировалась и верхом уходила под шапку
     (y=4.6) — прижимаем к верху контентной зоны пина (шапка+22 уже в padding) */
  .st-cut > .pin { align-items: flex-start; }
  /* раунд 7: верх карточки уходил под чип «ЗВУК ВЫКЛ» (86–113.6) */
  .st-cut .panel-card { margin-top: 26px; }
  /* раунд 5: разбор центрировался и закрывал модуль (1 выноска из 6) —
     карточка вниз над HUD, модуль и выноски живут в верхней половине кадра */
  .st-explode > .pin { align-items: flex-end; padding-bottom: 70px; }
  /* на телефоне карточка разбора закрывала модуль: объяснение дублируется
     выносками, подсказка про мышь на тач-экране неверна — карточка ниже,
     модуль и ≥2 выноски читаются в верхней половине */
  .st-explode .panel-card .lead, .st-explode .explode-hint { display: none; }
  /* раунд 5: пилот 754px при 812 — верх 64 (под шапкой), низ 818 (под HUD).
     Прижимаем к верху и уплотняем: кнопка CTA обязана быть над нижним HUD. */
  .st-pilot > .pin { align-items: flex-start; }
  /* верхняя кромка карточки уходила под чип «ЗВУК ВЫКЛ» (86–113.6) */
  .st-pilot .cta-card { padding: 18px 16px 24px; gap: 12px; margin-top: 26px; }
  .st-pilot .display { font-size: 30px; line-height: 1.06; }
  .st-pilot .cta-text .lead { font-size: 13px; line-height: 1.45; margin-top: 10px; }
  .st-pilot .pilot-channels { gap: 6px; }
  .st-pilot .pchannel { padding: 8px 12px; gap: 6px; }
  .st-pilot .cta-actions { gap: 8px; }
}

/* reduced-motion: без пульсаций */
@media (prefers-reduced-motion: reduce) {
  .hero-hint-orbit i, .gate-logo { animation: none; }
  /* прорисовка выключена — знак показываем собранным (иначе dashoffset 1
     оставил бы его невидимым) */
  .gate-logo [pathLength] { stroke-dashoffset: 0; animation: none; }
  .gate-logo .gate-mark { animation: none; opacity: 1; }
  .gate-logo-sub { opacity: 1; animation: none; }
  .panel, .panel-dock .panel-card,
  .station.pin-live .panel, .station.pin-in .panel,
  .station.pin-live .panel-dock .panel-card, .station.pin-in .panel-dock .panel-card { transition: none; }
}

/* До входа в цех фоновая 3D-сцена не показывается и не принимает ввод;
   #ctor/#client открывает станцию сразу, без гейта. */
body:not(.orbit-live) .orbit-stage,
body:not(.orbit-live) .orbit-canvas { visibility: hidden; }
body:not(.orbit-live) .orbit-stage { pointer-events: none; }
.skip-gate .gate { display: none !important; }

/* #ctor/#client: станция без живой 3D-сцены до клика — только постер и адрес.
   После входа (html.stage-live) сцена возвращается как фон остальных секций:
   иначе «Карта раскроя» и соседние станции остаются на чёрном экране. */
.skip-gate:not(.stage-live) .orbit-stage,
.skip-gate:not(.stage-live) .orbit-canvas { visibility: hidden !important; pointer-events: none !important; }
.skip-gate .orbit-stage { pointer-events: none !important; }
