/* v2-hotel.css — карточка отеля: РАСКЛАДКА из макета V2, ВИД из сегодняшней версии V1.
 *
 * Решение владельца 30.08.2026: из макета `V2 сайт/design_handoff_hotel_s/hotel.html`
 * берём только расположение и размеры сеток, а шрифты, цвета, шапку-стекло и отсутствие
 * белых плашек оставляем как в V1. Поэтому здесь нет ни палитры, ни типографики —
 * весь вид приходит из `hotel-base.css`, который страница подключает первым.
 *
 * Что берём из макета:
 *   • галерея одной полосой во всю ширину: большое фото слева на два ряда, маленькие 2×2
 *     справа (грид 2fr 1fr 1fr, ряды 210px, зазор 10px) — со стрелками листания, если
 *     фотографий больше пяти;
 *   • под ней две колонки 1fr / 360px с зазором 24px;
 *   • слева — секции, справа — панель поиска с ценой «от».
 *
 * Название отеля осталось НАД галереей, как в V1 (решение владельца 30.08.2026).
 *
 * Раскладка галереи и колонок заперта в @media (min-width:1024px): на телефоне остаётся
 * сегодняшний вид. Отдельным блоком в конце файла — правки, которые нужны ТОЛЬКО на
 * телефоне (размер названия).
 * Ширину контейнера НЕ трогаем (1280px из V1) — по ней же выровнены шапка и подвал.
 *
 * Консьерж: с 31.08.2026 на странице стоит НАСТОЯЩИЙ виджет главной — разметку собирает
 * `shared/concierge.js`, стили приходят из `styles/concierge.css` (подключается после
 * этого файла). Своих правил консьержа здесь больше нет.
 */

@media (min-width: 1024px) {

  /* ---------- галерея во всю ширину, две колонки под ней ----------
     Галерея — отдельный ребёнок сетки на всю ширину, поэтому панель цены и поиска
     уезжает ПОД неё, в правую колонку, а секции — в левую. */
  .v2 #hotel-body {
    grid-template-columns: minmax(0, 1fr) 360px;
    column-gap: 24px;
    row-gap: 20px;
  }
  /* Колонки НЕ выравниваем по верху: правая должна тянуться на всю высоту ряда, иначе
     панели поиска некуда «ехать» и она перестаёт прилипать при прокрутке, как в V1. */
  .v2 #hotel-gallery { grid-column: 1 / -1; }
  .v2 #hotel-main { grid-column: auto; }
  .v2 #hotel-rail { grid-column: auto; }

  /* ---------- галерея мозаикой ---------- */
  .v2 #hotel-gallery {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    grid-template-rows: 210px 210px;
    gap: 10px;
  }
  /* Главное фото — слева на две строки */
  .v2 #hotel-gallery > div:first-child {
    grid-column: 1; grid-row: 1 / 3;
    height: auto;
    position: relative;
  }
  /* Лента миниатюр превращается в сетку 2×2 справа */
  .v2 #gallery-carousel { grid-column: 2 / 4; grid-row: 1 / 3; overflow: hidden; }
  /* Фотографий у отеля может быть больше четырёх — тогда плитка прокручивается ВБОК,
     на следующую четвёрку: миниатюры уезжают влево, а не обрезаются насовсем. Клик по
     миниатюре по-прежнему меняет главное фото, и ни один снимок не пропадает. */
  .v2 #gallery-thumbs {
    display: grid;
    grid-auto-flow: column;
    grid-template-rows: 1fr 1fr;
    grid-auto-columns: calc((100% - 10px) / 2);
    gap: 10px;
    height: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    scroll-snap-type: none;   /* «примагничивание» ленты V1 плитке не нужно */
  }
  /* Миниатюр меньше четырёх — плитка не должна зиять пустыми клетками:
     одна занимает всю правую часть, две встают в ряд, при трёх первая берёт оба ряда. */
  .v2 #gallery-thumbs:has(> :first-child:last-child) { grid-template-rows: 1fr; grid-auto-columns: 100%; }
  .v2 #gallery-thumbs:has(> :nth-child(2):last-child) { grid-template-rows: 1fr; }
  .v2 #gallery-thumbs:has(> :nth-child(3):last-child) > :first-child { grid-row: 1 / 3; }
  .v2 #gallery-thumbs > * { width: auto !important; height: auto !important; margin: 0; }
  .v2 #gallery-thumbs > * img { width: 100%; height: 100%; object-fit: cover; }
  /* Стрелки листания остаются на месте — круглые кнопки V1 у левого и правого края плитки,
     по вертикали по центру. Показывает и прячет их общий слой (setupGalleryArrows): при
     пяти фото и меньше плитка помещается целиком и стрелок нет вовсе. */

  /* Фотография одна — миниатюр нет, и правая половина мозаики осталась бы пустой.
     В этом случае главное фото занимает всю ширину. */
  .v2 #gallery-carousel.hidden,
  .v2 #hotel-gallery:has(#gallery-thumbs:empty) #gallery-carousel { display: none; }
  .v2 #hotel-gallery:has(> #gallery-carousel.hidden) > div:first-child,
  .v2 #hotel-gallery:has(#gallery-thumbs:empty) > div:first-child { grid-column: 1 / 4; }

  /* Название отеля (#hotel-head) стоит НАД галереей, как в V1 — это сделано разметкой.
     Плашки вокруг него нет: обычный текст, стилей не надо. */
}

