/* СлайдПро — вьюер-бандл: главная (вход по коду) + комната зрителя.
   Вёрстка 1:1 с прототипом «Комната зрителя» (design/handoff). */

* { box-sizing: border-box; }

/* Видно только скринридеру. Тот же приём уже стоял инлайном на #sr в /p/index.html —
   вынесен в класс, чтобы заголовки и подписи не тащили за собой стилевую простыню. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text-primary);
  font-family: var(--font-ui);
  overscroll-behavior: none;
}

a { color: var(--link); text-decoration: none; }

/* ---------- Главная: вход по коду ---------- */

.home {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 0 24px 120px;
  cursor: text;
}

.home__logo {
  position: relative;   /* база для зоны нажатия ::after */
  font-family: var(--font-ui);
  font-size: 34px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .01em;
  color: var(--text-primary);
  cursor: pointer;   /* .home задаёт cursor:text, а вордмарк теперь ссылка */
}

/* Вордмарк стал ссылкой на /lp/ — до этого с главной не было ни одного выхода наружу
   (аудит связанности §3.4). Зона нажатия добирается до 48px псевдоэлементом, а не
   паддингом: паддинг раздвинул бы центрированную колонку (UX-PLAN §0.5). */
.home__logo::after { content: ''; position: absolute; inset: -7px -12px; }

.home__logo b { color: var(--accent); font-weight: 700; }

.home__hint { font-size: 16px; color: var(--text-secondary); min-height: 24px; }
.home__hint--err { color: var(--danger); font-weight: 600; }

/* Ряд из четырёх ячеек был жёстким: 4×64 + 3×12 = 292px. При увеличении до 200%
   это 584 физических пикселя — на телефоне видны две цифры, остальные две надо
   помнить, пока рассматриваешь первые. А это ровно тот человек, которому увеличение
   и понадобилось. Ячейки теперь ужимаются вместе с доступной шириной. */
.cells { display: flex; gap: clamp(6px, 2vw, 12px); max-width: 100%; }

