/* ============================================================================
   МУЗЕЙ НА ОДНОГО ПОСЕТИТЕЛЯ — оформление.
   Этот файл отвечает только за внешний вид. Разметку строит museum.js,
   движение камеры — motion.js. Договор о классах: docs/разметка.md.

   Правила, которые тут соблюдены:
   · в :root не пишем ни строки — все новые переменные объявлены в своих блоках;
   · transform у .hall__cases не трогаем: им двигает камеру хореограф;
   · filter: blur() нет нигде — свет собран из мягких градиентов, чтобы
     прокрутка не проседала по кадрам;
   · анимируем только transform и opacity.

   Содержание:
     1. Общая материя музея (свет, стекло, латунь)
     2. Архитектура зала: стена, пол, плинтус, рельс, лампы, лучи, пыль
     3. Верхняя служебная строка (.topbar)
     4. Вход (.entrance): надпись на стене, ценник-экспонат, дверной проём
     5. Зал (.hall) и прилипающая сцена
     6. Витрина (.case) и живой сайт внутри стекла
     7. Музейная этикетка (.label)
     8. Мастерская (.workshop)
     9. Финал (.finale) и пустая витрина
    10. План этажа (.plan)
    11. Окно просмотра (.viewer)
    12. Палитры залов (data-palette)
    13. Широкие экраны, ноутбук и планшет (рубеж боковой раскладки — 1320 px)
    14. Телефон (главный сценарий: ссылка из Телеграма)
    15. Кому движение мешает (prefers-reduced-motion)
   ========================================================================== */


/* ==========================================================================
   1. ОБЩАЯ МАТЕРИЯ МУЗЕЯ
   Переменные объявлены на body — это не :root, base.css не задет.
   ========================================================================== */

body {
  /* стекло витрины */
  --glass-edge:  rgba(226, 208, 182, .26);
  --glass-edge-lit: rgba(255, 226, 186, .68);
  --glass-fill:  linear-gradient(158deg,
                   rgba(255, 238, 214, .085) 0%,
                   rgba(255, 238, 214, .012) 34%,
                   rgba(255, 238, 214, 0)    60%,
                   rgba(255, 238, 214, .045) 100%);

  /* линии и рамки служебного слоя */
  --hair:        rgba(226, 208, 182, .20);
  --hair-brass:  rgba(201, 165, 107, .38);

  /* тайминги: переходы короткие, музей не медлит */
  --t-fast:  .22s;
  --t-mid:   .42s;
  --t-slow:  .7s;

  /* отступ от края экрана — один на весь сайт */
  --edge: clamp(18px, 4vw, 76px);
}

/* Переход по плану этажа не должен прятать начало зала под шапкой. */
.entrance,
.hall,
.workshop,
.finale {
  scroll-margin-top: calc(var(--topbar-h) + 8px);
}

/* Крупные надписи — антиква, как краска по стене музея. */
.entrance__title,
.hall__client,
.label__title,
.workshop__title,
.finale__title,
.emptycase figcaption h3,
.workshop__col h3,
.pricecase__sum,
.topbar__monogram {
  font-family: var(--serif);
  font-weight: 400;
}

/* Служебные подписи вразрядку: чуть крупнее базовых 10px там, где несут смысл. */
.tag { line-height: 1.7; }

/* Кнопки музея: латунная рамка, высота не меньше 44 px (палец, а не курсор). */
.btn,
.label__enter,
.topbar__tg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 44px;
  padding: 11px 20px;
  border: 1px solid var(--hair-brass);
  color: #f6ecdc;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  background: linear-gradient(180deg, rgba(201, 165, 107, .14), rgba(201, 165, 107, .03));
  transition: border-color var(--t-fast) ease,
              background-color var(--t-fast) ease,
              transform var(--t-fast) var(--ease-cam),
              box-shadow var(--t-fast) ease;
}

.btn:hover,
.label__enter:hover,
.topbar__tg:hover {
  border-color: rgba(255, 215, 160, .8);
  background-color: rgba(255, 205, 150, .12);
  box-shadow: 0 0 24px rgba(255, 196, 140, .18);
  transform: translateY(-1px);
}

.btn:active,
.label__enter:active,
.topbar__tg:active { transform: translateY(0); }

.btn--big {
  min-height: 56px;
  padding: 16px 32px;
  font-size: 13px;
  letter-spacing: .18em;
  border-color: rgba(255, 215, 160, .6);
  background: linear-gradient(180deg, rgba(255, 205, 150, .16), rgba(255, 205, 150, .04));
}


/* ==========================================================================
   2. АРХИТЕКТУРА ЗАЛА
   Одни и те же классы работают и на входе, и в залах — museum.js выдаёт
   ту же стену и тот же пол, что лежат в index.html.
   ========================================================================== */

/* --- стена: тёплый почти чёрный уголь, отсвет лампы сверху ---------------- */
.hall__wall {
  position: absolute;
  inset: 0 0 30% 0;
  z-index: 0;
  background:
    radial-gradient(900px 420px at 66% 24%, var(--hall-glow), transparent 68%),
    /* Набег цвета на дальней стене. Раньше он был прибит тёплым — из-за
       этого все залы выглядели одинаково ламповыми, какой бы ни была
       палитра. Теперь стена и есть главный признак зала: её видно раньше,
       чем посетитель дошёл до витрины. */
    radial-gradient(700px 460px at 12% 34%,
      var(--hall-haze, rgba(255, 196, 140, .06)), transparent 70%),
    linear-gradient(180deg, #171310 0%, #131010 48%, var(--wall-deep) 100%);
}

/* штукатурка: еле заметные вертикальные панели, чтобы стена не была пустой */
.hall__wall::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(90deg,
              rgba(255, 255, 255, .014) 0 1px, transparent 1px 160px);
}

/* Неровность штукатурки: под лучом стена не должна быть идеально ровной —
   именно эти пятна превращают заливку в помещение. */
.hall__wall::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    /* неровности штукатурки подсвечены тем же светом, что и вся комната */
    radial-gradient(300px 190px at 21% 44%,
      var(--hall-beam-soft, rgba(255, 214, 168, .032)), transparent 70%),
    radial-gradient(360px 230px at 62% 24%,
      var(--hall-beam-soft, rgba(255, 214, 168, .028)), transparent 72%),
    radial-gradient(260px 320px at 85% 60%, rgba(0, 0, 0, .24), transparent 74%),
    radial-gradient(220px 170px at 38% 78%, rgba(0, 0, 0, .2), transparent 72%),
    radial-gradient(180px 140px at 8% 18%, rgba(0, 0, 0, .18), transparent 74%);
}

/* --- пол: полированный бетон, швы уходят в перспективу -------------------- */
.hall__floor {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 30%;
  z-index: 0;
  overflow: hidden;
  background:
    radial-gradient(560px 190px at 62% 4%, var(--hall-glow), transparent 72%),
    linear-gradient(180deg, #191512 0%, var(--floor) 42%, #08070a 100%);
}

.hall__floor::before {
  content: "";
  position: absolute;
  left: -40%; right: -40%; top: 0; bottom: -90px;
  background: repeating-linear-gradient(90deg,
              rgba(255, 235, 210, .055) 0 1px, transparent 1px 108px);
  /* --seam-x пишет motion.js: швы пола едут вместе с камерой, иначе пол стоит
     на месте и вся комната читается как декорация на заднике. Скорость швов
     меньше скорости витрин — это и даёт ощущение шага вдоль зала. */
  transform: translateX(var(--seam-x, 0px)) perspective(300px) rotateX(64deg);
  transform-origin: top center;
  -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, .85), transparent 78%);
          mask-image: linear-gradient(180deg, rgba(0, 0, 0, .85), transparent 78%);
}

/* Пятно света под витриной, которая стоит в фокусе камеры.
   Отдельного элемента под него в разметке нет — рисуем на полу. */
.hall__floor::after {
  content: "";
  position: absolute;
  left: calc(var(--cases-x, 50%) + var(--focus, 0px));
  translate: -50% 0;
  top: -8%;
  width: min(520px, 40vw);
  height: 86%;
  background: radial-gradient(closest-side at 50% 30%, var(--hall-glow), transparent 76%);
  /* --pool-x пишет motion.js: пятно принадлежит экспонату и обязано ехать
     вместе с ним. Стоящее на месте пятно выдавало «стенды едут мимо лампы» —
     ровно то, что просили убрать. Сам пол не двигаем: он шириной в экран,
     сдвиг открыл бы дыру справа. */
  transform: translateX(var(--pool-x, 0px));
}

/* на входе освещён не ряд витрин, а ценник справа */
.entrance .hall__floor::after {
  left: auto;
  right: var(--edge);
  translate: 0 0;
  margin-right: -60px;
}

/* --- стык пола и стены: светящаяся кромка плинтуса ------------------------ */
/* Кромка горит цветом зала: это отражённый свет, а не отдельная лампа. */
.hall__skirting {
  position: absolute;
  left: 0; right: 0; bottom: 30%;
  height: 1px;
  z-index: 1;
  background: linear-gradient(90deg,
              var(--hall-beam-soft, rgba(255, 215, 165, .04)),
              var(--hall-beam, rgba(255, 215, 165, .34)) 62%,
              var(--hall-beam-soft, rgba(255, 215, 165, .05)));
}

/* --- потолочный рельс со светильниками ------------------------------------ */
.hall__rail {
  position: absolute;
  left: 0; right: 0;
  top: calc(var(--topbar-h) + 42px);
  height: 1px;
  z-index: 2;
  background: linear-gradient(90deg,
              rgba(255, 225, 190, .02), rgba(255, 225, 190, .18) 40%,
              rgba(255, 225, 190, .26) 72%, rgba(255, 225, 190, .03));
}

/* Лампа. Погашена по умолчанию — свет включает посетитель (класс is-lit
   ставит motion.js). Корпус, стеклянная трубка и конус света под ней. */
.lamp {
  position: absolute;
  top: 0;
  left: 50%;
  width: 26px;
  height: 13px;
  margin-left: -13px;
  border-radius: 0 0 5px 5px;
  background: linear-gradient(180deg, #2a2320, #151110);
  box-shadow: 0 6px 14px rgba(0, 0, 0, .6);
}

/* трубка: погашена — серая, зажжена — светится цветом зала */
.lamp::after {
  content: "";
  position: absolute;
  left: 4px; right: 4px; bottom: -2px;
  height: 3px;
  border-radius: 2px;
  background: #3a322c;
  box-shadow: none;
  transition: background-color var(--t-mid) ease, box-shadow var(--t-mid) ease;
}

/* конус света под лампой: мягкий градиент, без blur (кадры дороже красоты) */
.lamp::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 12px;
  width: 300px;
  height: 46vh;
  margin-left: -150px;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(58% 100% at 50% 0%,
              var(--hall-beam, rgba(255, 209, 156, .2)) 0%,
              var(--hall-beam-soft, rgba(255, 201, 148, .07)) 42%, transparent 74%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .45) 58%, transparent 94%);
          mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .45) 58%, transparent 94%);
  transition: opacity var(--t-slow) var(--ease-cam);
}

.lamp.is-lit::after {
  background: var(--hall-light, var(--warm));
  /* ореол вокруг трубки — того же цвета, что и луч под ней */
  box-shadow: 0 0 14px 5px var(--hall-beam, rgba(255, 205, 150, .5));
}

.lamp.is-lit::before { opacity: 1; }

/* Раскладка ламп в зале: горящая лампа висит ровно над колбой, которая стоит
   в фокусе камеры, — та же точка, куда целятся луч и пятно света на полу.
   Считается от --focus, а не процентами на глаз: размеры витрины меняются
   вместе с окном, и проценты разъезжались со светом. */
/* Все лампы витрин висят в одной точке, и это не ошибка: камера подвозит
   каждый экспонат на одно и то же место зала, значит и гореть свет обязан
   всегда над ним. Разом они не горят никогда — хореограф зажигает ровно одну.
   За ритм пустого рельса отвечают две погашенные лампы ниже. */
.hall__rail .lamp[data-lamp] {
  left: calc(var(--cases-x) + var(--focus));
  margin-left: 0;
  translate: -50% 0;
}

/* Двух бутафорских ламп на рельсе больше нет.
   Раньше они держали вид пустого рельса, но были приклеены к процентам его
   ширины — а рельс теперь едет вместе с камерой и растягивается для запаса,
   так что бутафорию растягивало вместе с ним. Настоящие светильники теперь
   висят над каждым экспонатом и едут со своими стендами, поэтому рельс не
   пустует. Пока эти псевдоэлементы существовали, motion.js вынужденно вёл
   рельс вчетверо медленнее нужного — без них потолок идёт наравне с залом. */
.hall .hall__rail::before,
.hall .hall__rail::after { content: none; }

.hall .hall__rail::before { left: 22%; }
.hall .hall__rail::after  { left: 44%; }

/* --- луч над экспонатом --------------------------------------------------- */
/* Виден всегда: даже если хореограф ещё не подключён, в зале горит свет. */
.beam {
  position: absolute;
  z-index: 2;
  pointer-events: none;
  /* Луч — самый заметный источник цвета в кадре, поэтому он целиком на
     переменных зала: ядро плотнее, ореол мягче. */
  background:
    radial-gradient(14% 100% at 50% 0%,
      var(--hall-beam, rgba(255, 224, 186, .2)) 0%,
      var(--hall-beam-soft, rgba(255, 214, 168, .05)) 40%, transparent 72%),
    radial-gradient(56% 100% at 50% 0%,
      var(--hall-beam, rgba(255, 209, 156, .3)) 0%,
      var(--hall-beam-soft, rgba(255, 201, 148, .1)) 44%, transparent 76%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .4) 60%, transparent 95%);
          mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, .4) 60%, transparent 95%);
}

/* --- пыль в луче ---------------------------------------------------------- */
/* Две тонкие сетки точек, медленно плывущие вверх. Двигается только transform,
   слой маленький — он висит в пределах луча, а не на весь экран. */
.dust {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
}

/* Точки разбросаны внутри большой плитки в разных местах — иначе сетка
   читается как обои, а не как пыль. Сдвиг за цикл равен высоте плитки,
   поэтому петля незаметна. */