/* ================= Телефон: до 1024px =================
   Всё, что ниже, действует только на узком экране и только на новой карточке. */
@media (max-width: 1023px) {

  /* Название отеля. На широком экране это 48px (`display-lg`), и на 390px такая строка
     съедала пол-экрана: «Бутик-отель Шёлковый путь, Хива» уходил в четыре строки.
     28px — уже существующий в проекте размер `headline-lg-mobile`, вместе с его
     межстрочным и трекингом; самые длинные названия в базе (48 знаков) при нём ложатся
     в две строки. `balance` делает эти две строки примерно равными — где его нет
     (Safari до 17.5), текст просто переносится как раньше, без обрезки. */
  .v2 #hotel-name {
    font-size: 28px;
    line-height: 1.2;
    letter-spacing: -0.02em;
    text-wrap: balance;
    overflow-wrap: break-word;
  }

  /* Своего правила «Наверх» здесь больше нет: геометрия кнопки над кружком консьержа
     живёт в общем `styles/concierge.css` (26/96, а на узком экране 20/90) — одна на все
     страницы витрины. Локальный перебор `.v2 #backToTop` перекрывал бы его по весу
     селектора и на телефоне разъезжался бы с кружком. */
}

/* ================= Причёсывание V3 (фаза 30, аудит storefront-cards) =================
   Ниже — только отступы, состояния, плавность и попадание пальцем. Ни одного нового
   цвета, ни плашек вокруг секций, ни сдвигов раскладки: вид V1 остаётся запертым. */

/* S-01 Прыжок «Найти» (и любая ссылка-якорь) останавливался ПОД шапкой-стеклом —
   заголовок «Номера» и верх первой карточки уезжали ей за спину.
   80px шапки + 24px воздуха. Чистый CSS, JS не трогаем. */
.v2 #sec-rooms,
.v2 #booking-form,
.v2 #sec-nearby,
.v2 #sec-map,
.v2 #sec-reviews { scroll-margin-top: 104px; }

/* S-05 «Рядом»: длинное название упиралось прямо в расстояние («…искусства Узбекистана0.46 km»).
   Зазор между ними и запрет переносить само расстояние. */
.v2 #nearby-list > div { gap: 16px; }
.v2 #nearby-list > div > span:first-child { min-width: 0; }
.v2 #nearby-list > div > span:last-child { white-space: nowrap; flex-shrink: 0; }

/* S-06 Наплыв на главное фото: 700ms — вдвое дольше потолка интерфейсной анимации (300ms),
   и на телефоне касание оставляло фото увеличенным до следующего тапа. Теперь наезд только
   под настоящей мышью, вход 250ms — уход 150ms (решение владельца 31.08.2026).

   Слоёв главного фото два, и лежат они друг на друге: видимый помечен `.is-front`. Смена
   кадра — растворение, прозрачностью управляют эти же правила (id перебивает `.clip-reveal`
   из V1, поэтому старый показ по `.is-in` в новой версии не участвует). */
