/* ============================================================
   СМОТРИТЕЛЬ — фигура-проводник в углу зала.
   Разметку, фигуру и реплики строит assets/js/guide.js; здесь
   только вид и движение. Файл ничего не знает про залы: он
   оформляет один элемент .guide, который лежит поверх музея и
   никогда не участвует в раскладке страницы.

   Три правила, из-за которых тут всё именно так:

   • Ни filter, ни backdrop-filter. Музей чинили от рывков, и
     размытие поверх ЕДУЩЕГО зала — самое дорогое, что бывает:
     браузер пересчитывает его каждый кадр прокрутки. Мягкость
     здесь набрана градиентами и прозрачностью, а не размытием.

   • Двигаются только transform и opacity. Их браузер отдаёт
     видеокарте и не трогает раскладку. Поставишь сюда анимацию
     left/width/box-shadow — вернутся те самые рывки.

   • Контейнер прозрачен для мыши (pointer-events: none), нажатия
     ловят только кнопки и сама плашка с репликой. Иначе фигура
     в углу перехватывала бы клики по витрине под собой, а витрина
     в этом музее — главное, ради чего человек пришёл.
   ============================================================ */

.guide {
  position: fixed;
  left: clamp(12px, 2.2vw, 28px);
  /* Смотритель стоит НАД кнопкой связи, а не рядом с ней. Первый вариант
     ставил его в тот же нижний левый угол, и на снимке фигура легла прямо
     на заголовок зала и на кнопку «написать» — два разных обращения к
     человеку в одной точке экрана. Считаем от пола: полоса плана этажа
     (--plan-h), над ней кнопка связи (её высота с отступом ~62 px), и уже
     над ними смотритель. */
  /* Поднят ещё выше после проверки на живой странице: на уровне кнопки
     связи фигура ложилась прямо на крупный заголовок зала. Здесь, на
     высоте пола комнаты, слева пусто в каждом зале — смотритель стоит
     в помещении, а не поверх подписей. */
  bottom: calc(var(--plan-h) + 168px);
  /* Выше плавающей кнопки связи (40), но ниже окна просмотра работы
     (100) и входной двери (200): пока человек смотрит чужой сайт во
     весь экран, смотрителю там делать нечего. */
  z-index: 45;
  display: flex;
  align-items: flex-end;      /* фигура и плашка стоят на одной линии пола */
  gap: 12px;
  max-width: min(430px, 44vw);
  pointer-events: none;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s ease, transform .7s var(--ease-cam);
}

/* Появление: не «включился», а вышел из темноты зала. */
.guide.is-shown { opacity: 1; transform: none; }

/* Уход по кнопке «отключить»: отступает влево, за край кадра.
   Сам элемент убирает JS после того, как переход доиграет. */
.guide.is-gone {
  opacity: 0;
  transform: translateX(-26px);
  transition-duration: .5s;
}

/* Пока открыт просмотр работы во весь экран — смотритель отходит.
   Скрываем прозрачностью, а не display:none: элемент с aria-live
   должен оставаться в дереве, иначе следующая реплика не прозвучит
   для программы чтения с экрана. */
body.is-viewing .guide { opacity: 0; pointer-events: none; }

/* Запасная посадка. Полоса плана этажа в этом музее сейчас едет
   вместе со страницей, а не прибита к низу экрана, поэтому нижний
   угол свободен. Если план когда-нибудь снова станет фиксированным,
   guide.js это заметит и поднимет смотрителя над ним и над круглой
   кнопкой связи — иначе фигура окажется наполовину под панелью. */
.guide.is-above-plan { bottom: calc(var(--plan-h) + 168px); }
/* 168, а не 88: на 88 фигура вставала вровень с кнопкой связи и ложилась
   на крупный заголовок зала — проверено снимком живой страницы. На этой
   высоте она стоит на полу комнаты, где слева пусто в каждом зале. */

/* --- фигура --------------------------------------------------------- */

.guide__stand {
  position: relative;
  flex: 0 0 auto;
  width: clamp(58px, 5.4vw, 76px);
}

/* Фигура — настоящая кнопка: нажатие повторяет последнюю реплику.
   Так до неё добираются и с клавиатуры, и пальцем, а не только
   те, кто успел прочитать плашку до того, как она погасла. */
.guide__body {
  display: block;
  width: 100%;
  padding: 0;
  pointer-events: auto;
  border-radius: 4px;
}

.guide__fig { display: block; width: 100%; height: auto; }

/* Пятно тёплого света под ногами — рисуется градиентом, не тенью:
   тень пришлось бы анимировать, а это перерисовка. */
.guide__glow {
  position: absolute;
  left: 50%;
  bottom: -4%;
  width: 210%;
  height: 66%;
  translate: -50% 0;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(255, 215, 160, .20), rgba(255, 215, 160, 0) 70%);
  opacity: 0;
  transition: opacity .5s ease;
  pointer-events: none;
}
.guide.is-talking .guide__glow { opacity: 1; }

/* --- кнопка «отключить смотрителя» ---------------------------------- */

/* Зона нажатия честные 44×44, хотя кружок видно на 22: на телефоне
   в мелкий крестик не попасть, а отключение — единственный способ
   от смотрителя избавиться, промахиваться тут нельзя. */
.guide__off {
  position: absolute;
  top: -30px;
  left: 50%;
  width: 44px;
  height: 44px;
  margin-left: -22px;
  display: grid;
  place-items: center;
  pointer-events: auto;
  opacity: .4;
  transition: opacity .3s ease;
}
.guide:hover .guide__off,
.guide__off:hover,
.guide__off:focus-visible { opacity: 1; }

.guide__off::before {
  content: "";
  position: absolute;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid rgba(201, 165, 107, .55);
  background: rgba(10, 8, 7, .88);
}
.guide__off span {
  position: relative;
  font-size: 13px;
  line-height: 1;
  color: var(--brass);
}