.cells--shake { animation: shake .3s; }
@keyframes shake {
  20% { transform: translateX(-7px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(3px); }
}

.cell {
  width: clamp(48px, 15vw, 64px);
  height: clamp(56px, 17vw, 72px);
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1.5px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 clamp(30px, 10vw, 44px)/1 var(--font-mono);
  color: var(--text-primary);
}

.cell--err { border-color: var(--danger); }
.cell--mut { opacity: .55; }

.caret {
  width: 2px;
  height: 44px;
  background: var(--accent);
  border-radius: 2px;
  animation: blink 1s steps(2) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

.spin {
  width: 22px;
  height: 22px;
  border: 3px solid var(--accent);
  border-right-color: transparent;
  border-radius: var(--r-full);
  animation: rot 1s linear infinite;
}
@keyframes rot { to { transform: rotate(360deg); } }

.home__input { position: absolute; opacity: 0; width: 1px; height: 1px; font-size: 16px; }  /* 16px — iOS не зумит при фокусе */

.home__foot {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  padding: 16px 24px calc(24px + var(--sab));
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
}

.home__guide {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Вход гида — действие «аккаунтное», а не уличное: главное на этом экране — код.
     Отсюда шкала md контракта §2 вместо прежних 48/12/16, набранных на глаз. */
  height: var(--btn-h-md);
  padding: 0 20px;
  border-radius: var(--btn-r-md);
  font-size: var(--btn-fs-md);
  font-weight: 600;
  color: var(--text-secondary);
}
.home__guide:hover { color: var(--text-primary); }

/* Две мелкие ссылки одной строкой, пока хватает ширины (≈430 и шире), дальше честный
   перенос. Замерено на 430/375/360/320: даже в перенесённом виде футер не достаёт до
   ячеек кода, поэтому отдельная media-точка не нужна. */
.home__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.home__what,
.home__legal { font-size: 15px; display: inline-flex; align-items: center; min-height: var(--btn-h-md); padding: 4px 12px; }  /* 48 по контракту §2, а не 44 «на глаз» */
/* Правовая ссылка тише пригласительной: обязательство должно быть достижимо, но
   не конкурировать с «Что такое СлайдПро?» за внимание туриста. */
.home__legal { color: var(--text-secondary); }
.home__legal:hover { color: var(--link); text-decoration: underline; }

/* ---------- Комната зрителя ---------- */

.stage {
  position: fixed;
  inset: 0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  overflow: hidden;
}

.zoomw { position: absolute; inset: 0; transition: transform var(--ease), filter 300ms; }
.zoomw--drag { transition: filter 300ms; }
.zoomw--blur { filter: blur(6px); }

.lay { position: absolute; inset: 0; opacity: 0; transition: opacity var(--ease); }
.lay--on { opacity: 1; }

.lay__img {
  position: absolute;
  inset: 0;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}

/* Текст-карточка приходит с сервера картинкой; локальный рендер — только демо-режим */
.lay__text {
  position: absolute;
  inset: 0;
  background: #1C1A17;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px 28px;
  text-align: center;
  font-size: 34px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-primary);
}

.grad {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 92px;
  background: linear-gradient(rgba(0, 0, 0, .6), transparent);
  opacity: 0;
  transition: opacity var(--ease);
  pointer-events: none;
}
.grad--on { opacity: 1; }

/* Счётчик слайдов НАМЕРЕННО оставлен вне шкалы бейджей, хотя сидит с бейджем в одном
   ряду и тоже похож на статус. Это не статус, а голосовой фолбэк (§4.Д дизайн-дока):
   гид называет номер вслух — «смотрим четвёртый», — и зритель должен найти его на
   своём экране мгновенно, с вытянутой руки. Поэтому кегль 20 моноширинным с табличными
   цифрами: он крупнее любой ступени бейджа и не должен ехать вместе с ней. Высота 32
   здесь тоже не --badge-h-md, а просто пилюля под этот кегль: совпадение чисел
   случайно, связывать их токеном значило бы обещать зависимость, которой нет. */
.counter {
  position: fixed;
  top: calc(10px + var(--sat)); left: calc(12px + var(--sal));
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--r-full);
  background: var(--pill);
  color: var(--text-primary);
  font: 600 20px var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  pointer-events: none;
  z-index: 6;   /* инвариант «счётчик виден всегда»: выше бейджа (z:5) */
  /* На 320px «200/200» и «Загружаем · 100%» сходились в пару пикселей: оба элемента
     позиционируются от своих краёв и о существовании друг друга не знают. Раньше
     спасал только z-index — счётчик перекрывал статус. Ограничиваем ширину каждого
     примерно половиной экрана, чтобы длинный текст ужимался, а не наезжал. */
  max-width: calc(50% - 16px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.thin {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  background: var(--accent);
  border-radius: 0 2px 2px 0;
  pointer-events: none;
  transition: width 300ms linear;
  z-index: 6;
}

.capbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--overlay);
  color: var(--text-primary);
  font-size: 18px;
  line-height: 1.35;
  padding: 12px 16px calc(12px + var(--sab));
  /* pointer-events: none — чтобы тап по нижней части кадра листал слайд, а не «залипал»
     в подписи. Но рядом стоял overflow-y: auto, и это было противоречие: полоса
     объявлена прокручиваемой и при этом не принимает ни одного касания. На телефоне
     в горизонтальной ориентации 30vh — около трёх строк; историческая подпись на
     5–8 строк молча обрезалась, а попытка её прокрутить уходила в кадр под ней и
     читалась как листание. Класс --scroll ставит скрипт, когда текст ДЕЙСТВИТЕЛЬНО
     не поместился: только тогда полоса начинает принимать касание. */
  pointer-events: none;
  transition: bottom var(--ease);
  max-height: 30vh;
  overflow: hidden;
  z-index: 4;
}
.capbar--scroll {
  pointer-events: auto;
  overflow-y: auto;
  overscroll-behavior: contain;   /* прокрутка подписи не тянет за собой страницу */
  -webkit-overflow-scrolling: touch;
}

.btn-accent {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  /* Основное действие в финале занятия. */
  height: var(--btn-h-lg);
  min-width: 160px;
  padding: 0 20px;
  border-radius: var(--btn-r-lg);
  font-size: var(--btn-fs-lg);
  font-weight: 600;
  font-family: inherit;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  cursor: pointer;
}
.btn-accent:hover { background: var(--accent-hover); }

/* Вторичное действие финала: тот же уличный рост (≥56 — экран читают стоя, на солнце,
   иногда в перчатках), но контуром — «Листать слайды» остаётся главным. */
.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: var(--btn-h-lg); min-width: 160px; padding: 0 20px; margin-top: 10px;
  border-radius: var(--btn-r-lg);
  font-size: var(--btn-fs-lg); font-weight: 600; font-family: inherit;
  background: transparent; color: var(--accent);
  border: 1.5px solid var(--accent); cursor: pointer;
}
.btn-ghost:hover { background: var(--accent); color: #101010; }
.btn-ghost:active { transform: scale(.98); }

.toast {
  position: fixed;
  left: calc(12px + var(--sal)); right: calc(12px + var(--sar));
  bottom: calc(88px + var(--sab));
  background: var(--surface-raised);
  color: var(--text-primary);
  border-radius: var(--r-card);
  padding: 13px 16px;
  font-size: 16px;   /* показ ≥16 (было 15) */
  line-height: 1.45;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .55);
  display: flex;
  gap: 10px;
  align-items: flex-start;
  pointer-events: none;

  z-index: 8;
}