.v2 #gallery-main,
.v2 #gallery-main-b {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .25s cubic-bezier(.23,1,.32,1), transform 450ms cubic-bezier(0.25,0.46,0.45,0.94);
  backface-visibility: hidden;
}
.v2 #gallery-main.is-front,
.v2 #gallery-main-b.is-front { opacity: 1; }
/* Прозрачный слой лежит поверх видимого — нажатия и наведение он перехватывать не должен. */
.v2 #gallery-main:not(.is-front),
.v2 #gallery-main-b:not(.is-front) { pointer-events: none; }
@media (hover: hover) and (pointer: fine) {
  .v2 .group:hover #gallery-main,
  .v2 .group:hover #gallery-main-b {
    transform: scale(1.04) translateZ(0);
  }
  /* Тот же наплыв и на маленьких фото рядом с главным (решение владельца 31.08.2026).
     Двигается сама картинка внутри плитки: у плитки `overflow-hidden`, поэтому размер и
     рамка остаются на месте, наезжает только кадр. Правило живёт здесь, а не рядом с
     миниатюрами ниже, потому что ВЕСЬ наезд обязан лежать внутри этого блока — иначе на
     телефоне касание оставит фото увеличенным до следующего тапа. */
  .v2 #gallery-thumbs [data-gphoto]:hover > img { transform: scale(1.04) translateZ(0); }
}
@media (prefers-reduced-motion: reduce) {
  .v2 .group:hover #gallery-main,
  .v2 .group:hover #gallery-main-b { transform: none; }
}

/* Стрелки листают фотографии, поэтому видно, с какой миниатюры снят текущий кадр.
   Рамка рисуется внутрь (outline-offset), чтобы не менять размер плитки. */
.v2 #gallery-thumbs [data-gphoto] { transition: outline-color .2s ease; }
.v2 #gallery-thumbs [data-gphoto].is-current {
  outline: 3px solid #1c1b1b;
  outline-offset: -3px;
  border-radius: 1rem;
}

/* Плавность наплыва миниатюры — та же общая кривая, что у главного фото. Само увеличение
   стоит выше, внутри блока наведения. */
.v2 #gallery-thumbs [data-gphoto] > img {
  transition: transform 450ms cubic-bezier(0.25,0.46,0.45,0.94);
  backface-visibility: hidden;
}
@media (prefers-reduced-motion: reduce) {
  .v2 #gallery-thumbs [data-gphoto]:hover > img { transform: none; }
}

/* S-07 Рамка фокуса рисовалась скруглённым прямоугольником вокруг КРУГЛОЙ кнопки
   (стрелки галереи, «поделиться», шаги счётчика гостей, «наверх»). */
.v2 a.rounded-full:focus-visible,
.v2 button.rounded-full:focus-visible,
.v2 .bk-step:focus-visible { border-radius: 9999px; }

/* S-13 Стрелки галереи: «назад» появлялась рывком посреди прокрутки. Само вдавливание
   с 05.09.2026 одно на весь сайт (/styles/press.css) — здесь только его плавность,
   дописанная в список того, что у кнопки уже плыло. */
.v2 #gallery-prev,
.v2 #gallery-next { transition: opacity .15s ease, background-color .15s ease, scale .16s cubic-bezier(.23,1,.32,1); }
.v2 #share-btn,
.v2 #bc-search { transition: color .2s ease, background-color .2s ease, scale .16s cubic-bezier(.23,1,.32,1); }

/* S-12 + S-20 Появление секций при прокрутке было маркетинговой скоростью (0.8s/1.25s) на
   обычном тексте — секции доезжали заметно позже взгляда. И `will-change` висел вечно:
   каждая секция, включая карту, держала свой слой всю жизнь страницы.
   Каскад 60/120/180/240ms из V1 остаётся — он уже в правильной полосе. */