/* Где нет наведения (телефон, планшет) — кнопка видна сразу:
   иначе про неё узнают только те, кто случайно ткнул. */
@media (hover: none) {
  .guide__off { opacity: .8; }
}

/* --- плашка с репликой ---------------------------------------------- */

.guide__say {
  position: relative;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 320px;
  padding: 11px 15px 13px;
  border: 1px solid rgba(201, 165, 107, .30);
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(28, 21, 17, .97), rgba(14, 11, 10, .97));
  box-shadow: 0 16px 38px rgba(0, 0, 0, .55);
  pointer-events: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  /* visibility переключается с задержкой РОВНО в длину затухания:
     пока плашка тает, её ещё можно выделить мышью, а как погасла —
     она уходит и из дерева доступности, и из-под курсора. */
  transition: opacity .45s ease, transform .45s var(--ease-cam), visibility 0s .45s;
}

.guide.is-talking .guide__say {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .45s ease, transform .45s var(--ease-cam), visibility 0s 0s;
}

/* Хвостик к фигуре: повёрнутый квадрат с двумя гранями — так он
   продолжает рамку плашки, а не лежит на ней заплаткой. */
.guide__say::before {
  content: "";
  position: absolute;
  left: -5px;
  bottom: 24px;
  width: 9px;
  height: 9px;
  background: rgba(20, 15, 13, .97);
  border-left: 1px solid rgba(201, 165, 107, .30);
  border-bottom: 1px solid rgba(201, 165, 107, .30);
  transform: rotate(45deg);
}

/* Подпись «смотритель» — служебная строка музея, как на табличках.
   Она же отличает его голос от «От меня»: там говорит автор. */
.guide__cap {
  font-family: var(--sans);
  font-size: 9.5px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 5px;
}

.guide__text {
  font-family: var(--sans);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--paper);          /* контраст к фону плашки — около 12:1 */
}

/* --- жизнь фигуры ---------------------------------------------------
   Дыхание и поворот головы намеренно на грани заметности: смотритель
   должен читаться живым краем глаза, а не тянуть взгляд с экспоната.
   Циклы длинные и разной длины (5,4 с и 11 с), чтобы движения не
   складывались в механический такт. */

.guide__breath {
  transform-box: fill-box;      /* без этой строки SVG считает начало
                                   координат от угла всего холста, и
                                   фигура при вдохе уезжает вбок */
  transform-origin: 50% 100%;
  animation: guide-breath 5.4s ease-in-out infinite;
}

.guide__head {
  transform-box: fill-box;
  transform-origin: 50% 96%;    /* поворот от шеи, а не от макушки */
  animation: guide-turn 11s ease-in-out infinite;
}

@keyframes guide-breath {
  0%, 100% { transform: scaleY(1); }
  50%      { transform: scaleY(1.016); }
}

@keyframes guide-turn {
  0%, 38%   { transform: rotate(0deg); }
  48%, 62%  { transform: rotate(-3deg); }
  76%, 100% { transform: rotate(0deg); }
}

/* Кивок в начале реплики: короткий, один раз. На это время он
   перебивает медленный поворот головы — двум анимациям на одном
   свойстве не ужиться, и кивок как более важный побеждает. */
.guide.is-nod .guide__head { animation: guide-nod .9s ease-in-out; }

@keyframes guide-nod {
  0%   { transform: translateY(0) rotate(0deg); }
  35%  { transform: translateY(1.8px) rotate(-2.4deg); }
  70%  { transform: translateY(0) rotate(1deg); }
  100% { transform: translateY(0) rotate(0deg); }
}

/* --- телефон --------------------------------------------------------
   На узком экране музей идёт лентой, и любой угол — это чей-то текст.
   Поэтому смотритель ужимается вдвое, плашка не шире двух третей
   экрана, а появляется он у самого низа, где лежит пол кадра. */
@media (max-width: 767px) {
  .guide {
    left: 10px;
    bottom: 12px;
    gap: 8px;
    max-width: calc(100vw - 20px);
  }
  .guide__stand { width: 46px; }
  .guide__say {
    max-width: min(64vw, 250px);
    padding: 9px 12px 10px;
    border-radius: 2px;
  }
  .guide__text { font-size: 12.5px; line-height: 1.45; }
  .guide__cap { font-size: 9px; letter-spacing: .2em; margin-bottom: 3px; }
  .guide__off { top: -26px; }
  .guide.is-above-plan { bottom: calc(var(--plan-h) + 96px); }   /* на телефоне заголовок ниже, хватает меньшего запаса */
}

/* Совсем тесно — смотрителя нет вовсе. Честнее убрать проводника,
   чем закрыть им половину экспоната: на 320 px фигура с плашкой
   занимает треть кадра, а музей тут и так впритык.
   display:none, а не opacity: невидимый, но живой элемент всё равно
   ловил бы фокус с клавиатуры и зачитывался бы вслух. */
@media (max-width: 379px), (max-height: 559px) {
  .guide { display: none; }
}

/* --- «поменьше движения» --------------------------------------------
   base.css глушит все анимации глобально, здесь дописано явно: не
   полагаться на чужой !important, если его однажды уберут. Смотритель
   при этом не исчезает — он просто стоит неподвижно и говорит. */
@media (prefers-reduced-motion: reduce) {
  .guide { transition: opacity .2s linear; transform: none; }
  .guide.is-shown, .guide.is-gone { transform: none; }
  .guide__say { transition: opacity .2s linear, visibility 0s .2s; transform: none; }
  .guide.is-talking .guide__say { transform: none; }
  .guide__breath, .guide__head, .guide.is-nod .guide__head { animation: none; }
}