.toast__ic { flex: none; margin-top: 1px; }
.toast__ic--suc { color: var(--success); }

/* Ожидание и сувенир */

.waitcol {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  gap: 16px;
  padding: calc(24px + var(--sat)) max(24px, var(--sar)) calc(24px + var(--sab)) max(24px, var(--sal));
  text-align: center;
  overflow-y: auto;
}
.waitcol > * { flex-shrink: 0; max-width: 100%; overflow-wrap: anywhere; }

.waitcol__cover {
  width: 62%;
  max-width: var(--w-form);
  aspect-ratio: 16 / 9;
  max-height: 220px;
  border-radius: var(--r-modal);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .6);
  background-size: cover;
  background-position: center;
}

.waitcol__title { font-size: 20px; font-weight: 600; margin: 0; }
.waitcol__sub { font-size: 16px; color: var(--text-secondary); margin: 0; line-height: 1.5; }
/* Подтверждение связи в момент неопределённости (zero-risk 86 + ambiguity 93). */
.wait-ok { color: var(--success); font-weight: 600; }

.souvenir {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  padding: 16px 16px calc(16px + var(--sab));
  display: flex;
  flex-direction: column;
  gap: 8px;   /* ≥8px между таргетами (было 4) */
  align-items: center;
  border-top: 1px solid var(--border);
  background: var(--surface);
}

/* «Собрано в СлайдПро» и правовая ссылка — одной строкой, пока хватает ширины; на узком
   экране переносятся. Высота футера от этого прыгает, поэтому место под него финальный
   экран резервирует не константой, а замером — см. render() в viewer.js. */
.souvenir__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.souvenir__link {
  font-size: 16px; font-weight: 700; color: var(--accent);   /* показ ≥16 (было 15) */
  display: inline-flex; align-items: center; min-height: 48px; padding: 4px 8px;   /* таргет ≥48 */
}
.souvenir__link:hover { color: var(--text-primary); }

/* Единственный выход к обязательствам сервиса со стороны зрителя: он не регистрировался,
   но фото и подписи ему уже показали (аудит §3.4). Тон приглушённый — это не действие. */
.souvenir__legal {
  font-size: 16px; color: var(--text-secondary);   /* показ ≥16 */
  display: inline-flex; align-items: center; min-height: 48px; padding: 4px 8px;   /* таргет ≥48 */
}
.souvenir__legal:hover { color: var(--accent); }
/* Пик-энд + органический рост: тёплый зритель — лучший лид в гиды (§4.Г). */
.souvenir__invite {
  font-size: 16px;   /* показ ≥16 (было 13) */
  font-weight: 600;
  color: var(--text-secondary);
  text-decoration: none;
  display: inline-flex; align-items: center; min-height: 48px; padding: 4px 8px;   /* таргет ≥48 */
}
.souvenir__invite:hover { color: var(--accent); }

.hidden { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  .lay, .zoomw, .capbar, .grad, .thin { transition: none; }
  /* .gspin — спиннер страницы /g/{код}. Он крутился вопреки запрету движения
     именно там, где ждать можно ЧАСАМИ: человек заранее открыл ссылку из чата
     и ждёт начала экскурсии. Правило гасило .spin, но про близнеца забыли. */
  .gspin { animation: none; }
  /* Полный сброс: не только переходы, но и бесконечные анимации (спиннер, каретка,
     тост, шейк) — для вестибулярно-чувствительных (X2 P2-6). */
  .toast, .cells--shake, .spin, .caret { animation: none; }
  .caret { opacity: 1; }
}

/* Шесть цифр на телефоне и отдельный экран проектора. */
.cells{gap:8px}.cell{width:clamp(36px,12vw,56px)}
.projector #reattach,.projector #souvenir-foot{display:none!important}
.projector .lay__img{background-size:contain}
.projector #browse-btn, .projector #keep-btn {display:none;}

/* Финал и его ссылки прокручиваются вместе: футер не закрывает кнопки
   на коротком экране, резервировать его высоту скриптом не требуется. */
.viewer-end { position:fixed; inset:0; height:100dvh; overflow-y:auto; display:flex; flex-direction:column; }
.viewer-end .waitcol { position:static; overflow:visible; flex:none; margin:auto 0; padding-bottom:24px; }
.viewer-end .souvenir { position:static; flex:none; padding-left:max(16px,var(--sal)); padding-right:max(16px,var(--sar)); text-align:center; }
.capbar { padding-left:max(16px,var(--sal)); padding-right:max(16px,var(--sar)); overflow-wrap:anywhere; }
.counter { max-width:calc(45% - 16px - var(--sal)); }
.stage { inset:var(--sat) var(--sar) var(--sab) var(--sal); }
.waitcol__cover:not([style*="background-image"]) { display:none; }
@media(max-width:380px) {
  .counter { max-width:calc(100% - 24px - var(--sal) - var(--sar)); }
}
@media(orientation:landscape) and (max-height:560px) {
  .waitcol__cover { width:180px; max-height:100px; }
  .waitcol { gap:12px; }
  .viewer-end .waitcol { display:grid; grid-template-columns:minmax(100px,180px) minmax(0,420px); justify-content:center; align-items:center; gap:12px 24px; }
  .viewer-end .waitcol__cover { grid-row:1/5; width:100%; max-height:none; }
  .viewer-end .waitcol > :not(.waitcol__cover) { grid-column:2; }
  .viewer-end .btn-ghost { margin:0; }
  .viewer-end .waitcol:not(:has(.waitcol__cover[style*="background-image"])) { display:flex; }
}