html.js-ready.v2 .reveal {
  transform: translateY(16px);
  transition: opacity .45s cubic-bezier(.23,1,.32,1), transform .5s cubic-bezier(.23,1,.32,1);
}
/* `.v2` висит на самом <html>, а не на потомке: с пробелом запись не совпадала ни с чем.
   `transform: none` повторён здесь нарочно — правило V1 идёт РАНЬШЕ и с той же силой,
   без него секция замирала бы сдвинутой на 16px. */
html.js-ready.v2 .reveal.is-in { transform: none; will-change: auto; }

/* S-15 «Минус» у счётчика гостей был #fcf9f8 на поле #f6f3f2 — разница в один процент
   светлоты, кнопка читалась только по тени. Белый плюс волосяная рамка, палитра та же. */
.v2 .bk-step:not(.plus) {
  background: #fff;
  /* Волосяная линия внутрь (box-shadow), а не border: рамка снаружи делала «минус»
     на 2px больше «плюса», и счётчик терял симметрию. */
  box-shadow: inset 0 0 0 1px rgba(28, 27, 27, 0.12);
}
.v2 .bk-step:not(.plus):hover:not(:disabled) { background: #f0edec; }

/* S-17 Подсветка выбранного номера (ring на 2.4 секунды) включалась и гасла рывком. */
.v2 [data-room-id] { transition: box-shadow .25s cubic-bezier(.23,1,.32,1); }

/* S-36 Значок «свободно N» и затемнение занятых номеров возникали в тот же кадр, что и
   нажатие «Найти» — связь между кнопкой и изменившимся списком не показывалась. */
.v2 .room-badge-free,
.v2 .room-badge-cap { transition: opacity .2s ease, transform .25s cubic-bezier(.23,1,.32,1); }
@starting-style {
  .v2 .room-badge-free,
  .v2 .room-badge-cap { opacity: 0; transform: scale(.94); }
}
.v2 .room-dimmed { transition: opacity .25s ease; }

/* S-03 + S-29 Окно подтверждения и окно услуги НИКОГДА не проигрывали свой вход: JS в одном
   кадре и показывает узел (display), и вешает `.open`, поэтому переходу не от чего считать.
   `@starting-style` даёт ему точку отсчёта, `allow-discrete` — уход. Выход короче входа.
   Пружинистая кривая (.34,1.56,.64,1) с подтверждения брони убрана: это серьёзный момент. */
.v2 #bk-modal,
.v2 #facility-modal { transition: display .2s allow-discrete; }
.v2 #bk-modal .bk-dialog,
.v2 #facility-modal .fm-dialog {
  transition: opacity .18s ease, transform .18s cubic-bezier(.23,1,.32,1);
}
.v2 #bk-modal.open .bk-dialog,
.v2 #facility-modal.open .fm-dialog {
  transition: opacity .25s cubic-bezier(.23,1,.32,1), transform .3s cubic-bezier(.23,1,.32,1);
}
.v2 #bk-modal .bk-backdrop,
.v2 #facility-modal .fm-backdrop { transition: opacity .18s ease; }
.v2 #bk-modal.open .bk-backdrop,
.v2 #facility-modal.open .fm-backdrop { transition: opacity .25s ease; }
@starting-style {
  .v2 #bk-modal.open .bk-dialog { opacity: 0; transform: translateY(24px) scale(.97); }
  .v2 #facility-modal.open .fm-dialog { opacity: 0; transform: translateY(28px); }
  .v2 #bk-modal.open .bk-backdrop,
  .v2 #facility-modal.open .fm-backdrop { opacity: 0; }
}

/* S-10 Шторка бургера возникала мгновенно — и панель, и затемнение. Это самый частый
   мобильный жест на странице. Сдвиг в процентах, без пиксельных смещений. */
.v2 #mobile-menu {
  opacity: 0; pointer-events: none;
  transition: opacity .3s ease, display .3s allow-discrete;
}
.v2 #mobile-menu:not([hidden]) { opacity: 1; pointer-events: auto; }
.v2 #mobile-menu-panel { transform: translateX(100%); transition: transform .3s cubic-bezier(.32, .72, 0, 1); }
.v2 #mobile-menu:not([hidden]) #mobile-menu-panel { transform: none; }
/* Закрытое состояние задано выше ЯВНО — иначе уход был бы телепортом: шторка оставалась бы
   на экране во всю прозрачность, ловила бы нажатия и пропадала рывком в конце. Здесь
   `@starting-style` служит только точкой отсчёта для входа. */