.dust::before,
.dust::after {
  content: "";
  position: absolute;
  inset: -30% -10%;
  background-image:
    radial-gradient(circle at 17% 23%, rgba(255, 232, 205, .9)  0 1.1px, transparent 1.7px),
    radial-gradient(circle at 63% 41%, rgba(255, 232, 205, .62) 0 1px,   transparent 1.6px),
    radial-gradient(circle at 38% 78%, rgba(255, 232, 205, .78) 0 1.2px, transparent 1.8px),
    radial-gradient(circle at 86% 64%, rgba(255, 232, 205, .5)  0 .9px,  transparent 1.5px);
  background-size: 224px 260px;
  -webkit-mask-image: radial-gradient(58% 70% at 50% 24%, #000, transparent 82%);
          mask-image: radial-gradient(58% 70% at 50% 24%, #000, transparent 82%);
  opacity: .42;
  animation: dust-up 30s linear infinite;
}

.dust::after {
  background-size: 163px 191px;
  opacity: .24;
  animation: dust-down 44s linear infinite;
}

@keyframes dust-up   { from { transform: translate3d(0, 0, 0); }
                       to   { transform: translate3d(0, -260px, 0); } }
@keyframes dust-down { from { transform: translate3d(0, 0, 0); }
                       to   { transform: translate3d(0, 191px, 0); } }

/* Пыль в зале, которого сейчас не видно (класс ставит motion.js тем же
   наблюдателем, что останавливает её дыхание). Именно ПАУЗА, а не
   выключение: анимация замирает на текущем кадре и продолжится с него же,
   поэтому вернувшийся зал не начинает сыпать пыль заново. */
.dust.is-idle::before,
.dust.is-idle::after { animation-play-state: paused; }

/* --- виньетка и зерно: кадр фильма, а не страница ------------------------- */
.hall__stage::after,
.entrance__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  /* Виньетка начинается позже и садится мягче, чем раньше: её край
     приходился ровно на экран с работой и гасил его вместе с углами зала. */
  background: radial-gradient(136% 96% at 52% 46%, transparent 52%, rgba(4, 3, 6, .58) 100%);
}


/* ==========================================================================
   3. ВЕРХНЯЯ СЛУЖЕБНАЯ СТРОКА
   ========================================================================== */

.topbar {
  position: fixed;
  left: 0; right: 0; top: 0;
  z-index: 40;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 var(--edge);
  overflow: hidden;             /* шапка не имеет права вырасти и наехать на зал */
  background: linear-gradient(180deg, rgba(7, 6, 10, .92), rgba(7, 6, 10, .55) 62%, transparent);
}

.topbar__mark {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
}

.topbar__monogram {
  flex: 0 0 auto;
  width: 32px; height: 32px;
  display: grid;
  place-items: center;
  border: 1px solid var(--brass-dim);
  color: var(--brass);
  font-size: 16px;
  transition: border-color var(--t-fast) ease, color var(--t-fast) ease;
}

.topbar__mark:hover .topbar__monogram {
  border-color: var(--warm);
  color: var(--warm);
}

.topbar__name {
  display: block;
  font-size: 11.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: #e6d9c7;
  white-space: nowrap;
}

.topbar__name b { font-weight: 600; }

.topbar__name i {
  display: block;
  margin-top: 3px;
  font-style: normal;
  font-size: 10px;
  letter-spacing: .18em;
  color: var(--paper-dim);
}

.topbar__center {
  flex: 0 1 auto;
  text-align: center;
  color: var(--paper-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar__tg {
  flex: 0 0 auto;
  white-space: nowrap;
}

.topbar__tg span { color: var(--brass); }


/* ==========================================================================
   4. ВХОД В МУЗЕЙ
   Первый кадр: надпись краской по стене слева, проём в зал 01 по центру,
   витрина-ценник справа. Всё лежит поверх архитектуры зала.
   ========================================================================== */

.entrance {
  position: relative;
  height: 100vh;
  min-height: 660px;
  overflow: hidden;
}

.entrance__stage {
  position: absolute;
  inset: 0;
}

/* --- надпись на стене ----------------------------------------------------- */
.entrance__text {
  position: absolute;
  left: var(--edge);
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;
  width: min(46vw, 560px);
}

.entrance__text .tag { color: var(--brass); }

.entrance__text .tag::after {
  content: "";
  display: block;
  width: 54px; height: 1px;
  margin-top: 14px;
  background: var(--brass-dim);
}

.entrance__title {
  margin-top: 24px;
  font-size: clamp(38px, 6.2vw, 76px);
  line-height: .96;
  letter-spacing: -.005em;
  color: #f4e8d6;
  text-shadow: 0 0 54px rgba(255, 206, 152, .24);
}

.entrance__title em {
  font-style: italic;
  color: #e9d6bb;
}

.entrance__lead {
  margin-top: 26px;
  max-width: 480px;
  font-size: clamp(14px, 1.05vw, 15.5px);
  line-height: 1.72;
  color: rgba(238, 226, 209, .82);   /* контраст к стене ≈ 8:1 */
}

.entrance__lead b { color: #fdf3e4; font-weight: 600; }

.entrance__hint {
  margin-top: 26px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 10.5px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: rgba(238, 226, 209, .6);
}

.entrance__hint i {
  flex: 0 0 auto;
  width: 24px; height: 24px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(201, 165, 107, .45);
  color: var(--brass);
  font-style: normal;
  font-size: 12px;
  animation: hint-nudge 2.6s var(--ease-cam) infinite;
}

@keyframes hint-nudge {
  0%, 70%, 100% { transform: translateY(0); }
  82%           { transform: translateY(4px); }
}

/* --- экспонат 00: цена под стеклом ---------------------------------------- */
.pricecase {
  position: absolute;
  right: var(--edge);
  bottom: calc(var(--plan-h) + 6vh);
  z-index: 5;
  width: min(38vw, 400px);
}

.pricecase__glass {
  position: relative;
  display: flex;
  gap: 16px;
  padding: 22px 20px;
  border: 1px solid var(--hair-brass);
  background: var(--glass-fill);
  box-shadow: 0 0 50px rgba(255, 196, 140, .09), inset 0 0 30px rgba(255, 205, 155, .05);
}

/* блик по стеклу */
.pricecase__glass::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(118deg, transparent 34%, rgba(255, 247, 232, .1) 44%, transparent 51%);
}

/* бумажный ценник: тёмные чернила по светлой бумаге — самый читаемый кусок сайта */
.pricecase__ticket {
  flex: 1 1 auto;
  padding: 14px 16px 13px;
  background: linear-gradient(180deg, #f3e7d3, #e4d3ba);
  color: #20180f;
  transform: rotate(-2.2deg);
  box-shadow: 0 16px 30px rgba(0, 0, 0, .5);
}

.pricecase__cap {
  font-size: 9px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #6d5a3d;
}

.pricecase__sum {
  margin-top: 6px;
  /* На ценнике теперь фраза, а не сумма: кегль чуть меньше, строки дышат,
     перенос по смыслу — иначе «вы» повисало отдельной строкой. */
  font-size: clamp(24px, 2.1vw, 31px);
  line-height: 1.1;
  letter-spacing: -.01em;
  text-wrap: balance;
}

.pricecase__note {
  margin-top: 7px;
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #6d5a3d;
}

.pricecase__label {
  flex: 0 0 96px;
  padding-top: 2px;
}

.pricecase__label .tag { color: var(--brass); }

.pricecase__label p:last-child {
  margin-top: 9px;
  font-size: 10.5px;
  line-height: 1.6;
  color: rgba(238, 226, 209, .72);
}

.pricecase__text {
  margin-top: 14px;
  font-size: 12px;
  line-height: 1.62;
  color: rgba(238, 226, 209, .72);
}

.pricecase__text b { color: #f4e9d8; font-weight: 600; }

/* --- проём в первый зал: холодный свет из соседней комнаты ---------------- */
.doorway {
  position: absolute;
  left: 50%;
  top: 26vh;
  z-index: 1;
  width: clamp(110px, 12vw, 168px);
  height: 42vh;
  margin-left: clamp(-84px, -6vw, -55px);
  background: linear-gradient(180deg, #090a0d 0%, #0c1015 58%, #0e141a 100%);
  box-shadow: inset 0 0 60px rgba(0, 0, 0, .9), 0 0 0 1px rgba(150, 185, 215, .1);
}

.doorway__sign {
  position: absolute;
  left: 0; right: 0;
  top: -26px;
  text-align: center;
  font-size: 10px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: rgba(190, 214, 234, .72);
}

/* свечение в глубине проёма + полоса света, падающая через него на пол */
.doorway__glow {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 62%;
  background: linear-gradient(180deg, rgba(111, 149, 184, 0), rgba(111, 149, 184, .3));
}

.doorway__glow::after {
  content: "";
  position: absolute;
  left: -18%; right: -18%;
  bottom: -104px;
  height: 112px;
  background: linear-gradient(180deg, rgba(126, 166, 202, .3), rgba(126, 166, 202, 0));
  -webkit-mask-image: linear-gradient(180deg, #000, transparent);
          mask-image: linear-gradient(180deg, #000, transparent);
}

/* подпись в глубине проёма — обещание, что впереди есть куда идти */
.doorway__deep {
  position: absolute;
  left: 0; right: 0;
  bottom: 12%;
  text-align: center;
  font-size: 9.5px;
  line-height: 1.7;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: rgba(176, 204, 228, .55);
}

/* лучи и пыль на входе */
.entrance .beam--title {
  left: calc(var(--edge) - 40px);
  top: calc(var(--topbar-h) + 42px);
  width: min(560px, 52vw);
  height: 70vh;
  opacity: .8;
}

.entrance .beam--case {
  right: calc(var(--edge) - 60px);
  top: calc(var(--topbar-h) + 42px);
  width: min(520px, 46vw);
  height: 76vh;
}

.entrance .dust {
  right: var(--edge);
  top: calc(var(--topbar-h) + 40px);
  width: min(460px, 42vw);
  height: 60vh;
}


/* ==========================================================================
   5. ЗАЛ И ПРИЛИПАЮЩАЯ СЦЕНА
   Высоту прокрутки задаёт museum.js переменной --cases (число витрин).
   Сцена внутри зала прилипает к экрану — камера едет по ней вбок.
   ========================================================================== */

.hall {
  position: relative;
  height: calc(100vh + var(--cases, 1) * 85vh);
}

/* Зал с одной витриной вбок не едет: запас прокрутки ему не нужен, иначе
   человек крутит колесо, а на экране ничего не меняется. Прокрутка сразу
   уводит в следующий зал. */
.hall--single {
  height: 100vh;
}

.hall--single .hall__cases {
  transform: none !important;   /* камеру по горизонтали тут не запускаем */
}

.hall__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;

  /* Размеры витрины объявлены здесь, а не в .case: по ним считается, куда
     целить луч и пятно света на полу — а эти элементы .case не видят. */
  --glass-w:  320;              /* ширина экрана, безразмерно (px) — так велит
                                   пересчёт масштаба живого сайта: CSS не делит
                                   длину на длину */

  /* Ширина колбы — обычная длина, и она нарочно считается от ВЫСОТЫ окна:
     колба главный предмет кадра, ей нужно место по вертикали. Второй предел
     (21vw) держит её, когда окно низкое и широкое, — иначе ряд не влезает. */
  --vit-w:    min(clamp(196px, 32vh, 292px), 21vw);
  /* Просвет между экраном и колбой. Считается не от колбы, а от ТУМБЫ: она
     шире стекла на --plinth-out с каждой стороны и съедает просвет первой.
     На 1,8vw край тумбы уходил за экран сайта на треть своей столешницы —
     плоскость, ради которой всё затевалось, оказывалась обрезанной.
     --focus ниже пересчитается сам: он ссылается на эту переменную.
     Замерено 2026-08-12: при 2.6vw столешница всё ещё заходила под экран на
     23 px — на снимке это читалось как «фотка сайта залезла на стенд». 4.4vw
     разводит их с запасом на всех ширинах от 1024 px. */
  --pair-gap: clamp(26px, 5vw, 72px);
  --label-w:  212px;            /* колонка музейной этикетки */

  /* откуда начинается ряд витрин: слева от него живёт вводная табличка */
  --cases-x: clamp(20px, 30vw, 520px);

  /* На какой линии стоят экспонаты: отступ от нижнего края ряда до пола.
     Пол занимает нижние 30% зала, и предметы должны стоять НА нём, а не
     упираться в стену — иначе перед ними остаётся пустая полоса. */
  --stand-line: clamp(26px, 10vh, 104px);

  /* Центр колбы относительно начала ряда. Колба стоит второй в паре
     (экран слева, колба справа), поэтому к её половине прибавляем экран. */
  --focus: calc(var(--glass-w) * 1px + var(--pair-gap) + var(--vit-w) / 2);
}

/* --- вводная табличка зала ------------------------------------------------ */
.hall__intro {
  position: absolute;
  left: var(--edge);
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  /* Уже, чем раньше: место в кадре отдано колбе. Ширина подобрана так,
     чтобы между табличкой и краем экрана оставался просвет, а не 20 px. */
  width: min(22vw, 360px);
}

.hall__kind {
  color: var(--hall-accent);
  margin-bottom: 14px;
}

.hall__client {
  font-size: clamp(28px, 3.4vw, 46px);
  line-height: 1.06;
  color: #f4e8d6;
  text-shadow: 0 0 46px rgba(255, 206, 152, .18);
}

.hall__subject {
  margin-top: 8px;
  font-size: 13px;
  letter-spacing: .05em;
  color: rgba(238, 226, 209, .72);
}

.hall__text {
  margin-top: 18px;
  font-size: 13.5px;
  line-height: 1.7;
  color: rgba(238, 226, 209, .78);   /* контраст к стене ≈ 7:1 */
}

/* честная приписка «три решения одной задачи» — часть экспозиции */
.hall__multi {
  margin-top: 18px;
  padding: 10px 14px;
  border-left: 2px solid var(--hall-accent);
  background: rgba(201, 165, 107, .07);
  font-size: 11.5px;
  line-height: 1.6;
  letter-spacing: .04em;
  color: rgba(238, 226, 209, .82);
}

/* --- номер зала, лежащий на полу в перспективе ---------------------------- */
/* Номер лежит в ближнем левом углу пола — там, где раньше был пустой бетон.
   По центру он больше стоять не может: экспонаты опустились на пол и встали
   бы прямо на буквах. */
.hall__number {
  position: absolute;
  /* Наклон в перспективе растягивает верхнюю кромку букв шире их коробки,
     поэтому отступ берётся с запасом — иначе «З» срезает край экрана. */
  left: calc(var(--edge) + 3.5vw);
  right: auto;
  width: max-content;
  bottom: calc(var(--plan-h) + 2vh);
  z-index: 1;
  text-align: left;
  font-size: clamp(24px, 3.8vw, 52px);
  letter-spacing: .34em;
  text-transform: uppercase;
  color: rgba(255, 214, 168, .13);
  transform: perspective(420px) rotateX(62deg);
  transform-origin: top center;   /* надпись «уходит» от зрителя по полу */
  white-space: nowrap;
  overflow: hidden;
}

/* --- луч и пыль над колбой в фокусе камеры --------------------------------
   Луч целится не в середину витрины, а в колбу: она главный предмет.
   `translate` вместо margin — так центр совпадает при любой ширине окна,
   и хореографу остаётся свободным `transform`. */
.hall .beam--case {
  left: calc(var(--cases-x) + var(--focus));
  translate: -50% 0;
  top: calc(var(--topbar-h) + 42px);
  width: min(540px, 42vw);
  height: 74vh;
}

.hall .dust {
  left: calc(var(--cases-x) + var(--focus));
  translate: -50% 0;
  top: calc(var(--topbar-h) + 40px);
  width: min(460px, 38vw);
  height: 62vh;
}

/* --- ряд витрин ----------------------------------------------------------- */
/* ВНИМАНИЕ: transform этого элемента принадлежит хореографу (motion.js).
   Здесь его нет и быть не должно — только раскладка. */
.hall__cases {
  position: absolute;
  left: var(--cases-x);
  top: var(--topbar-h);
  bottom: var(--plan-h);
  z-index: 5;
  display: flex;
  /* Экспонаты не висят в середине пустой комнаты, а СТОЯТ на полу: низ ряда
     прижат к линии пола, вверх композиция растёт сама. Раньше ряд был
     отцентрован по свободной высоте и упирался в стык стены с полом —
     под ним оставалась пустая полоса в треть экрана. */
  align-items: flex-end;
  padding-bottom: var(--stand-line);
  /* просвет между витринами большой намеренно: иначе этикетка соседней
     витрины стоит вплотную к колбе и читается как подпись к ней */
  gap: clamp(90px, 12vw, 240px);
  padding-right: 40vw;          /* хвост, чтобы последняя витрина доехала до центра */
  will-change: transform;
}


/* ==========================================================================
   6. ВИТРИНА = КОЛБА + ЭКРАН
   Витрина состоит из двух предметов, стоящих рядом на полу зала:

     · КОЛБА — стеклянный куб на массивном постаменте. Внутри парит сам
       товар заказчика: торт, браслет, игрушка, машина, клавиатура.
       Это главный герой кадра, на него смотрят первым.
     · ЭКРАН — сайт, который для этого товара сделан. Меньше колбы,
       с полоской настоящего адреса сверху и с подставкой снизу,
       чтобы читался как работающая страница, а не как картинка.

   Экран строго 8:5 — ровно первый экран сайта (1440×900), поэтому живая
   страница внутри не искажается.

   Класс .case остаётся на внешнем элементе: по центрам .case хореограф
   считает, куда подвести камеру.
   ========================================================================== */

/* --glass-w, --vit-w и --label-w приходят по наследству от .hall__stage —
   там же их меняют медиазапросы. --glass-w безразмерная: из неё считается
   масштаб живого сайта, а CSS не умеет делить длину на длину. --vit-w —
   обычная длина, она считается от высоты окна. */
.case {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: auto minmax(178px, var(--label-w));
  grid-template-areas: "pair label";
  align-items: start;
  column-gap: clamp(22px, 2.4vw, 36px);
}

/* Колба и экран стоят на одном полу. row-reverse: в разметке колба идёт
   первой (она главная), а в кадре стоит справа — вплотную к своей
   этикетке, как предмет и табличка в настоящем зале.

   align-self: end — пара всегда прижата к низу витрины, даже если этикетка
   рядом оказалась выше её. Иначе у одной витрины предмет стоял бы на полу,
   а у соседней парил бы над ним. */
.case__pair {
  grid-area: pair;
  align-self: end;
  display: flex;
  flex-direction: row-reverse;
  align-items: flex-end;
  gap: var(--pair-gap);
}


/* --------------------------------------------------------------------------
   6.1 КОЛБА
   -------------------------------------------------------------------------- */

.vitrine {
  position: relative;
  flex: 0 0 auto;
  width: var(--vit-w);
  cursor: pointer;

  /* Размеры тумбы под колбой. Объявлены здесь, а не по месту: по ним
     считаются столешница, корпус, контактная тень и отражение на полу —
     разъедутся, если править их поодиночке.
       --plinth-h    вся тумба целиком;
       --plinth-top  толщина плиты столешницы: палуба + торец;
       --deck-h      палуба — та часть плиты, которую видно СВЕРХУ, плоскостью;
       --plinth-out  насколько тумба шире стекла с каждой стороны. */
  --plinth-h:   clamp(70px, 9.4vh, 108px);
  --plinth-top: clamp(26px, 3.5vh, 42px);
  /* цоколь: нижняя ступень во всю ширину тумбы. Корпус стоит НА ней, а не
     упирается в пол — по этой ступени вещь и читается как мебель */
  --base-h: clamp(9px, 1.2vh, 15px);
  /* 58% плиты — палуба, 42% — её торец. Доля продублирована числом в
     clip-path столешницы (CSS не умеет делить длину на длину). Меняете
     здесь — поменяйте и там, иначе ребро уедет с перелома. */
  --deck-h: calc(var(--plinth-top) * .58);
  /* Тумба шире колбы: постамент, который уже своего экспоната, выглядит
     шатким — это первое, что заметил владелец. На 26% она расползалась
     прилавком во всю стену; 21% + низкий корпус дают приземистую,
     тяжёлую вещь, на которую стекло поставить не страшно. */
  --plinth-out: 21%;

  /* Морёный дуб. Раньше корпус был почти чёрным (#1d1713 в середине) и
     материала в нём не читалось. Средний тон поднят: дерево в ночном зале
     тёмное, но не угольное. */
  --oak-deck:  #6d5238;   /* полированная палуба под лампой */
  --oak-face:  #493626;   /* матовый фасад корпуса */
  --oak-deep:  #241a13;   /* низ корпуса, куда свет не доходит */
}

/* Стеклянный куб. Стекло — это не рамка, а материал: у него есть толщина
   на рёбрах, зеленоватый набег в массе, преломление у нижней кромки и
   второе отражение на дальней грани. Всё собрано градиентами и внутренними
   тенями — ни одного filter, чтобы прокрутка ничего не стоила. */
.vitrine__glass {
  position: relative;
  width: 100%;
  aspect-ratio: 10 / 14;        /* вытянутый куб: предмету нужна высота */
  overflow: hidden;
  border: 1px solid var(--glass-edge);
  background:
    /* толща стекла у боковых рёбер отдаёт в зелень — как настоящее */
    linear-gradient(90deg,
      rgba(154, 198, 180, .11) 0%, rgba(154, 198, 180, 0) 9%,
      rgba(154, 198, 180, 0) 91%, rgba(154, 198, 180, .11) 100%),
    linear-gradient(180deg, rgba(154, 198, 180, .07) 0%, transparent 8%),
    var(--glass-fill);
  box-shadow:
    /* колба светится наружу цветом своего зала */
    0 0 60px var(--hall-haze, rgba(255, 196, 140, .1)),
    inset 0 0 40px rgba(255, 205, 155, .06),
    /* внутренние рёбра: видна толщина переднего и заднего стекла */
    inset 7px 0 0 -6px rgba(226, 208, 182, .2),
    inset -7px 0 0 -6px rgba(226, 208, 182, .2),
    inset 0 8px 0 -7px rgba(255, 240, 214, .24);
  transition: border-color var(--t-mid) ease, box-shadow var(--t-mid) ease;
}

/* преломление у нижней кромки и второе отражение на дальней грани */
.vitrine__glass::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background:
    linear-gradient(0deg,
      rgba(255, 240, 214, .18) 0 3px,
      rgba(255, 240, 214, .05) 3px 11px,
      transparent 11px),
    linear-gradient(90deg,
      transparent 76%, rgba(255, 247, 232, .075) 83%, transparent 90%);
}

/* главный блик по переднему стеклу, светлая кромка сверху и линия дна */
.vitrine__glass::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  background:
    linear-gradient(112deg, transparent 26%, rgba(255, 247, 232, .16) 41%, transparent 51%),
    linear-gradient(180deg, rgba(255, 231, 199, .6) 0 1px, transparent 1px),
    linear-gradient(0deg,   rgba(255, 231, 199, .44) 0 1px, transparent 1px);
}

/* Свет внутри колбы: конус сверху, пятно на дне и отсвет самого предмета
   на дальней грани — он и делает предмет «стоящим в свете», а не наклейкой. */
.vitrine__pool {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(52% 64% at 50% -8%,
      rgba(255, 214, 168, .3), rgba(255, 206, 152, .05) 52%, transparent 80%),
    radial-gradient(48% 14% at 50% 96%, var(--hall-glow), transparent 74%);
  opacity: .74;
  transition: opacity var(--t-slow) var(--ease-cam);
}

.vitrine__pool::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 16%;
  width: 74%;
  height: 46%;
  translate: -50% 0;
  background: radial-gradient(closest-side, var(--hall-glow), transparent 78%);
}

/* Предмет парит над дном. Двигается только transform — это дёшево.
   Доля высоты поднята с 62% до 68%: предмет заказчика — то, ради чего
   человек вообще подошёл к витрине, он обязан читаться первым. */
.vitrine__object {
  position: absolute;
  left: 50%;
  bottom: 16%;
  z-index: 3;
  width: auto;
  height: 68%;
  max-width: 88%;
  object-fit: contain;
  translate: -50% 0;            /* центрирование отдельным свойством, чтобы
                                   transform остался свободен под парение */
  opacity: .88;
  pointer-events: none;
  animation: exhibit-float 7.5s ease-in-out infinite;
  transition: opacity var(--t-slow) ease;
}

/* Тень предмета — та же картинка, залитая чёрным и уложенная на дно:
   она повторяет форму предмета, а не рисуется кругом. Статична, поэтому
   filter считается один раз и в кадровый цикл не попадает. */
.vitrine__cast {
  position: absolute;
  left: 50%;
  bottom: 8%;
  z-index: 2;
  width: auto;
  height: 68%;
  max-width: 88%;
  object-fit: contain;
  translate: -50% 0;
  transform: scaleY(-.2);
  transform-origin: bottom center;
  filter: brightness(0);
  opacity: .5;
  pointer-events: none;
}

/* мягкое подтенение под предметом — оно и «дышит» вместе с парением */
.vitrine__shadow {
  position: absolute;
  left: 50%;
  bottom: 7%;
  z-index: 2;
  width: 66%;
  height: 28px;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, .78), rgba(0, 0, 0, 0) 76%);
  animation: exhibit-shade 7.5s ease-in-out infinite;
}

@keyframes exhibit-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}

@keyframes exhibit-shade {
  0%, 100% { transform: scale(1);   opacity: .85; }
  50%      { transform: scale(.88); opacity: .58; }
}

/* Витрина далеко за кадром (класс ставит museum.js — полтора экрана вниз
   или полтора вбок). Предмет там рисовать некому, а браузер честно крутит
   анимацию внутри рисунка и каждый раз заново заливает тень чёрным.
   Снимаем ОТРИСОВКУ, а не раскладку: место, размер и фаза парения остаются
   на своих местах, поэтому вернувшаяся в кадр колба выглядит ровно так же.
   display: none тут был бы ошибкой — он сбрасывает парение в начало, и
   предмет возвращался бы в кадр всегда с одной и той же высоты. */
.case.is-dim .vitrine__object,
.case.is-dim .vitrine__cast { visibility: hidden; }

/* Колба, для которой предмет ещё не нарисован или не загрузился.
   Честная табличка вместо пустоты — и ничего не разъезжается. */
.vitrine__wait {
  position: absolute;
  left: 0; right: 0;
  bottom: 24%;
  z-index: 3;
  text-align: center;
  color: rgba(238, 226, 209, .6);
  opacity: 0;
  pointer-events: none;
}

.vitrine.is-empty .vitrine__wait   { opacity: 1; }
.vitrine.is-empty .vitrine__shadow { display: none; }
/* в пустой колбе свету нечего освещать — убавляем, иначе она светится
   ярче соседних, где предмет уже стоит */
.vitrine.is-empty .vitrine__pool        { opacity: .4; }
.vitrine.is-empty .vitrine__pool::after { display: none; }

/* --- ТУМБА ПОД КОЛБОЙ ------------------------------------------------------
   Было: плита читалась полоской, корпус — почти чёрной панелью в дырочку,
   а стекло стояло встык, без веса. Стало — предмет мебели из морёного дуба,
   у которого видно ПЛОСКОСТЬ столешницы, а не её торец:

     1) ПЛИТА (::before) — палуба (видна сверху, под углом) плюс её торец.
        Палуба светлее всего остального: она обращена к лампе;
     2) ПАЛУБА-НАКЛАДКА (.vitrine::after) — то, что лежит НА палубе:
        подпятник под кубом, его короткая плотная тень и волокно шпона;
     3) КОРПУС (::after плиты) — матовое тело тумбы: волокно двух шагов,
        завал света к краям, ступенчатый цоколь внизу;
     4) ОТРАЖЕНИЕ на полированном полу (.vitrine__mirror) плюс контактная
        тень в месте касания.

   По вертикали посетитель видит: предмет в стекле → подпятник → палубу →
   корпус → пол с отражением. Сам .vitrine__plinth фона не несёт: он только
   отмеряет высоту, чтобы плоскости не разъезжались.
   Ни одного filter и ни одной анимации фона — прокрутка ничего не стоит. */
.vitrine__plinth {
  position: relative;
  height: var(--plinth-h);
  margin: 0 calc(-1 * var(--plinth-out));
  /* Единственное, что красит сам элемент, — ЦОКОЛЬ: нижняя ступень во всю
     ширину тумбы, шире корпуса. Слой прижат к низу через background-size,
     плоскостей столешницы и корпуса он не задевает (те лежат выше и своими
     псевдоэлементами). Раньше цоколь был нарисован внутри корпуса и не
     выступал — из-за этого тумба заканчивалась ничем и «висела». */
  background:
    linear-gradient(180deg,
      rgba(255, 228, 184, .15) 0 1px,     /* только кромка ловит свет */
      #2a1f15 1px, #191209 56%, #0d0906 100%);
  background-size: 100% var(--base-h);
  background-position: 0 100%;
  background-repeat: no-repeat;
}

/* 1. ПЛИТА СТОЛЕШНИЦЫ: палуба (верхние 58%) + торец (нижние 42%).
   Сужается только палуба — торец остаётся прямоугольным во всю ширину:
   так и устроена плита, если смотреть на неё чуть сверху. Порядок
   остановок в вертикальном градиенте — это разрез материала. */
.vitrine__plinth::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: var(--plinth-top);
  z-index: 2;
  /* дальний край палубы уже ближнего — плоскость уходит от зрителя.
     58% — это --deck-h, перелом палубы в торец */
  clip-path: polygon(4% 0, 96% 0, 100% 58%, 100% 100%, 0 100%, 0 58%);
  background:
    /* ребро перелома: лак на кромке ловит свет — по этой линии глаз и
       понимает, что верх — плоскость, а не полоса */
    linear-gradient(180deg,
      transparent 0 56.4%, rgba(255, 236, 200, .62) 56.4% 58%, transparent 58%),
    /* рассеянный свет лампы лежит на палубе пятном, а не полосой */
    radial-gradient(46% 84% at 50% 24%, rgba(255, 228, 186, .3), transparent 74%),
    /* концы плиты уходят в темноту зала — плоскость получает длину */
    linear-gradient(90deg,
      rgba(0, 0, 0, .42) 0%, transparent 12%,
      transparent 88%, rgba(0, 0, 0, .42) 100%),
    linear-gradient(180deg,
      #5c4530 0%, var(--oak-deck) 26%, #63482f 58%,   /* палуба */
      #33261a 58%, #241a12 82%, #170f0a 100%);        /* торец в тени */
  box-shadow:
    inset 0 1px 0 rgba(255, 240, 210, .34),   /* дальняя кромка палубы */
    0 7px 16px rgba(0, 0, 0, .6);             /* плита бросает тень на корпус */
}

/* 2. КОРПУС: матовое тело тумбы. Свес плиты маленький, 3% с каждой стороны:
   большой свес превращал тумбу в консольную полку, а нужен цельный блок.
   Снизу корпус не доходит до пола на высоту цоколя — он стоит на ступени.
   Симметричный, без боковой грани: колба нарисована строго в лоб, и «косой»
   корпус под ней спорил с ней перспективой. */
.vitrine__plinth::after {
  content: "";
  position: absolute;
  inset: calc(var(--plinth-top) - 1px) 3% var(--base-h) 3%;
  z-index: 1;
  clip-path: polygon(1% 0, 99% 0, 100% 100%, 0 100%);
  background:
    /* тень от свеса плиты: у самого верха плотная, за 20 px сходит на нет */
    linear-gradient(180deg,
      rgba(0, 0, 0, .72) 0, rgba(0, 0, 0, .3) 9px, transparent 20px),
    /* волокно трёх несовпадающих шагов (7, 19 и 31 px) и очень слабое.
       Одинаковый шаг с заметной линией давал рубчик, будто фасад из гофры,
       — проверено снимком; крапина превращала дерево в перфорацию.
       Волокно должно угадываться вблизи, а не разлиновывать фасад */
    repeating-linear-gradient(90deg,
      rgba(255, 236, 212, .022) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, .055) 0 1px, transparent 1px 19px),
    repeating-linear-gradient(90deg,
      rgba(0, 0, 0, .045) 0 2px, transparent 2px 31px),
    /* фигура шпона: две широкие мягкие полосы, светлая и тёмная */
    linear-gradient(90deg,
      transparent 22%, rgba(255, 226, 186, .05) 31%, transparent 40%,
      transparent 58%, rgba(0, 0, 0, .2) 66%, transparent 74%),
    /* края корпуса заворачиваются в тень — объём без единой обводки */
    linear-gradient(90deg,
      rgba(0, 0, 0, .5) 0%, transparent 10%,
      transparent 90%, rgba(0, 0, 0, .5) 100%),
    /* свет лампы сползает по фасаду и гаснет к полу */
    radial-gradient(76% 116% at 50% 0%, rgba(255, 208, 158, .19), transparent 64%),
    /* корпус садится на цоколь: у самого низа полоска тени от собственного
       свеса — иначе ступень выглядит приклеенной, а не подложенной */
    linear-gradient(0deg, rgba(0, 0, 0, .5) 0 4px, transparent 9px),
    linear-gradient(180deg,
      var(--oak-face) 0%, #3b2c1f 34%, var(--oak-deep) 74%, #1b140f 100%);
  box-shadow: 0 30px 58px rgba(0, 0, 0, .8);
}

/* 3. ЧТО ЛЕЖИТ НА ПАЛУБЕ. Отдельный слой поверх плиты, потому что здесь
   собрано всё, что делает куб стоящим, а не приставленным:

     подпятник — тонкая плита под стеклом, видно её торец и светлую кромку;
     тень      — короткая и плотная, растекается от подпятника вперёд;
     шпон      — поперечные волокна палубы (вдоль ближнего края).

   Горизонтальные границы слоёв заданы через background-size: один градиент
   не умеет ограничивать себя по обеим осям сразу. */
.vitrine::after {
  content: "";
  position: absolute;
  left:  calc(-1 * var(--plinth-out));
  right: calc(-1 * var(--plinth-out));
  bottom: calc(var(--plinth-h) - var(--deck-h));
  height: var(--deck-h);
  z-index: 4;
  pointer-events: none;
  background:
    /* подпятник: торец в 44% высоты палубы и светлая кромка на его нижнем
       ребре — на ней и держится ощущение отдельной плитки под кубом.
       Шириной в 66% тумбы — чуть уже самого стекла */
    linear-gradient(180deg,
      rgba(34, 25, 18, .92) 0 41%,
      rgba(255, 226, 184, .42) 41% 45%,
      transparent 45%),
    /* тень стекла на палубе: держится у подпятника, быстро гаснет вперёд */
    radial-gradient(54% 96% at 50% 4%,
      rgba(0, 0, 0, .8), rgba(0, 0, 0, .34) 48%, transparent 80%),
    /* отражение колбы в лаке: слабый вертикальный след перед подпятником.
       Он и отличает полированную палубу от матового корпуса — на матовом
       дереве отражений не бывает */
    linear-gradient(180deg, transparent 0 44%, rgba(226, 216, 200, .07) 100%),
    /* волокно палубы идёт поперёк — плоскость получает направление */
    repeating-linear-gradient(180deg,
      rgba(255, 234, 204, .06) 0 1px, transparent 1px 4px);
  background-size: 66% 100%, 96% 100%, 58% 100%, 100% 100%;
  background-position: 50% 0, 50% 0, 50% 0, 0 0;
  background-repeat: no-repeat;
}

/* Табличка с номером — привинчена к фасаду тумбы. Латунь здесь
   ПОТЕМНЕВШАЯ, не полированная: рядом, на музейной этикетке, уже горит
   ярко-латунная линейка, и два одинаковых акцента в кадре спорили за
   внимание. Табличка на тумбе — служебная, её читают вторым взглядом,
   поэтому металл ушёл в патину, а свет остался только на верхнем ребре.
   Контраст надписи к дереву фасада — 6.0 : 1 при норме 4.5 : 1. */
.vitrine__no {
  position: absolute;
  left: 50%;
  bottom: 24%;
  z-index: 3;
  translate: -50% 0;
  padding: 3.5px 15px;
  border: 1px solid rgba(168, 137, 88, .34);
  border-radius: 1px;
  background:
    linear-gradient(180deg,
      rgba(176, 146, 98, .16) 0%, rgba(150, 122, 78, .09) 46%,
      rgba(96, 77, 47, .08) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 231, 190, .2),
    inset 0 -1px 0 rgba(0, 0, 0, .38),
    0 2px 5px rgba(0, 0, 0, .55);
  font-size: 8.5px;
  letter-spacing: .24em;
  font-variant-numeric: tabular-nums;
  color: rgba(232, 214, 186, .82);
  text-shadow: 0 1px 0 rgba(0, 0, 0, .55);
  white-space: nowrap;
}

/* два винта по краям таблички — оба нарисованы одним слоем фона */
.vitrine__no::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle 1.6px at 5px 50%, rgba(240, 222, 188, .4), rgba(70, 55, 32, .8) 70%, transparent),
    radial-gradient(circle 1.6px at calc(100% - 5px) 50%, rgba(240, 222, 188, .4), rgba(70, 55, 32, .8) 70%, transparent);
}