/* Компактные кнопки поверх слайда: без нижней панели и стрелок листания. */
.viewer-controls {
  position: fixed; right: calc(12px + var(--sar)); bottom: calc(12px + var(--sab));
  display: flex; align-items: center; gap: 8px; z-index: 7;
}
.viewer-control {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; padding: 0; flex: none; border-radius: 50%;
  border: 1px solid rgba(255,255,255,.2); background: var(--pill);
  color: var(--text-primary); cursor: pointer;
}
.viewer-control--follow { background: var(--accent); color: var(--on-accent); border-color: transparent; }
.viewer-control:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.viewer-fullscreen #fullscreen { color: var(--accent); }
.capbar { bottom: calc(72px + var(--sab)); }
.stage { height: calc(100dvh - var(--sat) - var(--sab)); }
:fullscreen .stage { height: auto; }

/* Состояние синхронизации — небольшая точка; текст доступен средствам чтения экрана. */
.connection-dot {
  position: fixed; top: calc(22px + var(--sat)); right: calc(24px + var(--sar));
  width: 12px; height: 12px; border-radius: 50%; z-index: 6;
  box-shadow: 0 0 0 6px rgba(0,0,0,.65); pointer-events: none;
}
.connection-dot--following { background: #9DCE65; }
.connection-dot--independent { background: #F0C744; }
.connection-dot--offline { background: #FF6868; }

/* Ожидание: подтверждение подключения и одно объяснение следующего шага. */
.waiting-screen { gap: 16px; padding-left: 24px; padding-right: 24px; }
.waiting-screen .waitcol__title { font-size: clamp(24px, 5.5vw, 32px); line-height: 1.15; max-width: 520px; }
.waiting-screen .waitcol__sub { max-width: 380px; margin-top: 4px; }
.waiting-material { margin: 0; max-width: 420px; font-size: 20px; font-weight: 600; color: var(--text-primary); overflow-wrap: anywhere; }
.waiting-preview {
  position: relative; width: min(76vw, 360px); aspect-ratio: 16/9; overflow: hidden;
  display: grid; place-items: center; border-radius: 12px; background: #F0C744; color: #30270A;
}
.waiting-preview img { width: 100%; height: 100%; object-fit: contain; background: var(--surface); }
.waiting-preview--empty { width: 80px; height: 80px; aspect-ratio: 1; border-radius: 20px; }
.waiting-preview:not(.waiting-preview--empty) .waiting-art { display: none; }
#wait-cover-loading { position: absolute; right: 5px; bottom: 5px; width: 18px; height: 18px; }
.waiting-state { display: flex; align-items: center; gap: 8px; margin-top: 4px; color: var(--accent); font-size: 15px; }
.waiting-state--ready { color: var(--success); }
.waiting-state--error { color: var(--danger); }
.waiting-link { min-height: 44px; display: inline-flex; align-items: center; color: var(--accent); }
.viewer-spinner {
  display: inline-block; width: 24px; height: 24px; flex: none; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: viewer-loading 900ms linear infinite;
}
.waiting-state .viewer-spinner { width: 16px; height: 16px; }
.waiting-spinner { width: 28px; height: 28px; color: var(--accent); margin-top: 4px; }
@keyframes viewer-loading { to { transform: rotate(360deg); } }
.slide-loading {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 4;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 20px 24px; width: max-content; max-width: calc(100vw - 48px);
  border-radius: 16px; background: rgba(25,26,22,.94); color: var(--text-primary);
  font-size: 16px; line-height: 1.4; text-align: center; pointer-events: none;
}
.slide-loading .viewer-spinner { color: var(--accent); }
.slide-loading button { pointer-events: auto; margin-top: 0; }
@media (orientation: landscape) and (max-height: 560px) {
  .waiting-screen { gap: 10px; }
  .waiting-preview--empty { width: 56px; height: 56px; border-radius: 14px; }
  .waiting-preview:not(.waiting-preview--empty) { width: 180px; max-height: 100px; }
}
@media (prefers-reduced-motion: reduce) { .viewer-spinner { animation: none; } }