@starting-style {
  .v2 #mobile-menu:not([hidden]) { opacity: 0; }
  .v2 #mobile-menu:not([hidden]) #mobile-menu-panel { transform: translateX(100%); }
}

@media (prefers-reduced-motion: reduce) {
  .v2 #gallery-main,
  .v2 #gallery-main-b,
  .v2 #gallery-prev,
  .v2 #gallery-next,
  .v2 .room-badge-free,
  .v2 .room-badge-cap,
  .v2 .room-dimmed,
  .v2 [data-room-id],
  .v2 #bk-modal,
  .v2 #facility-modal,
  .v2 #mobile-menu,
  .v2 #mobile-menu-panel { transition: none !important; }
}

@media (min-width: 1024px) {
  /* S-09 Заглушка галереи (у отеля нет ни одной фотографии): картинки-заглушки со словом,
     впечатанным в растр, размером под старую ленту 192×128, растягивались `cover` в плитку
     295×210 — слова «Lobby / Room / View» лезли кеглем под 48px, а надпись «Скоро фото»
     ложилась прямо на слово. Вписываем картинку целиком и уводим надпись вниз. */
  .v2 #gallery-thumbs > div > img[src*="placehold.co"] {
    object-fit: contain;
    background: #e5e2e1;
    padding: 28%;
  }
  .v2 #gallery-thumbs > div > .absolute {
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 14px;
    background: linear-gradient(to top, rgba(28, 27, 27, .55), rgba(28, 27, 27, 0) 55%);
  }
}

@media (max-width: 1023px) {
  /* S-02 Кружок консьержа и «Наверх» ложились поверх текста подвала — закрывали
     «© 2026 HotelS…» и «Партнёрам». 48 кнопки + 24 отступ снизу + 24 промежуток + 16 воздуха. */
  .v2 footer { padding-bottom: 112px; }

  /* S-11 Стрелки на телефоне не опускаются ниже 40px: сам кружок 36×36 (решение владельца
     05.09.2026 — 40 смотрелись грубовато), но палец получает площадку побольше. */
  .v2 #gallery-prev,
  .v2 #gallery-next { min-width: 40px; min-height: 40px; }

  /* Липкой полосы прыжка (S-19) здесь больше нет: с 31.08.2026 её место заняла шторка
     поиска — правила ниже. */

  /* ===== Шторка поиска: язычок у правого края + выдвижная панель =====
     Слои: шапка 50, консьерж 70, «Наверх» 40. Язычок садится на 45 — выше «Наверха» и ниже
     шапки; по вертикали он ровно посередине экрана и ни с одним из кружков не пересекается.
     Сама шторка — на 65, как шторка бургера (#mobile-menu): открытая панель обязана быть НАД
     шапкой, иначе язык, валюта и бургер проступают поверх неё и закрывают крестик. */
  .v2 #search-tab {
    display: flex;
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 45;
    width: 36px;
    height: 112px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    border-radius: 20px 0 0 20px;
    /* Матовое стекло вместо глухого чёрного прямоугольника (решение владельца 31.08.2026):
       язычок пропускает страницу сквозь себя и размывает её. Уже и выше прежнего — читается
       как аккуратная закладка на краю, а не как кнопка, приклеенная поверх. Светлый волосок
       по краю отделяет его от фона на тёмной фотографии. */
    background: rgba(28, 27, 27, .55);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    backdrop-filter: blur(16px) saturate(180%);
    border: 1px solid rgba(255, 255, 255, .18);
    border-right: 0;
    color: #fcf9f8;
    box-shadow: -10px 0 26px -12px rgba(28, 27, 27, .45);
    transition: transform .16s cubic-bezier(.23, 1, .32, 1), background-color .2s ease;
  }
  /* Браузер без размытия фона (старый Firefox) получил бы полупрозрачный серый прямоугольник
     и белые значки на нём — вместо этого остаётся прежний плотный фон. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .v2 #search-tab { background: rgba(28, 27, 27, .92); }
  }
  /* Лупа жёлтая — как на карточке отеля в макете; шеврон остаётся светлым. */
  .v2 #search-tab #search-tab-glass { color: #febb14; }
  .v2 #search-tab:active { background: rgba(28, 27, 27, .7); }

  .v2 #search-sheet {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 65;
    /* Уход шторки должен доиграть: без `allow-discrete` она пропадала бы в первый же кадр. */
    transition: display .5s allow-discrete;
  }
  .v2 #search-sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(28, 27, 27, .38);
    opacity: 0;
    transition: opacity .4s ease;
  }
  .v2 #search-sheet:not([hidden]) #search-sheet-backdrop { opacity: 1; }
  .v2 #search-sheet-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 65vw;
    min-width: 288px;
    max-width: 420px;
    background: #fcf9f8;
    border-radius: 28px 0 0 28px;
    box-shadow: -20px 0 48px -22px rgba(28, 27, 27, .5);
    padding: 20px 16px calc(20px + env(safe-area-inset-bottom));
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(100%);
    transition: transform .5s cubic-bezier(.32, .72, 0, 1);
  }
  .v2 #search-sheet:not([hidden]) #search-sheet-panel { transform: none; }
  /* Панель поиска внутри шторки: своей плашки и тени ей здесь не нужно — фон уже её. */
  .v2 #search-sheet-slot #booking-form {
    padding: 0;
    border: 0;
    box-shadow: none !important;
    background: transparent;
  }
  /* Закрытое состояние задано выше ЯВНО, `@starting-style` — только точка отсчёта для входа
     (тот же приём, что у шторки бургера). */
  @starting-style {
    .v2 #search-sheet:not([hidden]) #search-sheet-backdrop { opacity: 0; }
    .v2 #search-sheet:not([hidden]) #search-sheet-panel { transform: translateX(100%); }
  }
}