/* --- отражение стойки на полированном полу --------------------------------
   Отражается сам корпус (тёмная перевёрнутая трапеция), а сверху лежит
   тёплый отсвет лампы. Ширина считается от стойки, а не от стекла: колба
   уже своего основания, и отражение по её ширине выглядело бы обрубком. */
.vitrine__mirror {
  position: absolute;
  left: 50%;
  top: 100%;
  translate: -50% 0;
  width: calc(100% + var(--plinth-out) * 1.78);
  height: clamp(44px, 6.4vh, 88px);
  pointer-events: none;
  background:
    /* в отражении первым виден свет зала, под ним — сам камень */
    linear-gradient(180deg, var(--hall-glow, rgba(255, 220, 178, .17)), transparent 52%),
    linear-gradient(180deg,
      rgba(61, 47, 36, .62) 0%, rgba(38, 29, 23, .34) 38%, transparent 80%);
  /* сужается книзу: отражение уходит от зрителя */
  clip-path: polygon(5% 0, 95% 0, 78% 100%, 22% 100%);
  /* растворяется по мере удаления — иначе читается как световой треугольник */
  -webkit-mask-image: linear-gradient(180deg, #000 0 10%, rgba(0, 0, 0, .45) 48%, transparent 92%);
          mask-image: linear-gradient(180deg, #000 0 10%, rgba(0, 0, 0, .45) 48%, transparent 92%);
}

/* контактная тень: место, где тумба действительно касается пола.
   Узкая и плотная — именно она «приземляет» предмет. Тень тем плотнее,
   чем тяжелее вещь: под тумбой в 400 кг она почти чёрная и без ореола. */
.vitrine__mirror::before {
  content: "";
  position: absolute;
  left: -5%; right: -5%; top: -8px;
  height: 30px;
  background:
    radial-gradient(42% 100% at 50% 0%, rgba(0, 0, 0, .94), transparent 76%),
    radial-gradient(78% 150% at 50% 0%, rgba(0, 0, 0, .56), transparent 80%);
}

/* Пятно света лампы на палубе. Отдельным слоем поверх плиты, потому что оно
   загорается вместе с лучом — а анимировать разрешено только opacity.
   Именно пятно, а не полоса: свет падает сверху на плоскость, значит на ней
   лежит вытянутый овал, а вдоль ближнего ребра бежит тонкий блик на лаке.
   Лежит НИЖЕ подпятника (z-index 3 против 4) — свет не может засветить
   предмет, который стоит на пути. */
.vitrine::before {
  content: "";
  position: absolute;
  left:  calc(-1 * var(--plinth-out) + 5%);
  right: calc(-1 * var(--plinth-out) + 5%);
  bottom: calc(var(--plinth-h) - var(--deck-h));
  height: var(--deck-h);
  z-index: 3;
  pointer-events: none;
  /* Полупрозрачный цвет зала, а не сплошной: блик на лаке — это отражение
     лампы, он не может быть плотнее самой лампы. */
  background:
    linear-gradient(90deg,
      transparent, var(--hall-beam, rgba(255, 240, 208, .55)) 50%, transparent),
    radial-gradient(56% 130% at 50% 58%,
      var(--hall-beam, rgba(255, 240, 208, .55)), transparent 74%),
    /* ядро пятна. Цвет зала у холодных палитр почти прозрачен (у стального
       это rgba(198,222,242,.3)), и одного его на лаке не видно — под ним
       лежит нейтральный тёплый свет самой лампы накаливания */
    radial-gradient(42% 108% at 50% 62%,
      rgba(255, 242, 220, .17), transparent 76%);
  background-size: 100% 2px, 100% 100%, 100% 100%;
  background-position: 0 100%, 0 0, 0 0;   /* тонкий блик — ровно по ребру */
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity var(--t-slow) var(--ease-cam);
}


/* --------------------------------------------------------------------------
   6.2 ЭКРАН С ЖИВЫМ САЙТОМ
   -------------------------------------------------------------------------- */

.screen {
  flex: 0 0 auto;
  width: calc(var(--glass-w) * 1px);
}

/* полоска с настоящим адресом — сразу видно, что внутри рабочая страница */
.screen__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 26px;
  padding: 0 10px;
  border: 1px solid var(--glass-edge);
  border-bottom: 0;
  background: linear-gradient(180deg, #1c1714, #110e0c);
  font-size: 9.5px;
  letter-spacing: .1em;
  color: rgba(238, 226, 209, .74);
  overflow: hidden;
}

.screen__dot {
  flex: 0 0 auto;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--hall-accent);
  box-shadow: 0 0 7px var(--hall-accent);
}

.screen__url {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* подставка: экран тоже на чём-то стоит */
.screen__stand {
  height: 14px;
  margin: 0 26%;
  background: linear-gradient(180deg, #241d18, #100d0c);
  clip-path: polygon(8% 0, 92% 0, 100% 100%, 0% 100%);
}

.case__glass {
  position: relative;
  width: calc(var(--glass-w) * 1px);
  aspect-ratio: 8 / 5;
  overflow: hidden;
  cursor: pointer;
  border: 1px solid var(--glass-edge);
  background: #0b0908;
  box-shadow: 0 0 60px rgba(255, 196, 140, .08), inset 0 0 40px rgba(255, 205, 155, .06);
  transition: border-color var(--t-mid) ease,
              box-shadow var(--t-mid) ease;
}

/* снимок первого экрана: он же заглушка, пока сайт грузится */
.case__shot,
.case__live {
  position: absolute;
  left: 0; top: 0;
  z-index: 1;
}

.case__shot {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  transition: opacity var(--t-slow) ease;
}

/* Живой сайт: настоящая страница 1440×900, ужатая до ширины витрины.
   Мышь внутрь не проваливается — клик ловит стекло, его слушает museum.js. */
.case__live {
  width: 1440px;
  height: 900px;
  /* без этого правило `iframe { max-width: 100% }` из base.css ужимает рамку
     до ширины витрины, и сайт внутри рисуется узкой колонкой */
  max-width: none;
  transform-origin: top left;
  transform: scale(calc(var(--glass-w) / 1440));
  pointer-events: none;
  opacity: 0;
  background: #0b0908;
  transition: opacity var(--t-slow) ease;
}

/* сайт загрузился — снимок плавно уступает место живой странице */
.case.is-live .case__shot { opacity: 0; }
.case.is-live .case__live { opacity: 1; }

/* Затемнение экрана: спит в темноте, просыпается под лучом.
   Держим и в покое достаточно света, чтобы работа читалась без motion.js.

   Сила вуали зависит от того, какой сайт внутри. museum.js замеряет
   яркость снимка работы и ставит витрине data-tone="dark|mid|light":
     · тёмный сайт (DARE, BR, BindLab) под общей вуалью превращался
       в чёрный прямоугольник — под лучом вуаль с него снимается совсем;
     · светлый сайт (кремовый ViKtorian) наоборот слепит в ночном зале —
       ему вуали добавляем.
   Обещание портфолио — «работы живые, а не картинки»; экран, на котором
   ничего не разобрать, это обещание отменяет. */
.case__glass::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: radial-gradient(120% 100% at 50% 0%, rgba(7, 6, 10, .5), rgba(7, 6, 10, .88));
  opacity: var(--veil-rest, .56);
  transition: opacity var(--t-slow) var(--ease-cam);
}

.case[data-tone="dark"]  { --veil-rest: .40; --veil-near: .18; --veil-lit: 0;   }
.case[data-tone="mid"]   { --veil-rest: .52; --veil-near: .26; --veil-lit: .06; }
.case[data-tone="light"] { --veil-rest: .66; --veil-near: .40; --veil-lit: .20; }

/* блик по стеклу и светлая кромка сверху */
.case__glass::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background:
    linear-gradient(112deg, transparent 30%, rgba(255, 247, 232, .13) 43%, transparent 52%),
    linear-gradient(180deg, rgba(255, 231, 199, .5) 0 1px, transparent 1px);
  opacity: .9;
  transition: opacity var(--t-mid) ease;
}

/* --- надпись «спит» ------------------------------------------------------- */
.case__sleep {
  position: absolute;
  left: 0; right: 0;
  bottom: 16px;
  z-index: 4;
  text-align: center;
  color: rgba(238, 226, 209, .72);
  transition: opacity var(--t-mid) ease;
}

/* --- состояния витрины ---------------------------------------------------- */
/* Свет прибавляется сразу обоим предметам: колба и экран — одна витрина. */

/* Подошли ближе — вуаль убавляется. Насколько именно, решает тон сайта
   внутри (см. --veil-* выше): у тёмной работы и «слегка» уже перебор. */
.case:hover .case__glass::before,
.case:focus-within .case__glass::before { opacity: var(--veil-near, .34); }

.case:hover .case__glass,
.case:focus-within .case__glass,
.case:hover .vitrine__glass,
.case:focus-within .vitrine__glass {
  border-color: rgba(255, 226, 186, .46);
  box-shadow: 0 0 70px rgba(255, 196, 140, .16), inset 0 0 40px rgba(255, 205, 155, .08);
}

.case:hover .vitrine__pool,
.case:focus-within .vitrine__pool { opacity: .92; }

.case:hover .vitrine__object,
.case:focus-within .vitrine__object { opacity: 1; }

/* витрина в фокусе камеры: полный свет */
.case.is-active .case__glass,
.case.is-active .vitrine__glass {
  border-color: var(--glass-edge-lit);
  box-shadow: 0 0 90px rgba(255, 196, 140, .22), inset 0 0 46px rgba(255, 205, 155, .1);
}

.case.is-active .case__glass::before { opacity: var(--veil-lit, .08); }
.case.is-active .case__glass::after  { opacity: .48; }
.case.is-active .vitrine__pool       { opacity: 1; }

/* Витрина под лучом: экран должен выглядеть включённым, а не подсвеченным
   снаружи. Тёплый ореол вокруг рамки — тот свет, который сайт даёт сам. */
.case.is-active .case__glass {
  box-shadow:
    0 0 90px rgba(255, 196, 140, .22),
    0 18px 60px rgba(0, 0, 0, .55),
    inset 0 0 46px rgba(255, 205, 155, .06);
}

/* Блик по стеклу — красивая деталь, но на тёмном сайте это белая полоса
   поперёк работы. Гасим её ровно там, где она мешает читать. */
.case[data-tone="dark"].is-active .case__glass::after { opacity: .22; }
.case.is-active .vitrine__object     { opacity: 1; }
.case.is-active .vitrine__mirror     { opacity: 1; }
/* лампа зажглась — на столешнице появился блик */
.case.is-active .vitrine::before     { opacity: 1; }
.case:hover .vitrine::before         { opacity: .55; }

/* витрина не в фокусе — её отражение на полу гаснет вместе с лучом */
.vitrine__mirror {
  opacity: .55;
  transition: opacity var(--t-slow) var(--ease-cam);
}

.case.is-active .case__sleep,
.case:hover .case__sleep { opacity: 0; }

/* внутрь заказан живой сайт, но он ещё летит по проводам */
.case.is-awake .case__sleep { opacity: 0; }

.case.is-active .label { opacity: 1; }
.case.is-active .label__title { color: #fdf3e4; }


/* ==========================================================================
   7. МУЗЕЙНАЯ ЭТИКЕТКА
   Тонкая латунная линия слева, как в настоящем зале.
   ========================================================================== */

.label {
  grid-area: label;
  align-self: start;
  padding-left: 20px;
  border-left: 1px solid rgba(201, 165, 107, .5);
  opacity: .82;
  transition: opacity var(--t-mid) ease;
  hyphens: none;
}

/* Номер экспоната — висячая строка над волосяной линейкой: так набирают
   настоящие музейные таблички. Цифры моноширинные, чтобы столбик из
   девяти этикеток не «плясал». */
.label__num {
  color: var(--hall-accent);
  letter-spacing: .3em;
  font-variant-numeric: tabular-nums;
}

.label__num span::before { content: " · "; }

.label__num::after {
  content: "";
  display: block;
  width: 34px;
  height: 1px;
  margin-top: 11px;
  background: var(--hall-accent);
  opacity: .55;
}

.label__title {
  margin-top: 13px;
  font-size: clamp(20px, 1.7vw, 27px);
  line-height: 1.1;
  letter-spacing: -.005em;
  color: #f2e7d6;
  text-wrap: balance;            /* заголовок не рвётся сиротой на две буквы */
  transition: color var(--t-mid) ease;
}

.label__variant {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 9px;
  border: 1px solid var(--hair-brass);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--hall-accent);
}

.label__gist {
  margin-top: 14px;
  font-size: 12.5px;
  line-height: 1.66;
  color: rgba(238, 226, 209, .82);   /* контраст ≈ 8:1 к тёмной стене */
  text-wrap: pretty;                 /* без висячих однословных строк */
}

/* «Материал: …» — служебная строка, но её читают: кегль поднят до 11 px.
   Отделена волосяной линейкой, как раздел на музейной табличке. */
.label__material {
  margin-top: 15px;
  padding-top: 13px;
  border-top: 1px solid rgba(201, 165, 107, .2);
  font-size: 11px;
  letter-spacing: .12em;
  line-height: 1.65;
  text-transform: none;
  color: rgba(238, 226, 209, .66);
  text-wrap: pretty;
}

.label__enter {
  width: 100%;
  margin-top: 18px;
}

.label__link {
  display: block;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid rgba(201, 165, 107, .24);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #f6ecdc;
  transition: color var(--t-fast) ease;
}

.label__link span {
  display: block;
  margin-top: 5px;
  font-size: 10.5px;
  letter-spacing: .02em;
  text-transform: none;
  color: var(--hall-accent);
  /* Длинный адрес переносится по точкам и дефисам, а не «где придётся»:
     break-all рвал строку посреди слова — «…pages.d / ev». */
  overflow-wrap: anywhere;
  word-break: normal;
}

.label__link:hover { color: var(--warm); }
.label__link:hover span { color: var(--warm); }

.label__invite {
  margin-top: 12px;
  font-size: 11.5px;
  font-style: italic;
  line-height: 1.55;
  color: rgba(238, 226, 209, .6);
}


/* ==========================================================================
   7.1 ОТЗЫВ ЗАКАЗЧИКА — выписка из книги отзывов
   Блок необязательный: museum.js вставляет его, только если у работы есть
   поле «отзыв». Нет поля — в разметке нет ничего, пустая рамка не остаётся.

   Почему именно так, а не «карточка с аватаркой»:
   · это вещь из зала — латунная пластина, привинченная под этикеткой,
     а не элемент интернет-магазина;
   · она держится тёмной: белая карточка в ночном зале спорила бы с колбой
     за взгляд, а колба здесь главная;
   · выглядит законченной и в одиночку — соседним витринам зала ничего
     дорисовывать не нужно, столбик этикеток от неё не разъезжается.
   ========================================================================== */

.review {
  position: relative;
  margin-top: 16px;
  padding: 13px 14px 12px;
  border: 1px solid rgba(201, 165, 107, .26);
  background:
    linear-gradient(180deg,
      rgba(201, 165, 107, .085) 0%,
      rgba(201, 165, 107, .02) 55%,
      rgba(0, 0, 0, .2) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 235, 196, .12);
}

/* латунная кромка по верху пластины — она же «шляпка» крепления */
.review::before {
  content: "";
  position: absolute;
  left: -1px; right: -1px; top: -1px;
  height: 2px;
  background: linear-gradient(90deg,
    rgba(201, 165, 107, .25), rgba(228, 196, 142, .8), rgba(201, 165, 107, .25));
}

.review__cap {
  color: var(--hall-accent);
  opacity: .9;
}

/* Сама цитата — антиквой курсивом: голос человека, а не служебная строка
   музея. Кегль крупнее «сути», потому что читают её одним взглядом. */
.review__text {
  position: relative;
  margin-top: 9px;
  padding-left: 15px;                /* место под гравированную кавычку */
  font-family: var(--serif);
  font-style: italic;
  font-size: 13.5px;
  line-height: 1.6;
  color: rgba(240, 229, 212, .9);    /* контраст к полю пластины ≈ 9:1 */
  text-wrap: pretty;
}

/* Открывающая кавычка — крупная, латунная, как гравировка на пластине.
   Привязана к первой строке цитаты, а не к углу таблички: в узкой колонке
   планшета заголовок «отзыв заказчика» переносится на две строки, и
   кавычка из угла наезжала прямо на него (видно на снимке 768 px). */
.review__text::before {
  content: "«";
  position: absolute;
  left: -3px;
  top: -5px;
  font-size: 30px;
  line-height: 1;
  font-style: normal;
  color: var(--hall-accent);
  opacity: .32;
  pointer-events: none;
}

/* Везде, кроме телефона, цитата ограничена четырьмя строками: там она стоит
   в колонке этикетки, а колонка растёт вверх и утаскивает заголовок работы
   под шапку. На телефоне лента вертикальная, места сколько угодно — там
   отзыв показывается целиком. */
@media (min-width: 768px) {
  .review__text {
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

.review__who {
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid rgba(201, 165, 107, .2);
  font-size: 10.5px;
  letter-spacing: .1em;
  line-height: 1.5;
  color: rgba(238, 226, 209, .72);
}

.review__date {
  display: block;
  margin-top: 3px;
  font-size: 10px;
  letter-spacing: .16em;
  font-variant-numeric: tabular-nums;
  color: var(--hall-accent);
  opacity: .8;
}

/* --- отзыв переезжает на стену над экраном --------------------------------
   Проблема, ради которой это сделано: колонка этикетки и без отзыва занимает
   почти всю высоту зала, а ряд витрин прижат к полу — значит любой блок в
   её потоке растит этикетку ВВЕРХ и загоняет заголовок работы под шапку.
   Проверено снимком: зал 04 с длинным отзывом обрезало сверху.

   Над экраном сайта пустует стена: экран вдвое ниже колбы. Туда цитату и
   вешаем — абсолютным слоем, который на раскладку уже не влияет. Заодно
   это ровно то, о чём просили: отзыв стоит рядом с самим экспонатом, а не
   в конце столбика текста.

   Все размеры считаются, а не подбираются на глаз:
     высота экрана = полоска адреса (26) + стекло (--glass-w × 5/8) + подставка (14);
     высота колбы   = --vit-w × 1.4 (стекло 10/14) + --plinth-h (стойка).
   Пороги подобраны по снимкам, а не на глаз:
     ширина ≥ 1320 px — до этого рубежа вводная табличка зала переезжает
       наверх и занимает как раз ту стену, куда просится отзыв (на ноутбуке
       1280×800 пластина упиралась в описание зала);
     высота ≥ 800 px — ниже свободной стены над экраном не остаётся.
   За этими порогами отзыв просто стоит в потоке этикетки. */
@media (min-width: 1320px) and (min-height: 800px) {
  .review {
    position: absolute;      /* точка отсчёта — .case, у него position: relative */
    left: 0;
    bottom: calc(var(--glass-w) * .625px + 56px);
    width: calc(var(--glass-w) * 1px);
    /* страховка: выше свободной стены блок не станет ни при каком тексте */
    max-height: calc(var(--vit-w) * 1.4 + var(--plinth-h)
                     - var(--glass-w) * .625px - 82px);
    margin: 0;
    overflow: hidden;
    z-index: 3;
  }

  /* На широкой пластине строка вмещает вдвое больше, поэтому тех же четырёх
     строк хватает на три предложения: обрезка тут — крайний случай. */
  .review__text { font-size: 14px; }

  .review__who {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
  }

  .review__date { margin-top: 0; }
}


/* ==========================================================================
   8. МАСТЕРСКАЯ — комната за служебной дверью
   ========================================================================== */

.workshop {
  position: relative;
  padding: clamp(70px, 12vh, 140px) var(--edge) clamp(70px, 12vh, 130px);
  background:
    radial-gradient(760px 420px at 20% 0%, rgba(255, 196, 140, .07), transparent 70%),
    linear-gradient(180deg, var(--ink) 0%, #100d0c 40%, var(--ink) 100%);
  border-top: 1px solid rgba(201, 165, 107, .16);
}

/* Миллиметровка под лампой: комната за служебной дверью — рабочая, а не
   выставочная. Сетка статична и нарисована градиентами, поэтому не стоит
   ни одного кадра прокрутки. */
.workshop::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    repeating-linear-gradient(90deg, rgba(255, 235, 210, .03) 0 1px, transparent 1px 96px),
    repeating-linear-gradient(0deg,  rgba(255, 235, 210, .024) 0 1px, transparent 1px 96px);
  -webkit-mask-image: radial-gradient(110% 86% at 20% 0%, #000, transparent 74%);
          mask-image: radial-gradient(110% 86% at 20% 0%, #000, transparent 74%);
}

.workshop__stage {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
}

/* табличка на двери */
.workshop__door {
  display: inline-block;
  padding: 9px 16px;
  border: 1px dashed rgba(111, 149, 184, .5);
  color: rgba(176, 204, 228, .85);
}

.workshop__title {
  margin-top: 26px;
  font-size: clamp(30px, 4vw, 54px);
  line-height: 1.05;
  color: #f4e8d6;
}

.workshop__cols {
  margin-top: clamp(32px, 5vh, 58px);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: clamp(28px, 3vw, 52px);
}

.workshop__col h3 {
  font-size: 20px;
  color: #f0e4d2;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hair-brass);
}

/* Только простой абзац колонки. Без :not([class]) это правило перебивало
   собственный вид ценника и врезки — они шли ниже, но с меньшим весом
   селектора, и цена «от 3000 ₽» рисовалась обычным текстом в 14 px. */
.workshop__col > p:not([class]) {
  margin-top: 16px;
  font-size: 14px;
  line-height: 1.72;
  color: rgba(238, 226, 209, .8);
}

.steps,
.includes {
  margin-top: 18px;
  list-style: none;
  counter-reset: step;
}

.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 38px;
  margin-top: 16px;
  font-size: 13.5px;
  line-height: 1.66;
  color: rgba(238, 226, 209, .78);
}

.steps li::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0; top: 1px;
  width: 26px;
  text-align: center;
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--brass);
  border-bottom: 1px solid var(--hair-brass);
  padding-bottom: 3px;
}

.steps li b,
.includes li b { color: #f4e9d8; font-weight: 600; }

.includes li {
  position: relative;
  padding-left: 22px;
  margin-top: 12px;
  font-size: 13.5px;
  line-height: 1.6;
  color: rgba(238, 226, 209, .78);
}

.includes li::before {
  content: "";
  position: absolute;
  left: 0; top: 9px;
  width: 10px; height: 1px;
  background: var(--brass);
}

.workshop__aside {
  margin-top: 20px;
  padding: 12px 14px;
  border-left: 2px solid rgba(111, 149, 184, .5);
  background: rgba(111, 149, 184, .06);
  font-size: 12.5px;
  line-height: 1.6;
  color: rgba(226, 232, 238, .74);
}

/* Цена — то, ради чего эту колонку дочитывают. Она стоит на бумажном ценнике,
   как экспонат 00 на входе: два одинаковых предмета в разных концах музея
   читаются как одно обещание. */
.workshop__price {
  display: inline-block;
  max-width: 100%;                 /* ценник теперь фраза, а не «3000 ₽»:
                                      без ограничения он вылезал из колонки */
  margin: 22px 0 18px;
  padding: 10px 18px 12px;
  font-family: var(--serif);
  font-size: clamp(26px, 2.6vw, 34px);
  line-height: 1.12;
  text-wrap: balance;
  color: #20180f;
  background: linear-gradient(180deg, #f3e7d3, #e4d3ba);
  box-shadow: 0 14px 28px rgba(0, 0, 0, .5);
  transform: rotate(-1.4deg);
}

.btn--tg { width: 100%; max-width: 320px; }


/* ==========================================================================
   9. ФИНАЛ — полный свет
   Все девять окон горят одновременно, а в конце зала стоит пустая витрина.
   ========================================================================== */

.finale {
  position: relative;
  padding: clamp(70px, 12vh, 140px) var(--edge) calc(var(--plan-h) + clamp(50px, 8vh, 90px));
  background:
    radial-gradient(1200px 620px at 50% 0%, rgba(255, 206, 152, .12), transparent 72%),
    radial-gradient(700px 460px at 22% 88%, rgba(255, 206, 152, .1), transparent 74%),
    linear-gradient(180deg, #151110 0%, #0d0b0a 60%, var(--ink) 100%);
  border-top: 1px solid rgba(255, 215, 165, .2);
}

.finale__stage {
  max-width: 1280px;
  margin: 0 auto;
}

.finale__tag { color: var(--warm); }

.finale__title {
  margin-top: 18px;
  font-size: clamp(30px, 4.4vw, 58px);
  line-height: 1.04;
  color: #fdf3e4;
  text-shadow: 0 0 60px rgba(255, 206, 152, .26);
}

/* подзаголовок финала: объясняет, что витрины кликаются */
.finale__lead {
  margin-top: 14px;
  max-width: 46ch;
  font-size: clamp(15px, 1.15vw, 17px);
  color: var(--paper-dim);
}

.finale__grid {
  margin-top: clamp(32px, 5vh, 56px);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: clamp(14px, 1.6vw, 26px);
}

/* окно = маленькая витрина: снимок работы под стеклом */
.finale__cell {
  position: relative;
  display: block;
  overflow: hidden;
  border: 1px solid var(--glass-edge);
  background: #0b0908;
  transition: border-color var(--t-fast) ease,
              transform var(--t-fast) var(--ease-cam),
              box-shadow var(--t-fast) ease;
}

.finale__cell img {
  width: 100%;
  aspect-ratio: 8 / 5;
  object-fit: cover;
  object-position: top center;
  opacity: .78;
  transition: opacity var(--t-fast) ease;
}

.finale__cell:hover {
  border-color: var(--glass-edge-lit);
  transform: translateY(-3px);
  box-shadow: 0 0 44px rgba(255, 196, 140, .2);
}

.finale__cell:hover img { opacity: 1; }

.finale__name {
  display: block;
  padding: 12px 14px 0;
  font-size: 13px;
  letter-spacing: .04em;
  color: #f2e7d6;
}

.finale__host {
  display: block;
  padding: 4px 14px 13px;
  letter-spacing: .1em;
  text-transform: none;
  word-break: break-all;
}

/* --- пустая витрина: экспонат 10 ----------------------------------------- */
.emptycase {
  margin-top: clamp(44px, 8vh, 90px);
  display: grid;
  grid-template-columns: minmax(240px, 420px) minmax(260px, 1fr);
  gap: clamp(24px, 3vw, 54px);
  align-items: center;
}

.emptycase__glass {
  position: relative;
  aspect-ratio: 8 / 5;
  border: 1px solid var(--glass-edge-lit);
  background: var(--glass-fill);
  box-shadow: 0 0 80px rgba(255, 196, 140, .2), inset 0 0 60px rgba(255, 205, 155, .07);
}

/* луч над пустой витриной — место для будущей работы уже освещено */
.emptycase__glass::before {
  content: "";
  position: absolute;
  left: 50%; top: -1px;
  width: 70%; height: 100%;
  margin-left: -35%;
  background:
    radial-gradient(16% 100% at 50% 0%,
      rgba(255, 226, 190, .26), rgba(255, 214, 168, .05) 44%, transparent 74%),
    radial-gradient(60% 100% at 50% 0%,
      rgba(255, 209, 156, .34), rgba(255, 201, 148, .07) 52%, transparent 80%);
}

.emptycase__glass::after {
  content: "";
  position: absolute;
  left: 8%; right: 8%; bottom: 0;
  height: 2px;
  background: linear-gradient(90deg,
              rgba(255, 220, 180, .1), rgba(255, 226, 190, .6), rgba(255, 220, 180, .1));
}

.emptycase figcaption .tag { color: var(--warm); }

.emptycase figcaption h3 {
  margin-top: 12px;
  font-size: clamp(28px, 3.4vw, 44px);
  line-height: 1.05;
  color: #fdf3e4;
}

.emptycase__mat {
  margin-top: 14px;
  font-size: 13.5px;
  line-height: 1.7;
  color: rgba(238, 226, 209, .78);
}

.emptycase__note {
  margin-top: 14px;
  font-size: 12.5px;
  line-height: 1.6;
  color: rgba(238, 226, 209, .66);
}

.emptycase .btn--big { margin-top: 22px; }


/* ==========================================================================
   10. ПЛАН ЭТАЖА — навигация
   Всегда внизу экрана: видно, где вы и сколько залов осталось.
   ========================================================================== */

.plan {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 30;
  height: var(--plan-h);
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 26px);
  padding: 0 var(--edge);
  border-top: 1px solid rgba(201, 165, 107, .2);
  /* Фон панели плотный, без backdrop-filter. Размытие здесь выглядело
     уместно, но стоило дорого: панель прибита к низу экрана, а зал под ней
     едет, поэтому браузер пересчитывал размытие КАЖДЫЙ кадр прокрутки —
     на всю ширину экрана. Замер (tools/lag-probe.mjs) показал разницу
     в рывках; вид без размытия сохранён тем, что фон стал плотнее. */
  background: linear-gradient(180deg, rgba(8, 7, 10, .82), rgba(8, 7, 10, .985) 55%);
}

.plan__cap {
  flex: 0 0 auto;
  width: 74px;
  color: rgba(201, 165, 107, .9);
}

.plan__list {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-width: 0;
  list-style: none;
}

.plan__item {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
}

.plan__item button {
  width: 100%;
  min-height: 56px;
  height: 100%;
  display: grid;
  grid-template-columns: 30px 1fr;
  align-items: center;
  column-gap: 10px;
  padding: 8px 10px;
  text-align: left;
  border: 1px solid var(--hair);
  border-right: 0;
  transition: border-color var(--t-fast) ease, background-color var(--t-fast) ease;
}

.plan__item:last-child button { border-right: 1px solid var(--hair); }

.plan__item button:hover { background: rgba(255, 205, 150, .07); }

.plan__num {
  grid-row: 1 / 3;
  display: grid;
  place-items: center;
  height: 22px;
  border: 1px solid var(--hair);
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(238, 226, 209, .7);
}

.plan__name {
  font-size: 11.5px;
  letter-spacing: .06em;
  color: rgba(238, 226, 209, .84);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.plan__sub {
  font-size: 9.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(201, 165, 107, .88);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* вы здесь */
.plan__item.is-current button {
  border-color: rgba(255, 214, 168, .7);
  background: rgba(255, 205, 150, .1);
  box-shadow: inset 0 0 22px rgba(255, 196, 140, .16);
}

.plan__item.is-current .plan__num {
  border-color: rgba(255, 214, 168, .8);
  color: #f7ecdb;
}

.plan__item.is-current .plan__name { color: #f7ecdb; }

.plan__item.is-current::before {
  content: "вы здесь";
  position: absolute;
  left: 10px;
  top: -17px;
  display: block;
  padding-left: 12px;
  font-size: 8.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--warm);
  white-space: nowrap;
}

.plan__item.is-current::after {
  content: "";
  position: absolute;
  left: 10px;
  top: -12px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--warm);
  box-shadow: 0 0 0 4px rgba(255, 215, 160, .16), 0 0 12px 3px rgba(255, 205, 150, .6);
}

/* служебная дверь в мастерскую — пунктиром и холодным цветом */
.plan__item--service .plan__num {
  border-style: dashed;
  border-color: rgba(111, 149, 184, .5);
  color: rgba(160, 193, 220, .8);
}

.plan__item--service .plan__name { color: rgba(176, 204, 228, .82); }
.plan__item--service .plan__sub  { color: rgba(140, 178, 208, .8); }

.plan__tail {
  flex: 0 0 auto;
  width: 128px;
  text-align: right;
  color: var(--paper-dim);
}


/* ==========================================================================
   11. ОКНО ПРОСМОТРА — работа целиком
   ========================================================================== */

.viewer {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  background: rgba(5, 4, 8, .96);
}

.viewer[hidden] { display: none; }

body.is-viewing { overflow: hidden; }

.viewer__bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(10px, 2vw, 24px);
  padding: 10px var(--edge);
  border-bottom: 1px solid var(--hair-brass);
  background: linear-gradient(180deg, #14110f, #0b0908);
}

.viewer__title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--serif);
  font-size: clamp(16px, 1.6vw, 22px);
  color: #f4e8d6;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.viewer__open,
.viewer__close {
  flex: 0 0 auto;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 10px 16px;
  border: 1px solid var(--hair-brass);
  font-size: 11.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #f6ecdc;
  transition: border-color var(--t-fast) ease, background-color var(--t-fast) ease;
}

.viewer__open:hover,
.viewer__close:hover {
  border-color: var(--warm);
  background: rgba(255, 205, 150, .1);
}

.viewer__frame {
  flex: 1 1 auto;
  position: relative;
  background: #0b0908;
}

.viewer__frame iframe {
  width: 100%;
  height: 100%;
}


/* ==========================================================================
   12. ПАЛИТРЫ ЗАЛОВ
   Материя музея одна, а свет у каждого заказчика свой. Значения по умолчанию —
   тёплая лампа; незнакомая палитра ничего не ломает.
   ========================================================================== */

/* Шесть переменных на зал. Первые три были и раньше — их имена трогать
   нельзя: по ним хореограф (motion.js) зажигает лампы. Три последние
   добавлены, потому что прежние палитры почти не было видно: цвет доходил
   до лампочки и заканчивался, а комната у всех залов оставалась одинаково
   тёплой. Теперь цвет достаёт до луча, стены, пола и колбы.

   | Переменная       | Что красит                                        |
   |------------------|---------------------------------------------------|
   | --hall-light     | трубку лампы (чистый цвет, без прозрачности)      |
   | --hall-glow      | отсвет: пятно на полу, свет в колбе, отражение    |
   | --hall-accent    | служебные линии и подписи зала                    |
   | --hall-beam      | ядро луча, конус лампы, кромка плинтуса, блик     |
   | --hall-beam-soft | ореол вокруг луча                                 |
   | --hall-haze      | набег цвета на стене — им зал и «звучит» издали   |

   Материя музея при этом общая: стена, пол, стекло и латунь этикеток
   везде одни и те же. Меняется свет, а не отделка. */

.hall {
  --hall-light:     var(--warm);
  --hall-glow:      rgba(255, 206, 152, .2);
  --hall-accent:    var(--brass);
  --hall-beam:      rgba(255, 209, 156, .3);
  --hall-beam-soft: rgba(255, 201, 148, .09);
  --hall-haze:      rgba(255, 196, 140, .07);
}

/* РОЗОВАЯ ГЛАЗУРЬ — DARE, косметички-тортики.
   Кондитерская витрина: пудровый свет, тёплая малиновая тень на стене. */
.hall[data-palette="rose"] {
  --hall-light:     #ffc7c4;
  --hall-glow:      rgba(255, 150, 150, .24);
  --hall-accent:    #dda394;
  --hall-beam:      rgba(255, 186, 182, .3);
  --hall-beam-soft: rgba(255, 164, 160, .09);
  --hall-haze:      rgba(214, 96, 104, .09);
}

/* СТАЛЬ И БОРДО — ViKtorian PendanT, браслеты с фотокарточками.
   Театральный зал: холодный металлический луч сверху, а комната позади
   налита бордовым, как занавес. Два разных источника — потому зал и не
   спутать с соседним холодным. */
.hall[data-palette="steel"] {
  --hall-light:     #d8e8f5;
  --hall-glow:      rgba(158, 46, 70, .28);
  --hall-accent:    #d3a0aa;
  --hall-beam:      rgba(198, 222, 242, .3);
  --hall-beam-soft: rgba(168, 200, 228, .08);
  --hall-haze:      rgba(142, 34, 58, .12);
}

/* ЦЕХОВОЙ БЕЛЫЙ — BR Engineering, гоночный прототип.
   Ни грамма уюта: жёсткая белая лампа, серо-стальной воздух, никакого
   тёплого набега на стенах. Самый резкий зал музея. */
.hall[data-palette="graphite"] {
  --hall-light:     #f7fafd;
  --hall-glow:      rgba(196, 220, 240, .24);
  --hall-accent:    #c2ccd4;
  --hall-beam:      rgba(232, 244, 255, .34);
  --hall-beam-soft: rgba(206, 224, 240, .12);
  /* Холода на стене нарочно больше, чем логика «жёсткого света» требует:
     базовая штукатурка музея тёплая, и без этого зал оставался коричневым. */
  --hall-haze:      rgba(168, 200, 230, .09);
}

/* ШЕРСТЬ И КАРАМЕЛЬ — comfortable table, вязаные игрушки.
   Самый домашний зал: свет как от лампы под абажуром, стены медовые. */
.hall[data-palette="wool"] {
  --hall-light:     #ffcf92;
  --hall-glow:      rgba(226, 132, 46, .32);
  --hall-accent:    #e3b985;
  --hall-beam:      rgba(255, 190, 116, .34);
  --hall-beam-soft: rgba(236, 158, 78, .12);
  /* Медовый набег сильнее прочих: рядом стоит зал с розовой лампой, и без
     этого «тёплый» и «розовый» читались как один и тот же тёплый свет. */
  --hall-haze:      rgba(206, 112, 34, .14);
}

/* НОЧНАЯ СИНЬ — BindLab, сервис для игроков.
   Комната ночью у монитора: синий воздух и холодный неоновый луч. */
.hall[data-palette="night"] {
  --hall-light:     #a8b8ff;
  --hall-glow:      rgba(58, 84, 224, .28);
  --hall-accent:    #a7b6ee;
  --hall-beam:      rgba(130, 158, 255, .3);
  --hall-beam-soft: rgba(96, 124, 236, .09);
  --hall-haze:      rgba(40, 64, 190, .13);
}

/* ФАЗА — изумрудно-лаймовая гамма самого приложения. */
.hall[data-palette="phase"] {
  --hall-light:     #b8f2c8;
  --hall-glow:      rgba(96, 214, 138, .24);
  --hall-accent:    #9fd8ae;
  --hall-beam:      rgba(150, 238, 180, .3);
  --hall-beam-soft: rgba(110, 214, 146, .09);
  --hall-haze:      rgba(48, 168, 104, .09);
}

/* ЛУННОЕ СЕРЕБРО — Слёзы Ангелов Кутюр.
   Холодный лунный луч держит зал музейным, а тонкий багровый набег на стене
   напоминает о втором, демоническом лице бренда. */
.hall[data-palette="angel"] {
  --hall-light:     #edf2ff;
  --hall-glow:      rgba(174, 184, 214, .25);
  --hall-accent:    #d2d8e4;
  --hall-beam:      rgba(218, 228, 248, .32);
  --hall-beam-soft: rgba(154, 170, 204, .1);
  --hall-haze:      rgba(122, 34, 58, .09);
}

/* служебные подписи внутри зала берут его цвет */
.hall .tag { color: var(--hall-accent); }


/* ==========================================================================
   ВХОДНАЯ ДВЕРЬ
   Закрыта при загрузке, распахивается двумя створками в музей. Тёплый свет
   пробивается из щели и разливается, когда створки расходятся. Разметка и
   логика — в index.html; здесь только вид и движение.
   ========================================================================== */

.door {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: transparent;   /* за створками — настоящий зал сайта, а не рисунок */
  perspective: 1500px;
  perspective-origin: 50% 46%;
  overflow: hidden;
}

/* держим прокрутку, пока дверь закрыта */
html.door-shut,
html.door-shut body { overflow: hidden !important; height: 100%; }

/* --- КАМЕННЫЙ ПОРТАЛ -------------------------------------------------------
   Рама вокруг проёма: перемычка сверху, косяки по бокам, порог снизу.
   Именно она даёт двери вес — без рамы створки читаются как две панели. */
.door__portal { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.door__lintel,
.door__jamb,
.door__sill {
  position: absolute;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.014) 0 3px, rgba(0,0,0,.05) 3px 7px),
    linear-gradient(180deg, #221c18, #100c0a);
}
.door__lintel {
  top: 0; left: 0; right: 0;
  height: clamp(34px, 6vh, 68px);
  box-shadow: 0 10px 40px rgba(0,0,0,.75), inset 0 -1px 0 rgba(201,165,107,.16);
}
.door__jamb { top: 0; bottom: 0; width: clamp(24px, 4.5vw, 74px); }
.door__jamb--l { left: 0;  box-shadow: 14px 0 44px rgba(0,0,0,.7), inset -1px 0 0 rgba(201,165,107,.14); }
.door__jamb--r { right: 0; box-shadow: -14px 0 44px rgba(0,0,0,.7), inset 1px 0 0 rgba(201,165,107,.14); }
.door__sill {
  left: 0; right: 0; bottom: 0;
  height: clamp(16px, 2.6vh, 30px);
  background: linear-gradient(180deg, #2a231d, #14100d);
  box-shadow: 0 -8px 30px rgba(0,0,0,.6), inset 0 1px 0 rgba(201,165,107,.2);
}

/* --- СТВОРКИ ---------------------------------------------------------------
   Дерево набрано слоями: продольные волокна, тёмный ореол по краям,
   вертикальный градиент. Свет падает от стыка — там створка светлее. */
.door__leaf {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50.4%;
  z-index: 4;
  background:
    linear-gradient(90deg, rgba(0,0,0,.62), rgba(0,0,0,0) 18%, rgba(0,0,0,0) 82%, rgba(0,0,0,.62)),
    repeating-linear-gradient(88deg, rgba(255,255,255,.016) 0 1px, rgba(0,0,0,.045) 1px 5px),
    repeating-linear-gradient(0deg, rgba(255,255,255,.008) 0 2px, rgba(0,0,0,.03) 2px 6px),
    linear-gradient(180deg, #2a201a 0%, #1a1310 46%, #0d0a09 100%);
  box-shadow: inset 0 0 160px rgba(0,0,0,.62);
  transition: transform 1.5s var(--ease-cam), filter 1.2s ease;
  backface-visibility: hidden;
  transform-style: preserve-3d;
  will-change: transform;
}

/* тонкая обвязка створки — рамка по периметру */
.door__leaf::before {
  content: "";
  position: absolute;
  inset: clamp(30px, 5vh, 62px) clamp(22px, 4vw, 60px) clamp(18px, 3vh, 40px);
  border: 1px solid rgba(201,165,107,.10);
  box-shadow: inset 0 0 0 6px rgba(0,0,0,.28);
  pointer-events: none;
}

/* блик вдоль стыка: свет из щели ложится на дерево */
.door__leaf::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 22%;
  background: linear-gradient(90deg, transparent, rgba(255,206,152,.10));
  pointer-events: none;
}
.door__leaf--l::after { right: 0; }
.door__leaf--r::after { left: 0; transform: scaleX(-1); }

.door__leaf--l { left: 0;  transform-origin: left center;  border-right: 1px solid rgba(0,0,0,.8); }
.door__leaf--r { right: 0; transform-origin: right center; border-left:  1px solid rgba(0,0,0,.8); }

/* утопленные филёнки — две на створку, с фаской */
.door__panel {
  position: absolute;
  left: clamp(38px, 7vw, 96px);
  right: clamp(38px, 7vw, 96px);
  background: linear-gradient(180deg, #1d1611, #120d0b);
  box-shadow:
    inset 0 2px 3px rgba(0,0,0,.85),
    inset 0 -2px 2px rgba(201,165,107,.07),
    0 1px 0 rgba(201,165,107,.06);
  border-radius: 2px;
}
.door__panel--top { top: clamp(52px, 9vh, 110px); height: 38%; }
.door__panel--bot { bottom: clamp(40px, 7vh, 84px); height: 30%; }

/* петли на внешнем краю створки */
.door__hinge {
  position: absolute;
  width: 13px;
  height: 46px;
  border-radius: 2px;
  background: linear-gradient(90deg, #6b5735, #c9a56b 45%, #6b5735);
  box-shadow: 0 1px 3px rgba(0,0,0,.7);
  opacity: .8;
}
.door__hinge--a { top: 22%; }
.door__hinge--b { bottom: 22%; }
.door__leaf--l .door__hinge { left: clamp(10px, 1.6vw, 20px); }
.door__leaf--r .door__hinge { right: clamp(10px, 1.6vw, 20px); }

/* латунная ручка-скоба у стыка */
.door__handle {
  position: absolute;
  top: 50%;
  width: 11px;
  height: 92px;
  margin-top: -46px;
  border-radius: 6px;
  background: linear-gradient(90deg, #6b5735, #f0d7a4 42%, #e6c98c 55%, #6b5735);
  box-shadow:
    0 0 18px rgba(255,206,152,.35),
    0 2px 6px rgba(0,0,0,.7),
    inset 0 1px 0 rgba(255,255,255,.35);
}
/* крепления скобы сверху и снизу */
.door__handle::before,
.door__handle::after {
  content: "";
  position: absolute;
  width: 20px;
  height: 8px;
  border-radius: 2px;
  background: linear-gradient(180deg, #c9a56b, #7a6440);
  box-shadow: 0 1px 3px rgba(0,0,0,.7);
}
.door__handle::before { top: -4px; }
.door__handle::after  { bottom: -4px; }
.door__leaf--l .door__handle { right: clamp(16px, 2.2vw, 26px); }
.door__leaf--r .door__handle { left:  clamp(16px, 2.2vw, 26px); }
.door__leaf--l .door__handle::before,
.door__leaf--l .door__handle::after { right: -4px; }
.door__leaf--r .door__handle::before,
.door__leaf--r .door__handle::after { left: -4px; }

/* латунная табличка на правой створке */
.door__brass {
  position: absolute;
  top: 26%;
  left: 50%;
  transform: translateX(-50%);
  padding: 9px 16px;
  font-family: var(--sans);
  font-size: 9px;
  line-height: 1.5;
  letter-spacing: .22em;
  text-transform: uppercase;
  text-align: center;
  color: #f0dcb4;
  background: linear-gradient(180deg, rgba(201,165,107,.24), rgba(107,87,53,.18));
  border: 1px solid rgba(201,165,107,.36);
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.14);
}
.door__brass em { font-style: normal; color: var(--warm); }

/* тёплый свет из щели */
.door__light {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  z-index: 5;
  width: 4px;
  transform: translateX(-50%);
  background: linear-gradient(180deg, transparent, var(--warm) 22%, var(--warm) 78%, transparent);
  box-shadow: 0 0 60px 18px rgba(255,206,152,.55);
  opacity: .6;
  animation: door-breathe 3.4s ease-in-out infinite;
  transition: opacity 1s ease;
}
@keyframes door-breathe {
  0%, 100% { opacity: .48; }
  50%      { opacity: .74; }
}

/* табличка на двери */
.door__plate {
  position: absolute;
  inset: 0;
  z-index: 7;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
  justify-content: center;
  text-align: center;
  transition: opacity .5s ease, transform .8s ease;
}
.door__name {
  font-family: var(--serif);
  font-size: clamp(30px, 7vw, 62px);
  line-height: .98;
  color: var(--paper);
  letter-spacing: .01em;
  text-shadow: 0 2px 34px rgba(0,0,0,.6);
}
.door__name em { color: var(--warm); font-style: italic; }
.door__enter {
  margin-top: 6px;
  padding: 10px 20px;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--brass);
  border: 1px solid rgba(201,165,107,.42);
  border-radius: 999px;
  transition: color .2s ease, border-color .2s ease;
}
.door__enter:hover { color: var(--warm); border-color: var(--warm); }

/* --- РАСПАХ ----------------------------------------------------------------
   Створки уходят внутрь и темнеют (они оказываются вне света зала), портал
   разъезжается вместе с ними, зал наезжает на зрителя — как будто мы входим. */
.door.is-open { pointer-events: none; }
.door.is-open .door__leaf--l { transform: rotateY(-104deg) translateZ(30px); filter: brightness(.35); }
.door.is-open .door__leaf--r { transform: rotateY(104deg)  translateZ(30px); filter: brightness(.35); }
.door.is-open .door__light   { opacity: 0; }
.door.is-open .door__plate   { opacity: 0; transform: scale(1.14); transition-duration: .4s; }
.door.is-open .door__lintel  { transform: translateY(-100%); transition: transform 1.5s var(--ease-cam); }
.door.is-open .door__sill    { transform: translateY(100%);  transition: transform 1.5s var(--ease-cam); }
.door.is-open .door__jamb--l { transform: translateX(-100%); transition: transform 1.5s var(--ease-cam); }
.door.is-open .door__jamb--r { transform: translateX(100%);  transition: transform 1.5s var(--ease-cam); }

/* белёсая вспышка света в момент входа — глаз привыкает к освещённому залу */
.door.is-open::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 6;
  background: radial-gradient(60% 55% at 50% 46%, rgba(255,214,166,.55), transparent 72%);
  opacity: 0;
  animation: door-flash 1.5s var(--ease-cam) forwards;
  pointer-events: none;
}
@keyframes door-flash {
  0%   { opacity: 0; }
  45%  { opacity: .9; }
  100% { opacity: 0; }
}

/* створки перестают дышать светом, как только пошёл распах */
.door.is-open .door__light { animation: none; }


/* ОБО МНЕ — короткий личный блок в мастерской */
.workshop__about {
  max-width: 760px;
  margin: 6px 0 30px;
  border-left: 2px solid rgba(201,165,107,.35);
  padding-left: 18px;
}
.workshop__about p { color: var(--paper-dim); font-size: 15px; line-height: 1.7; margin-bottom: 10px; }
.workshop__about p:last-child { margin-bottom: 0; }
.workshop__about b { color: var(--paper); font-weight: 600; }
.workshop__about-lead { font-size: 17px !important; color: var(--paper) !important; }


/* ==========================================================================
   13. ШИРОКИЕ ЭКРАНЫ И ПЛАНШЕТ (768–1319 px)
   Ряд «экран + колба + этикетка» занимает почти всю свободную ширину, и
   вводная табличка зала стоит слева от него. Как только этой ширины не
   хватает — а не хватает её уже на ноутбуке 1280 — табличка переезжает
   наверх, а ряд опускается вниз. Раньше рубеж стоял на 1199 px, и на
   типовом ноутбуке правый край этикетки срезало краем зала.
   ========================================================================== */

@media (min-width: 1600px) {
  .hall__stage { --glass-w: 380; --label-w: 224px; }
}

@media (max-width: 1439px) {
  /* строка «Залы 01—05 · 9 работ…» первой уходит из шапки: она справочная */
  .topbar__center { display: none; }
}

@media (max-width: 1319px) {
  .hall__stage {
    --glass-w: 330;
    --cases-x: clamp(20px, 14vw, 180px);
    --label-w: 206px;
  }

  .topbar__name i { display: none; }   /* подзаголовок в шапке уже не влезает */

  .plan__cap,
  .plan__tail { display: none; }       /* всю ширину отдаём комнатам */

  /* Табличка стоит в левом верхнем углу и не заходит на колбу: колба здесь
     высокая и её стеклянная крышка поднимается почти до шапки. Ширину
     считаем от места, где начинается колба, а не «на глаз». */
  .hall__intro {
    top: calc(var(--topbar-h) + 4vh);
    transform: none;
    width: min(35vw, 460px);
  }

  /* Табличка наверху — значит потолок для ряда ниже: колбе оставляем ровно
     ту высоту, что осталась между табличкой и планом этажа. Стоят экспонаты
     почти на самом плане: свободного пола тут нет, и рисовать его нечем. */
  .hall__cases {
    top: auto;
    height: 62vh;
    bottom: var(--plan-h);
    align-items: flex-end;
  }

  .hall__stage {
    --vit-w: min(clamp(180px, 27vh, 260px), 21vw);
    --stand-line: clamp(10px, 3vh, 34px);
  }

  /* Ряду здесь отведено ровно 62vh, и тумба обязана уместиться в остаток
     после колбы — иначе низ витрины уедет под план этажа. Плиту при этом
     не утончаем: видимая сверху палуба — главное, что делает тумбу тумбой,
     на ней стоит и подпятник, и пятно света. Урезаем только корпус. */
  .vitrine {
    --plinth-h: clamp(62px, 8.4vh, 96px);
    --plinth-top: clamp(22px, 2.9vh, 34px);
  }

  .hall__number { bottom: calc(var(--plan-h) + .5vh); opacity: .8; }

  .entrance__text { width: min(58vw, 520px); }

  .pricecase { width: min(46vw, 360px); }
}

@media (max-width: 1023px) {
  .hall__stage {
    --glass-w: 268;
    --cases-x: clamp(16px, 8vw, 120px);
    --label-w: 190px;
    --vit-w: min(clamp(150px, 24vh, 226px), 22vw);
    --pair-gap: clamp(18px, 4vw, 44px);   /* тумбе нужен просвет, см. выше */
  }

  .case { grid-template-columns: auto minmax(160px, var(--label-w)); column-gap: 22px; }

  /* Колонка этикетки здесь совсем узкая — пластина набирается плотнее.
     Ограничение цитаты в четыре строки задано выше, общим правилом. */
  .review { margin-top: 12px; padding: 11px 12px 10px; }
  .review__text { font-size: 13px; }

  .hall__intro .hall__text { display: none; }  /* в зале остаётся имя и предмет */

  .doorway { display: none; }

  .entrance__text {
    top: calc(var(--topbar-h) + 6vh);
    transform: none;
    width: min(68vw, 520px);
  }

  .pricecase {
    right: var(--edge);
    bottom: calc(var(--plan-h) + 3vh);
    width: min(56vw, 380px);
  }
}

/* Планшет стоймя (768×1024). Комната высокая: если прижать ряд к самому плану
   этажа, посреди зала остаётся пустая стена в треть экрана. Экспонаты
   поднимаются на полшага вперёд по полу, а табличка опускается им навстречу. */
@media (max-width: 1023px) and (orientation: portrait) {
  .hall__stage {
    --stand-line: 11vh;
    --glass-w: 268;
    --vit-w: min(clamp(170px, 21vh, 250px), 25vw);
    --cases-x: clamp(12px, 5vw, 90px);
    --label-w: 180px;
  }

  .hall__intro { top: calc(var(--topbar-h) + 9vh); }
  .hall__cases { height: 66vh; }
}

/* --------------------------------------------------------------------------
   Низкое окно (ноутбук 1366×768 — это ~625 px внутри браузера).
   Этикетка набрана плотнее: иначе её верхняя строка уезжает под шапку.
   Кегль основного текста не трогаем — режем только воздух между блоками.
   -------------------------------------------------------------------------- */
@media (max-height: 780px) {
  .label__title { font-size: clamp(18px, 1.45vw, 23px); margin-top: 10px; }
  .label__num::after { margin-top: 8px; }
  .label__variant { margin-top: 6px; }
  .label__gist { margin-top: 10px; }
  .label__material { margin-top: 11px; padding-top: 10px; }
  .label__enter { margin-top: 13px; }
  .label__link { margin-top: 10px; padding-top: 9px; }
  .label__invite { margin-top: 8px; }

  /* Отзыв набирается плотнее, но кегль цитаты не трогаем: её читают. */
  .review { margin-top: 11px; padding: 11px 12px 10px; }
  .review__text { margin-top: 7px; line-height: 1.5; }
  .review__who { margin-top: 8px; padding-top: 7px; }

  .hall__client { font-size: clamp(26px, 2.9vw, 38px); }
  .hall__text { margin-top: 12px; }
  .hall__multi { margin-top: 12px; }
}

/* Совсем низкое окно: приглашение «разберите торт на слои» — приятная,
   но не обязательная строка. Она уходит первой, чтобы кнопка и адрес
   работы остались на экране целиком. */
@media (max-height: 660px) {
  .label__invite { display: none; }
  .hall__intro .hall__text { display: none; }

  /* Совсем низкое окно: длинная цитата обрезается тремя строками, а не
     выталкивает кнопку за верх экрана. Подпись и дата остаются — отзыв
     без имени не отзыв. */
  .review__text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}


/* ==========================================================================
   14. ТЕЛЕФОН (до 767 px)
   Главный сценарий: ссылка из Телеграма. Живых сайтов в витринах здесь нет —
   museum.js их не создаёт, в стекле лежит снимок. Сцена перестаёт прилипать
   и становится обычной вертикальной лентой: одна витрина на экран.
   ========================================================================== */

/* Телефон И планшет стоймя. Планшет добавлен 2026-08-23: на нём оставалась
   «взрослая» раскладка со сценой, но ширины не хватало — этикетка сжималась
   до колонки в 180 px, текст сыпался лесенкой по два слова, а содержимое
   не влезало в прилипающий экран и обрезалось сверху. Лента решает всё это
   разом. Поправки на размер планшета — в assets/css/tablet.css. */
@media (max-width: 767px), (max-width: 1023px) and (orientation: portrait) {

  body { --edge: 18px; --plan-h: 78px; }

  /* --- шапка --- */
  /* Фон почти непрозрачный: на телефоне под шапкой всё время едет текст,
     и сквозь прежний полупрозрачный градиент читались чужие строки. */
  .topbar {
    height: 52px;
    padding: 0 var(--edge);
    gap: 10px;
    /* Сплошной фон, а не градиент: под шапкой всё время едет текст, и через
       полупрозрачный низ читались чужие строки — выглядело как наложение. */
    background: #07060a;
    box-shadow: 0 10px 18px rgba(7, 6, 10, .9);
    border-bottom: 1px solid rgba(201, 165, 107, .16);
  }

  .topbar__center { display: none; }
  .topbar__name i { display: none; }

  /* В шапке остаётся только имя: приписка «· веб-разработчик» лежит в
     разметке отдельным куском текста, спрятать её можно лишь так —
     обнулив кегль у контейнера и вернув его тегу <b>. */
  .topbar__name { font-size: 0; letter-spacing: 0; }
  .topbar__name b { font-size: 12px; letter-spacing: .16em; }

  .topbar__tg {
    padding: 10px 12px;
    font-size: 10px;
    letter-spacing: .1em;
  }

  .topbar__tg span { display: none; }   /* ник не влезает, ссылка остаётся живой */

  /* --- вход: обычная лента, декорации остаются фоном --- */
  /* Нижний отступ больше плана этажа: план висит поверх страницы, и без
     запаса последняя строка ценника пряталась бы под ним. */
  .entrance {
    height: auto;
    min-height: 0;
    padding: calc(52px + 24px) var(--edge) 46px;
  }

  .entrance__stage {
    position: static;
    display: flex;
    flex-direction: column;
    gap: 30px;
  }

  .entrance__text,
  .pricecase {
    position: static;
    transform: none;
    width: 100%;
    max-width: none;
  }

  .entrance__title { font-size: clamp(34px, 11vw, 48px); }
  .entrance__lead  { font-size: 15px; }

  /* ценник лежит под стеклом чуть косо — на узком экране угол убираем,
     иначе он упирается в рамку витрины */
  .pricecase__glass { flex-direction: column; gap: 14px; }
  .pricecase__ticket { transform: rotate(-1deg); margin: 4px 6px; }
  .pricecase__label { flex: 0 0 auto; }

  .doorway,
  .beam,
  .hall__rail,
  .hall__skirting { display: none; }

  /* фоновая архитектура на телефоне упрощена: стена во всю секцию, пола нет */
  .hall__wall {
    inset: 0;
    background:
      radial-gradient(120% 60% at 50% 0%, var(--hall-glow), transparent 70%),
      linear-gradient(180deg, #171310 0%, #0f0c0b 60%, var(--ink) 100%);
  }

  .hall__floor { display: none; }

  .entrance .dust,
  .hall .dust {
    left: 0; right: 0;
    top: 0;
    width: 100%;
    height: 42vh;
    opacity: .5;
  }

  .entrance__stage::after,
  .hall__stage::after { display: none; }   /* виньетка на маленьком экране только мешает */

  /* --- зал: лента, а не прилипающая сцена --- */
  .hall,
  .hall--single {          /* !важно: без второго селектора зал в один экран */
    height: auto;          /* держал бы 100vh, и лента залезала бы на соседний */
    padding: 42px 0 10px;
  }

  .hall__stage {
    position: static;
    height: auto;
    overflow: visible;
    display: flex;
    flex-direction: column;
    gap: 26px;
    padding: 0 var(--edge);
  }

  .hall__intro {
    position: static;
    transform: none;
    width: 100%;
  }

  .hall__intro .hall__text { display: block; font-size: 14px; }

  .hall__number {
    position: static;
    transform: none;
    text-align: left;
    font-size: 11px;
    letter-spacing: .3em;
    color: rgba(255, 214, 168, .4);
  }

  /* Камеры тут нет: ряд витрин разворачивается в столбик.
     !important — страховка от инлайнового transform, если хореограф
     всё-таки запустит движение на узком экране. */
  /* Направление колонки меняет смысл align-items: flex-end прижал бы витрины
     к правому краю. В ленте они тянутся во всю ширину. */
  .hall__cases {
    position: static;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 40px;
    padding-right: 0;
    padding-bottom: 0;
    transform: none !important;
    will-change: auto;

    /* Высоту обязательно сбросить: в блоке до 1023 px ряду задана высота
       в долях экрана (66vh) под горизонтальную камеру. На телефоне камеры
       нет, витрины стоят столбиком и в эту высоту не влезают — контейнер
       остаётся низким, а витрины вылезают и наезжают на соседние тексты.
       Ровно это и выглядело как «с мобильной версией очень плохо». */
    height: auto;
    min-height: 0;
  }

  /* --- витрина на телефоне: колба, под ней экран, под ним этикетка --- */
  .case {
    grid-template-columns: 1fr;
    grid-template-areas:
      "pair"
      "label";
    width: 100%;
  }

  /* пара разворачивается в столбик: сверху колба, под ней экран.
     column (а не column-reverse) — в разметке колба идёт первой */
  .case__pair {
    flex-direction: column;
    align-items: stretch;
    gap: 26px;
  }

  .vitrine {
    width: min(62%, 230px);
    align-self: center;
  }

  /* Тумба на телефоне ниже и уже: колба тут занимает больше половины
     ширины экрана, и тумба «в натуральную величину» съедала бы полэкрана.
     Плита остаётся толстой — иначе палуба снова схлопывается в тёмную
     полосу, из-за которой всё и переделывалось. Свес 15% проверен на 320 px:
     горизонтальной прокрутки не появляется. */
  .vitrine {
    --plinth-h: 62px;
    --plinth-top: 19px;
    --plinth-out: 15%;
  }

  .vitrine__no { bottom: 18%; padding: 3px 13px; }

  /* пола под колбой на телефоне нет — отражению не на чем быть */
  .vitrine__mirror { display: none; }

  /* ...а значит нет и отражённого света: блик на столешнице зажигаем сразу,
     камеры на телефоне не существует, зажигать его нечем */
  .vitrine::before { opacity: .8; }

  .screen { width: 100%; }

  .case__glass {
    width: 100%;
    /* свет включён сразу: подводить камеру нечем, а работу видеть надо */
  }

  /* Камеры на телефоне нет — подводить свет нечем, поэтому работа освещена
     сразу и настолько, насколько позволяет её собственный тон. */
  .case__glass::before,
  .case:hover .case__glass::before { opacity: var(--veil-lit, .1); }
  .case__glass::after { opacity: .5; }
  .case__sleep { display: none; }

  .label {
    margin-top: 26px;
    padding-left: 14px;
  }

  .label__gist { font-size: 14px; }
  .label__material { font-size: 11.5px; }
  .label__invite { font-size: 13px; }

  /* Отзыв встаёт в ленту после этикетки. Кегль цитаты — 15 px: на телефоне
     её читают с вытянутой руки, мельче 14 px тут запрещено. */
  .review { margin-top: 20px; padding: 15px 15px 14px; }
  .review__text { font-size: 15px; line-height: 1.62; }
  .review__who { font-size: 12px; }
  .review__date { font-size: 11px; }
  .review::after { font-size: 34px; top: 18px; }
  .label__enter { min-height: 48px; }
  .label__link { min-height: 44px; padding-top: 14px; }

  /* --- мастерская и финал --- */
  .workshop { padding: 56px var(--edge); }
  .workshop__cols { grid-template-columns: 1fr; gap: 34px; }
  .btn--tg { max-width: none; }

  .finale { padding: 56px var(--edge) calc(var(--plan-h) + 48px); }
  .finale__grid { grid-template-columns: 1fr; }

  .emptycase {
    grid-template-columns: 1fr;
    gap: 22px;
  }

  .emptycase .btn--big { width: 100%; }

  /* --- план этажа: лента вдоль нижнего края, листается пальцем --- */
  .plan {
    height: auto;
    min-height: var(--plan-h);
    padding: 8px 0 calc(8px + env(safe-area-inset-bottom, 0px));
    gap: 0;
  }

  .plan__cap,
  .plan__tail { display: none; }

  .plan__list {
    gap: 8px;
    padding: 0 var(--edge);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .plan__list::-webkit-scrollbar { display: none; }

  .plan__item {
    flex: 0 0 auto;
    width: 148px;
    scroll-snap-align: start;
  }

  .plan__item button {
    min-height: 52px;
    border: 1px solid var(--hair);
    border-radius: 2px;
  }

  .plan__item:last-child button { border-right: 1px solid var(--hair); }

  .plan__item.is-current::before,
  .plan__item.is-current::after { display: none; }

  .plan__item.is-current button {
    border-color: rgba(255, 214, 168, .75);
    background: rgba(255, 205, 150, .12);
  }

  /* --- окно просмотра --- */
  .viewer__bar {
    flex-wrap: wrap;
    padding: 8px var(--edge);
  }

  .viewer__title { flex: 1 0 100%; font-size: 16px; }
}

/* совсем узкие экраны (320 px): ничего не должно вылезать за край */
@media (max-width: 359px) {
  body { --edge: 14px; }

  .topbar__name b { font-size: 10px; }
  .plan__item { width: 132px; }
  .entrance__title { font-size: 32px; }
}


/* ==========================================================================
   15. КОМУ ДВИЖЕНИЕ МЕШАЕТ
   base.css уже гасит анимации; здесь добиваем свет — музей должен быть
   освещён и без единого кадра движения.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .lamp::after {
    background: var(--hall-light, var(--warm));
    box-shadow: 0 0 14px 5px rgba(255, 205, 150, .5);
  }

  .lamp::before { opacity: 1; }

  .case__glass::before { opacity: var(--veil-lit, .1); }
  .case__sleep { display: none; }
  .label { opacity: 1; }

  /* колба тоже под полным светом, а предмет не парит — просто стоит */
  .vitrine__pool   { opacity: 1; }
  .vitrine__mirror { opacity: 1; }
  .vitrine::before { opacity: 1; }   /* блик на столешнице горит без движения */
  .vitrine__object { opacity: 1; animation: none; }
  .vitrine__shadow { animation: none; }

  /* Раскладка тоже меняется, а не только свет. Камеры и прилипания нет —
     значит сцена не может остаться абсолютной, иначе зал схлопнется
     в нулевую высоту и исчезнет. Строим ту же ленту, что на телефоне. */
  .hall,
  .hall--single,          /* иначе зал в один экран держит 100vh и наезжает */
  .entrance {
    height: auto;
    padding-bottom: 40px;
  }

  .hall__stage,
  .entrance__stage {
    position: static;
    height: auto;
    overflow: visible;
    display: flex;
    flex-direction: column;
    gap: 30px;
    padding: 60px var(--edge);
  }

  .hall__intro,
  .hall__number,
  .entrance__text,
  .pricecase {
    position: static;
    transform: none;
    width: 100%;
    max-width: 900px;
  }

  .hall__cases {
    position: static;
    display: flex;
    flex-direction: column;
    align-items: flex-start;   /* колонка: flex-end увёл бы витрины вправо */
    gap: 48px;
    padding-right: 0;
    padding-bottom: 0;
    transform: none !important;
  }

  .hall__wall,
  .hall__floor { inset: 0; }

  .doorway,
  .beam,
  .dust { display: none; }   /* декорации, которые держались на движении */
}