/* На широком экране шторки и язычка не существует вовсе: панель поиска стоит справа от
   секций, как и стояла. Правило идёт ПОСЛЕ телефонного блока, чтобы наверняка перебить его. */
@media (min-width: 1024px) {
  .v2 #search-tab,
  .v2 #search-sheet { display: none; }
}

/* «Меньше движения»: шторка приезжает мгновенно, движется только затемнение. */
@media (prefers-reduced-motion: reduce) {
  .v2 #search-tab,
  .v2 #search-sheet,
  .v2 #search-sheet-panel { transition: none !important; }
  .v2 #search-sheet-panel { transform: none !important; }
}

/* ---------- T-37-01 (05.09.2026): место под шапку, чтобы страница не прыгала ----------
   Аудит layout-shift (docs/perf/cls-hotel-20260905.md) показал ОДИН повторяющийся сдвиг
   страницы отеля: в миг ответа базы разом появляются строка адреса (#hotel-address, до
   этого пустая и высотой 0) и плашка оценки (#hotel-rating, тоже пустая). Шапка вырастает
   на 21 px и утягивает вниз ВСЁ, что под ней, — галерею и остальную страницу; на неё
   приходится около семи десятых экрана, отсюда и весь CLS.

   Лечение — не новый класс Tailwind, а зарезервированный размер здесь: обе строки держат
   свою будущую высоту ещё до прихода данных. Числа взяты из измеренной раскладки: строка
   адреса — одна строка text-body-sm (14/21), плашка оценки — h-12 на телефоне и md:h-14 на
   десктопе. Видимой разницы это не даёт: у отеля без отзывов в шапке стоит низкая «плашка
   новизны», но высоту ряда и там задаёт кнопка «Поделиться» (48 px), а высоту всей шапки —
   левая колонка с названием.

   Сторож: tests/test_hotel_cls_reserved.py. Убрать эти правила — вернуть прыжок. */
.v2 #hotel-address { min-height: 21px; min-height: 1lh; }
.v2 #hotel-rating { min-height: 48px; }
@media (min-width: 768px) {
  .v2 #hotel-rating { min-height: 56px; }
}
