/*
Theme Name:  Конча-Заспа
Description: Тема санаторно-курортного комплексу «Конча-Заспа». Класична, на PHP-шаблонах: правиться будь-яким редактором без складальника.
Version:     1.0.0
Author:      —
Text Domain: koncha-zaspa
Requires PHP: 7.4
*/

/* ===================================================================
   Чому звичайний CSS, а не Tailwind чи складальник.

   Сайт передається сторонньому підрядникові. Будь-який крок збірки між
   «відкрив файл» і «побачив зміну» — це те, що нова людина спершу має
   налаштувати, а не полагодити сайт. Тому тут лише CSS, який читає
   браузер напряму.

   Кольори й типографіка — у змінних угорі: перефарбувати сайт означає
   змінити дев'ять рядків, а не шукати відтінок по файлу.
   =================================================================== */

:root {
  /* Палітра «Льон» (варіант 05), акцент — із фірмового знака.

     Тепло-сірий майже не має характеру — і це його сила: він не набридає
     й не прив'язує до моди, а працювати мають фотографії. Акцент узятий
     не з добірки, а виміряний із логотипа: знак золотий, і будь-який
     інший акцентний колір поряд із ним читається як чужий.

     Смуги (герой на внутрішніх сторінках, підвал) ТЕМНІ, текст на них
     білий. Робитимете смуги світлими — міняти треба не лише ці змінні:
     див. kz_bands_are_dark() у functions.php, від неї залежить, який
     варіант логотипа підставляти. Білий знак на світлому тлі зникає
     беззвучно.

     Усі кольори нижче підібрані РОЗРАХУНКОМ контрасту, не на око: у
     зразках добірки це були просто квадратики, і половина з них для
     тексту не годиться. */
  --background: #f5f3ef;
  --surface: #ffffff;
  --foreground: #2c2a26;
  --muted: #6b6559;       /* 5,2:1 на тлі, 5,8:1 на картці */
  --border: #ded9d1;
  --brand: #4a4741;       /* кнопки, смуги, заголовки */
  --brand-dark: #332f2a;  /* підвал і найтемніше */
  --brand-light: #e9e5dd;
  /* Акцент — золото з фірмового знака (#B79D6D, виміряне з логотипа, а не
     підібране на око: знак і сайт мають бути одного кольору, інакше шапка
     читається як чужа наліпка). Шавлія, що була тут раніше, із золотим
     знаком не в'язалася.

     Тільки ЗАЛИВКИ Й ПОЗНАЧКИ: на білому золото дає 2,6:1 — для тексту не
     годиться. */
  --accent: #b79d6d;
  --accent-hover: #c7b088; /* світліше, бо заливка темнішати при наведенні не має */
  /* Той самий акцент, але для ТЕКСТУ: ним набрані підписи на картках і
     надзаголовки секцій. 6,0:1 на білому, 5,4:1 на тлі, 4,8:1 на світлих
     блоках. */
  --accent-ink: #7a5f28;
  /* Текст НА акцентній заливці. Окремий токен, бо --brand-dark (#332F2A)
     на золоті дає 4,96:1 — впритул до межі. Цей дає 5,49:1. */
  --on-accent: #2c2a26;
  /* Колір напису «Конча-Заспа» в логотипі: середнє по 25 382 пікселях
     насиченої фарби макета. Ним залитий підвал — сторінка закінчується
     тим самим кольором, яким набрана назва санаторію. */
  --logo-ink: #58593e;
  /* Смуга меню — теплий вугільний, як на сайтах-зразках. Нею ж залита
     смуга-заголовок внутрішніх сторінок: шапка лежить просто на ній і
     напівпрозора, тож різні кольори дали б угорі видимий шов.

     Канали окремо числами саме через цю напівпрозорість:
     rgb(var(--…) / 0.7) розуміють усі браузери, на відміну від новішого
     rgb(from …). */
  --header-rgb: 62 59 56;
  --header-bg: rgb(var(--header-rgb));
  /* Золото для ТЕКСТУ на темних смугах. Фірмове --accent на підвалі дає
     лише 2,77:1 — наведення робило б посилання гіршим за звичайне. Це
     те саме золото, освітлене кремовим із логотипа: 4,69:1 на підвалі,
     7,23:1 на смузі меню. Для ЗАЛИВОК (кнопка) лишається --accent. */
  --accent-on-dark: #dccfb7;
  --footer-bg: var(--logo-ink);
  --on-band: #ffffff;     /* текст на смугах: герой, підвал */
  /* Приглушений текст НА ТЕМНИХ смугах. Окремий від --muted: той
     розрахований на світле тло й у підвалі давав би ~2:1. */
  --on-band-muted: rgb(255 255 255 / 0.72);

  --font-body: "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-head: Georgia, "Times New Roman", serif;

  /* Крива й тривалості руху — одні на весь сайт. Коли кожен блок
     анімується по-своєму, сторінка здається смиканою. */
  --ease-glide: cubic-bezier(0.19, 0.51, 0.29, 1);
  --reveal-duration: 0.9s;
  --curtain-duration: 1s;
  /* Перефарбування шапки з прозорої на суцільну. Помітно повільніше за
     решту рухів: це відбувається просто під пальцем під час прокрутки,
     і швидкий перехід читається як блимання. */
  --band-fade: 0.45s;

  --container: 1280px;
  /* Висота смуги шапки. Нею ж CSS підсуває перший екран під шапку, а
     скрипт рахує, коли перемикати її вигляд, — тому число одне. */
  --header-h: 80px;
  /* Проміжок у плитковій сітці. Окремою змінною, бо від нього залежить
     і висота плитки: вона рахується так, щоб три ряди разом із двома
     проміжками стали рівно в екран. Міняти в одному місці. */
  --tiles-gap: 4px;
}

/* --- основа ------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

/* Блоки заїжджають збоку: [data-reveal="right"] до появи стоїть на 40px
   правіше свого місця. На повну ширину сторінки це 40px за межею вікна —
   і браузер показує горизонтальну смугу прокрутки, яка зникає, щойно блок
   приїде. Виміряно: 1281px при вікні 1265px — на головній, у медіа-центрі
   та на сторінці «Про санаторій».

   Саме html, а не body: поки в кореня overflow: visible, браузер бере
   overflow із body й застосовує його до області перегляду — і смуга
   прокрутки лишалася на місці. Виміряно (вікно 1280×900): без правила
   горизонтальна смуга з'їдала 15px висоти на головній, у медіа-центрі та
   на «Про санаторій»; із правилом — 0 на всіх трьох.

   Прокрутка кодом (window.scrollTo) при цьому все одно спрацьовує на
   16px: у кореня clip перетворюється на hidden, а hidden ховає смугу, але
   не забороняє крутити зі скрипта. Це не недороблений фікс — міряти тут
   треба саму смугу, а не scrollX.

   clip, а не hidden. hidden зробив би область перегляду прокрутним
   контейнером, а від цього перестає працювати position: sticky у шапки
   меню — смуга поїхала б зі сторінкою вгору. clip лише відрізає зайве й
   контейнера не створює.

   Старі Safari (до 16) clip не знають і просто лишать як було — миготіння
   смуги, а не зламана сторінка. */
html { overflow-x: clip; }

body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  font-weight: 400;
  letter-spacing: 0.01em;
  margin: 0;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; height: auto; display: block; }
button { font: inherit; cursor: pointer; border: 0; background: none; color: inherit; }

.container {
  /* width: 100% обов'язковий, хоч у звичайному потоці він нічого не
     змінює (box-sizing: border-box стоїть глобально).

     Потрібен він там, де контейнер лежить у grid або flex. Елемент
     такого батька з автоматичними полями НЕ розтягується: auto-поля
     з'їдають вільне місце й центрують його за шириною ВМІСТУ. Саме це
     й сталося з героєм: .hero — grid, контейнер виходив 784px замість
     1280 і висів посередині, тож текст починався з 265px замість 24px
     і не збігався ні з логотипом у шапці, ні з блоками нижче.

     Гірше, що це ламало й пелену: текст заїжджав на 78% ширини кадру,
     де вона вже згасла до 0,26, замість триматися щільної лівої
     частини, під яку її й малювали. */
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 1.5rem;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* --- шапка -------------------------------------------------------- */

/* Смуга меню завжди темна, відрізняється лише щільність: над фотографією
   напівпрозора, далі суцільна.

   Рамки знизу немає навмисно. Темна смуга й так відділена від вмісту
   кольором, а рамка додавала б піксель до зовнішньої висоти шапки —
   смугу ж підсовуємо під неї рівно на --header-h, і цей зайвий піксель
   вилазив угорі світлою волосиною завширшки з екран. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--header-bg);
  color: var(--on-band);
  transition: background-color var(--band-fade) var(--ease-glide);
}

/* Знак точно посередині смуги, половини меню обабіч нього, «Бронювання»
   притиснуте до правого краю.

   Сітка, а не flex. Flex ставив би знак там, де лишилося місце між
   сусідами, тож центр з'їжджав би щоразу, коли редактор додасть пункт
   меню або перейменує кнопку.

   minmax(0, 1fr), а не просто 1fr. 1fr — це насправді minmax(auto, 1fr):
   колонка не може стати вужчою за свій вміст, і коли меню праворуч із
   кнопкою ширше за половину вільного місця, права колонка роздувається,
   ліва худне — а знак повзе вбік. Виміряно: на вікні 1100px він стояв на
   84px правіше центру, на 375px — на 70px лівіше. З minmax(0, 1fr) бокові
   колонки рівні завжди, і знак стоїть у центрі при будь-якій ширині.

   max-content у середньої колонки — щоб знак не стискався. На 375px
   «auto» дав колонку 124px замість 178, і зображення поїхало по ширині
   (висота лишалась 52px), тобто логотип просто сплющувало. */
.site-header__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content minmax(0, 1fr);
  align-items: center;
  gap: 1.5rem;
  height: var(--header-h);
}

/* Розставляємо за номерами колонок, а не порядком у HTML. Ліва половина
   меню притискається до знака (justify-self: end), права — починається
   одразу за ним: так обидві половини обрамляють знак, а не плавають десь
   скраю. */
.site-header__inner .site-nav--left { grid-column: 1; justify-self: end; }
.site-header__inner .site-logo { grid-column: 2; justify-self: center; }

/* Права колонка розтягується на всю свою ширину, а всередині праву
   половину меню й кнопку розводить space-between: меню лишається біля
   знака, кнопка стає рівно на правий край смуги. */
.site-header__right {
  grid-column: 3;
  justify-self: stretch;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

/* Знак із підписом «здоров'я · відновлення · гармонія» у три яруси: нижче
   52px нижній ярус перетворюється на пляму. Смуга шапки — 80px, вище вже
   тиснеться.

   Варіант знака тут лише один — світлий: смуга темна в обох станах, і
   підміняти нема на що. */
.site-logo img { height: 52px; width: auto; display: block; }

/* --- шапка над смугою --------------------------------------------- */

/* Шапка не стоїть НАД першим екраном, а лежить НА ньому: фотографія
   починається від верху вікна, а не з-під білої смуги. Смугу підтягуємо
   під шапку від'ємним відступом, а назад додаємо його ж полем — тоді
   вміст смуги лишається там, де був, і нічого не ховається під меню.

   Чому не position: fixed: шапка лишається sticky, тобто в потоці. Усе
   решта — висота сторінки, прокрутка до якоря, друк — поводиться як
   раніше, без компенсацій.

   Поки смуга видна, шапка напівпрозора; коли пішла — скрипт додає
   .is-solid і вона стає суцільною. Переходи повільні (--band-fade):
   швидке перефарбування шапки просто під пальцем читається як
   блимання. */
.has-top-band .hero {
  margin-top: calc(-1 * var(--header-h));
  padding-top: var(--header-h);
}

.has-top-band .page-hero {
  margin-top: calc(-1 * var(--header-h));
  padding-top: calc(4rem + var(--header-h));
}

.has-top-band .page-hero.section--tight {
  padding-top: calc(3.5rem + var(--header-h));
}

/* Над фотографією смуга напівпрозора — кадр просвічує крізь неї.

   0,7 — поміряно на всіх п'яти знімках героя: білий напис меню на
   найсвітлішому з них (басейн) дає 5,79:1. Без смуги взагалі було
   1,68:1. Беремо найменшу щільність, яка впевнено тримає AA, щоб
   фотографії лишалося якомога більше.

   Розмиття лишаємо тільки тут: під суцільною смугою розмивати нема
   чого, а зайвий backdrop-filter — це зайвий шар композиції. */
.site-header--float:not(.is-solid) {
  background: rgb(var(--header-rgb) / 0.7);
  backdrop-filter: blur(8px);
}

/* Меню й кнопка однакові в обох станах — смуга темна завжди. */
.site-nav a { color: var(--on-band); }

.site-nav a:hover { color: var(--accent-on-dark); }

/* Сторінка, на якій гість зараз. Раніше тут стояв селектор
   .current-menu-item, і він фарбував пункт у ТОЙ САМИЙ колір, що й решту,
   тобто не робив нічого: позначки поточного розділу в меню не було зовсім.

   Золотий --accent-on-dark узятий не на око: на смузі меню він дає
   7,23:1, тобто проходить AA з великим запасом. */
.site-nav a[aria-current] { color: var(--accent-on-dark); }

/* Кнопка — золота: сіро-коричнева --brand на зеленій смузі майже не
   читається, а це головна дія на сторінці. */
.site-header .btn--primary {
  background: var(--accent);
  color: var(--on-accent);
}

.site-header .btn--primary:hover { background: var(--accent-hover); }

.site-nav ul {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  transition: color 0.4s var(--ease-glide);

  /* Без цього «МЕДІА-ЦЕНТР» ламався на два рядки через дефіс, смуга
     ставала вищою за --header-h — і вилазила з-під підсунутого під неї
     першого екрана. Пункт меню або вміщається в рядок, або меню ховається
     зовсім; половинчастого стану тут бути не повинно. */
  white-space: nowrap;
}

/* Кольори меню задані вище, разом зі смугою: вони залежать від неї, а не
   від самого меню. Тут лишається тільки накреслення. */

/* Вузькі екрани: меню ховається (окремого випадайка ще немає), лишається
   знак і «Бронювання».

   Кнопку переносимо під знак, а не лишаємо збоку. Порахуймо: на телефоні
   360px усередині відступів лишається 312px, знак займає 178, кнопка —
   140. Разом 318 плюс проміжок: поруч вони не стають ніяк. Або знак
   з'їжджає з центру, або кнопку ріже краєм екрана. Другий рядок — єдиний
   чесний вихід, і --header-h росте рівно на його висоту. */
@media (max-width: 1024px) {
  .site-nav { display: none; }
}

/* --- бургер і випадайка ------------------------------------------- */

/* Кнопка й панель існують ЛИШЕ до 1024px — там, де ховається звичайне
   меню. Вище вони не просто невидимі, а відсутні: інакше скрипт міг би
   лишити панель відкритою після того, як вікно розтягнули, і вона
   висіла б над сторінкою поруч із повноцінним меню. */
.nav-toggle { display: none; }
.site-menu { display: none; }
.mobile-cta { display: none; }

@media (max-width: 1024px) {
  .nav-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;   /* 44px — найменша зручна ціль для пальця */
    height: 44px;
    padding: 0;
    border: 0;
    background: none;
    /* Золото, як у зразку. Не фірмове --accent (2,77:1 на смузі), а
       освітлене --accent-on-dark: 7,23:1. */
    color: var(--accent-on-dark);
    cursor: pointer;

    grid-column: 1;
    justify-self: start;
  }

  /* Права група шапки тут порожня: меню сховане, а кнопка переїхала в
     нижню смугу. Ховаємо цілком, щоб не тримала колонку. */
  .site-header__right { display: none; }

  /* Кнопка «Бронювання» смугою ВНИЗ екрана, як у зразку. Так вона
     завжди під великим пальцем, а шапка лишається однорядковою й
     низькою — фотографії видно більше.

     Смуга фіксована, тож перекривала б кінець сторінки: відступ знизу
     тілу додано поруч. */
  .mobile-cta {
    display: flex;
    justify-content: center;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 60;
    padding: 0.75rem 1.5rem;
    background: rgb(var(--header-rgb) / 0.92);
    backdrop-filter: blur(8px);
  }

  .mobile-cta .btn--primary {
    width: 100%;
    max-width: 22rem;
  }

  body { padding-bottom: 5.5rem; }

  /* Три смужки однією коробкою: сама смужка — це ::before, ::after і
     фон елемента. Трьох окремих <span> у розмітці не тримаємо: їх не
     читає ніхто, а розмітка шапки й так щільна. */
  .nav-toggle__bars,
  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    display: block;
    width: 22px;
    height: 2px;
    background: currentColor;
    transition: transform 0.3s var(--ease-glide), opacity 0.2s linear;
  }

  .nav-toggle__bars {
    position: relative;
  }

  .nav-toggle__bars::before,
  .nav-toggle__bars::after {
    content: "";
    position: absolute;
    left: 0;
  }

  .nav-toggle__bars::before { top: -7px; }
  .nav-toggle__bars::after  { top: 7px; }

  /* Відкрито — смужки складаються в хрестик: середня зникає, крайні
     сходяться й повертаються. */
  .nav-toggle[aria-expanded="true"] .nav-toggle__bars {
    background: transparent;
  }

  .nav-toggle[aria-expanded="true"] .nav-toggle__bars::before {
    transform: translateY(7px) rotate(45deg);
  }

  .nav-toggle[aria-expanded="true"] .nav-toggle__bars::after {
    transform: translateY(-7px) rotate(-45deg);
  }

  .nav-toggle:focus-visible {
    outline: 2px solid var(--accent-on-dark);
    outline-offset: 2px;
  }

  /* Панель висить ПІД смугою, а не розсуває її: інакше при відкриванні
     стрибала б уся сторінка, бо на --header-h зав'язані і відступ під
     шапку, і перемикання її вигляду.

     Тло суцільне навіть тоді, коли сама смуга напівпрозора над
     фотографією: крізь прозору панель проступали б крони, і білий
     перелік по них не прочитався б. Білий на #3E3B38 — 11,1:1. */
  /* Панель на ВЕСЬ екран під шапкою, як у зразку: великі засічкові
     великі літери, просторо, без дрібного переліку.

     absolute, а НЕ fixed, хоч за змістом тут напрошується саме fixed.
     Причина: у шапки над фотографією стоїть backdrop-filter, а він
     робить елемент початком відліку для фіксованих нащадків. Панель
     із position: fixed на головній приліплювалась би до шапки
     заввишки 80px замість екрана. Абсолютна ж рахується від самої
     шапки, а та липка — отже панель однаково стоїть на місці при
     прокрутці.

     Тло суцільне навіть тоді, коли сама смуга напівпрозора над
     фотографією: крізь прозору панель проступали б крони, і перелік по
     них не прочитався б. Білий на #3E3B38 — 11,1:1. */
  .site-menu:not([hidden]) {
    display: block;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: calc(100svh - var(--header-h));
    background: var(--header-bg);
    border-top: 1px solid rgb(255 255 255 / 0.12);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* Нижній відступ — під смугу з «Бронюванням»: вона фіксована й
     перекрила б останні пункти. */
  .site-menu ul {
    margin: 0;
    padding: 1.75rem 0 7rem;
    list-style: none;
  }

  .site-menu a {
    display: block;
    padding: 0.55rem 1.5rem;
    color: var(--on-band);
    font-family: var(--font-head);
    font-size: clamp(1.25rem, 5.5vw, 1.75rem);
    line-height: 1.3;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  .site-menu a:hover,
  .site-menu a:focus-visible { background: rgb(255 255 255 / 0.07); }

  /* Поточний розділ — те саме золото, що й у настільному меню: 7,23:1
     на цій смузі. */
  .site-menu a[aria-current] { color: var(--accent-on-dark); }
}

/* Шапка на телефоні лишається ОДНОРЯДКОВОЮ: бургер ліворуч, знак по
   центру, праворуч порожньо.

   Раніше тут було два ряди й --header-h: 116px — кнопка «Бронювання» не
   вміщалась поруч зі знаком (на 360px усередині відступів лишається
   312px, знак займає 178, кнопка 140). Відколи кнопка переїхала смугою
   вниз екрана, тіснити нема кому, і смуга повертається до 80px —
   фотографії видно на 36 пікселів більше.

   Рахунок на 375px: 343px усередині відступів мінус знак 178 мінус два
   проміжки по 8 = 149px на дві бокові колонки, тобто 74 на кожну.
   Бургер займає 44. Вміщається із запасом. */
@media (max-width: 640px) {
  .site-header__inner { gap: 0.5rem; }
}

/* --- кнопки ------------------------------------------------------- */

.btn {
  display: inline-block;
  padding: 0.75rem 1.75rem;
  border-radius: 9999px;
  font-size: 0.875rem;
  font-weight: 500;
  text-align: center;
  transition: background-color 0.5s var(--ease-glide), color 0.5s var(--ease-glide);
}

.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--brand-dark); }

.btn--accent {
  background: var(--accent);
  color: var(--on-accent);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
/* Наведення ОСВІТЛЮЄ, а не затемнює: текст на цій кнопці темний, тож
   темніше тло зменшує контраст. У попередній палітрі затемнення давало
   4,44:1 — нижче AA. */
.btn--accent:hover { background: var(--accent-hover); }

/* Друга кнопка — ЗАЛИВКА, не контур.
   Урок ПЕРЕДАЧІ: контур на просвіченому крізь пелену знімку давав 1,9:1 —
   кнопку було видно лише там, де під нею випадково темна ділянка фото. */
.btn--ghost {
  background: rgb(255 255 255 / 0.92);
  color: var(--foreground);
}
.btn--ghost:hover { background: #fff; }

.btn--block { display: block; width: 100%; }

/* --- типові секції ------------------------------------------------ */

.section { padding: 4rem 0; }
.section--tight { padding: 3.5rem 0; }
.section--light { background: var(--brand-light); }

/* Смуга-заголовок внутрішніх сторінок.

   Без фотографії вона того ж кольору, що й шапка. Інакше вилазив шов:
   шапка лежить НА цій смузі й напівпрозора, тож над іншим кольором вона
   давала власний відтінок, і вгорі сторінки стикалися два різні темні
   прямокутники — це читається не як задум, а як помилка промальовування. */
.page-hero {
  position: relative;
  background: var(--header-bg);
  color: var(--on-band);
  padding: 4rem 0;
  text-align: center;
}

.page-hero__eyebrow {
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: rgb(255 255 255 / 0.7);
}

.page-hero__title { font-size: 2.25rem; }

/* --- те саме, але з фотографією ----------------------------------- */

/* Висота від екрана, як у героя головної, але помітно нижча: це не
   перший екран сайту, а заголовок розділу, і під ним одразу має
   починатися те, по що людина прийшла. */
.page-hero--photo {
  display: grid;
  align-items: center;
  min-height: 58vh;
  min-height: 58svh;
  overflow: hidden;
  /* Поля не задаємо: їх уже дає правило `.has-top-band .page-hero` вище,
     і воно ваговитіше. Повторювати їх тут означало б мати два місця, де
     написано одне й те саме, з яких працює лише одне. */
}

.page-hero__media { position: absolute; inset: 0; z-index: 0; }
.page-hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Пелена рівна, без градієнта: заголовок стоїть ПОСЕРЕДИНІ, а не з
   краю, тож темнити якийсь один бік немає сенсу.

   0,55 — не на око. Фотографію тут обирає оператор, і яка вона буде,
   наперед не знає ніхто, тому рахуємо найгірший можливий кадр — суцільно
   білий. Під пеленою 0,55 він дає 115 із 255, а це 4,73:1 для білого
   тексту: вистачає навіть надзаголовку, набраному дрібним. Менша
   щільність трималася б лише на заголовку (він великий, і йому досить
   3:1), а надзаголовок на світлому знімку зникав би. */
.page-hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgb(0 0 0 / 0.55);
}

.page-hero--photo > .container { position: relative; z-index: 2; }

/* На знімку надзаголовок білий повністю: приглушені 70% розраховані на
   рівну заливку, а не на фотографію під пеленою. */
.page-hero--photo .page-hero__eyebrow { color: var(--on-band); }

.page-hero--photo .page-hero__title,
.page-hero--photo .page-hero__eyebrow {
  /* Друга лінія оборони — як у героя головної: середня щільність пелени
     нічого не обіцяє на локальній світлій плямі всередині кадру. */
  text-shadow: 0 1px 14px rgb(0 0 0 / 0.45);
}

@media (max-width: 900px) {
  .page-hero--photo { min-height: 46svh; }
}

.section-title {
  font-size: 1.875rem;
  margin-bottom: 2rem;
}

.section-eyebrow {
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--accent-ink);
}

.lead { font-size: 1.125rem; }
.muted { color: var(--muted); }
.small { font-size: 0.875rem; }

/* --- сітки -------------------------------------------------------- */

.grid { display: grid; gap: 1.5rem; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1024px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

/* --- блок «фото — текст» ------------------------------------------ */

/* Колонки НЕ рівні: 1.1fr під фото проти 1fr під текст. Рівні половинки
   виглядають як таблиця з двох клітинок; невелика перевага фотографії
   робить блок картиною з підписом, а не рядком. */
.split__inner {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  align-items: center;
  gap: 3.5rem;
}

/* Дзеркальний варіант міняє порядок, а не розмітку: фото в коді завжди
   йде першим, і на вузькому екрані воно всюди зверху — без додаткових
   правил і без сторінки, де фото стрибає то над текстом, то під ним.

   Разом із порядком обов'язково міняються й ширини колонок. Самого
   `order` мало: він пересуває фото у ДРУГУ колонку, а широкою лишається
   перша — і в дзеркальних блоках ширшим ставав текст. Помітно це лише
   поряд зі звичайним блоком, тому легко проґавити. */
.split--reverse .split__inner { grid-template-columns: 1fr 1.1fr; }
.split--reverse .split__media { order: 2; }

.split__media { border-radius: 0.75rem; }

.split__title { margin-bottom: 1rem; }

.split__text {
  color: var(--muted);
  margin: 0;
  max-width: 34rem;   /* довший рядок читати важко, хоч би скільки було місця */
}

.split__link { margin: 1.5rem 0 0; }
.split__link a { color: var(--accent-ink); }

@media (max-width: 860px) {
  /* Обидва селектори, і дзеркальний теж. Медіазапит НЕ додає ваги: саме
     `.split__inner` (0,1,0) слабше за `.split--reverse .split__inner`
     (0,2,0) вище, і без цього рядка дзеркальні блоки лишалися б у дві
     колонки по 140px — на телефоні фото завширшки з ніготь. */
  .split__inner,
  .split--reverse .split__inner {
    grid-template-columns: 1fr;
    gap: 2rem;
  }
  /* Порядок скасовуємо: в один стовпчик фото має бути зверху завжди. */
  .split--reverse .split__media { order: 0; }
}

/* --- фотогалерея --------------------------------------------------- */

/* Чотири в ряд: знімків у галереї бувають десятки, і по два вони
   розтягнули б сторінку на кілометр. auto-fill тут НЕ годиться — при
   десяти кадрах останній ряд лишався б із одним розтягнутим на всю
   ширину, а сітка галереї має бути рівною. */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

@media (max-width: 1100px) {
  .gallery-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 640px) {
  .gallery-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Кнопка, а не div: кадр відкриває переглядач, отже це дія. Але вигляд
   у неї мусить бути як у знімка, тож прибираємо все, що браузер малює
   кнопкам за умовчанням. */
.gallery-grid__item {
  padding: 0;
  border: 0;
  border-radius: 0.5rem;
  background: none;
  cursor: zoom-in;
}

/* --- плитка напряму ----------------------------------------------- */

/* Великий знімок, назва по центру, короткий опис спливає при наведенні.
   Дві в ряд: плитка має бути достатньо великою, щоб фотографія читалася
   як фотографія, а не як іконка. */
/* Мозаїка: ряди різної щільності — 2, потім 3, потім 4 в ряд.

   Щільність приходить із parts/tiles.php інлайновою --cols: саме він
   ріже перелік на ряди, бо тільки він знає кількість плиток. CSS лише
   розставляє колонки.

   Проміжок 4px — замовник просив розділювач найменший. Нуль не ставимо
   свідомо: плитки заокруглені (0,75rem), і впритул заокруглення сусідів
   утворили б між ними хрестики з тла. */
.tiles {
  display: flex;
  flex-direction: column;
  gap: var(--tiles-gap);
}

.tiles__row {
  display: grid;
  grid-template-columns: repeat(var(--cols, 2), 1fr);
  gap: var(--tiles-gap);
}

/* Планшет: більше двох у ряд не ставимо — третя й четверта плитки
   самі переходять нижче, бо сітка доповнює рядки автоматично. Три в
   ряд тут дали б стовпчик вужчий за 300px, і фотографія стала б
   смужкою. */
@media (max-width: 1100px) {
  .tiles__row { grid-template-columns: repeat(2, 1fr); }
}

/* Телефон: один стовпець НА ВСЮ ШИРИНУ екрана, без бічних полів —
   як на edemresort.com, звідки замовник узяв зразок 28.10.

   Від'ємні поля рівно такі, як padding у .container (1,5rem), тобто
   вони його й скасовують. Заокруглення теж знімаємо: заокруглений кут
   упритул до краю екрана читається як недоробка, а не як задум. */
@media (max-width: 860px) {
  .tiles__row { grid-template-columns: 1fr; }

  .tiles {
    margin-left: -1.5rem;
    margin-right: -1.5rem;
  }

  .tiles .tile { border-radius: 0; }
}

.tile {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 310px;
  padding: 2.5rem 1.5rem;
  overflow: hidden;
  border-radius: 0.75rem;
  background: var(--header-bg);
  color: var(--on-band);
  text-align: center;
}

.tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.1s var(--ease-glide);
}

/* Пелена. 0,5 вистачає назві (вона велика — 1,5rem), але не опису: він
   дрібний, і йому треба 4,5:1. Тому при наведенні, разом із появою
   опису, пелена густішає до 0,62 — на суцільно білому кадрі це 6,2:1.
   Заразом темніший фон підкреслює, що плитка «відкрилася». */
.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / 0.5);
  transition: background-color 0.6s var(--ease-glide);
}

.tile:hover::after,
.tile:focus-visible::after { background: rgb(0 0 0 / 0.62); }

.tile:hover img,
.tile:focus-visible img { transform: scale(1.06); }

.tile__body {
  position: relative;
  z-index: 2;
  max-width: 24rem;
  text-shadow: 0 1px 14px rgb(0 0 0 / 0.45);
}

.tile__title {
  display: block;
  font-family: var(--font-head);
  font-size: 1.5rem;
  line-height: 1.25;
}

.tile__rule {
  display: block;
  width: 40px;
  height: 1px;
  margin: 1rem auto 0;
  background: rgb(255 255 255 / 0.7);
}

/* Опис згорнутий у нуль висоти, а не просто прозорий: прозорий займав би
   місце, і назва ніколи не стояла б по центру плитки.

   Анімуємо max-height, а не height: висота тексту залежить від довжини, і
   точного числа тут бути не може. 11rem — стеля з запасом, до неї опис
   не доростає; якщо колись доросте, він просто покажеться без плавності,
   а не обріжеться. */
.tile__text {
  display: block;
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  overflow: hidden;
  font-size: 0.875rem;
  line-height: 1.5;
  transition:
    max-height 0.6s var(--ease-glide),
    opacity 0.5s var(--ease-glide),
    margin-top 0.6s var(--ease-glide);
}

.tile:hover .tile__text,
.tile:focus-visible .tile__text {
  max-height: 11rem;
  margin-top: 1rem;
  opacity: 1;
}

/* Тонка рамка всередині — та сама, що на зразку. Лише підказка, що плитка
   жива, тож і з'являється вона тільки при наведенні. */
.tile__frame {
  position: absolute;
  inset: 1rem;
  z-index: 1;
  border: 1px solid rgb(255 255 255 / 0.55);
  opacity: 0;
  transition: opacity 0.6s var(--ease-glide);
}

.tile:hover .tile__frame,
.tile:focus-visible .tile__frame { opacity: 1; }

/* Пристрої без миші: наводити нема чим, тож опис показуємо одразу, а
   пелену одразу робимо густою. Інакше весь текст був би недосяжним. */
@media (hover: none) {
  .tile::after { background: rgb(0 0 0 / 0.62); }
  .tile__text {
    max-height: 11rem;
    margin-top: 1rem;
    opacity: 1;
  }
  .tile__frame { opacity: 1; }
}

/* Три в ряд — стовпчик вужчий, тож і плитка нижча: при 310px вона на
   широкому екрані виходила б майже квадратною й ряд із трьох займав би
   весь екран. */
/* Висота плитки — від ЕКРАНА, щоб у в'юпорт ставало рівно три ряди.

   Рахунок: під липкою шапкою лишається 100svh − --header-h, звідти
   знімаємо два проміжки між трьома рядами й ділимо на три. На екрані
   900px це дає 270px — рівно стільки, скільки тут і стояло числом,
   але тепер воно тримається на будь-якій висоті вікна.

   svh, а не vh: на телефоні vh — це ВЕЛИКИЙ viewport, тобто висота без
   панелей браузера. Поки вони на екрані, ряд не вміщався б.

   clamp стримує з обох боків. Нижня межа 220px: на ноутбуці 768px без
   неї плитка стиснулась би до 190px, і знімок став би смужкою. Верхня
   340px: на моніторі 1440px три ряди дали б 440px, і три плитки
   займали б увесь екран, як банер, а не як перелік. */
.tiles .tile {
  min-height: clamp(
    220px,
    calc((100svh - var(--header-h) - 2 * var(--tiles-gap)) / 3),
    340px
  );
  padding: 2rem 1.25rem;
}

/* Плитка без посилання (розділ без тексту й без підрозділів).

   Опис показуємо ОДРАЗУ, а не при наведенні. Це не div замість посилання
   заради вигляду: div не отримує фокус, тож :focus-visible на ньому не
   настає ніколи — з клавіатури опис був би недосяжний зовсім. Та й
   спливання при наведенні обіцяє, що плитка жива, а вона нікуди не веде.

   Пелена одразу густа (0,62) — дрібному тексту треба 4,5:1, і на суцільно
   білому кадрі це дає 6,2:1. Рамку й наїзд знімка знімаємо з тієї ж
   причини: обоє натякають на клік. */
.tile--static .tile__text {
  max-height: 11rem;
  margin-top: 1rem;
  opacity: 1;
}

.tile--static::after { background: rgb(0 0 0 / 0.62); }
.tile--static .tile__frame { display: none; }
.tile--static:hover img { transform: none; }

/* --- картка ------------------------------------------------------- */

.card {
  display: block;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  transition: border-color 0.5s var(--ease-glide);
}

.card:hover { border-color: var(--accent); }
.card__body { padding: 1.25rem; }

.card__eyebrow {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent-ink);
  margin: 0;
}

.card__title {
  margin: 0.25rem 0 0;
  font-size: 1.125rem;
  transition: color 0.5s var(--ease-glide);
}

.card:hover .card__title { color: var(--brand); }

.card__price {
  margin: 0.75rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
  font-family: var(--font-head);
  font-size: 1.25rem;
  color: var(--brand);
}

/* Рамка знімка. aspect-ratio тримає сітку рівною навіть коли фото
   різних пропорцій — інакше картки «стрибають» по висоті. */
.ratio-4x3 { aspect-ratio: 4 / 3; background: var(--brand-light); }
.ratio-16x9 { aspect-ratio: 16 / 9; background: var(--brand-light); }

.ratio-4x3 img,
.ratio-16x9 img { width: 100%; height: 100%; object-fit: cover; }

.photo-stub {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: var(--muted);
  font-size: 0.875rem;
}

/* --- підвал ------------------------------------------------------- */

.site-footer {
  background: var(--footer-bg);
  color: var(--on-band);
}

.site-footer__inner {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  padding: 3rem 0;
}

@media (max-width: 900px) {
  .site-footer__inner { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .site-footer__inner { grid-template-columns: 1fr; }
}

.site-footer img { height: 64px; width: auto; }
.site-footer h3 { font-size: 1rem; margin-bottom: 0.75rem; }
/* Наведення — ОСВІТЛЕНЕ золото, не фірмове. На зеленому підвалі
   --accent дає 2,77:1: посилання під курсором ставало б гіршим за
   звичайне біле. --accent-on-dark дає 4,69:1. */
.site-footer a:hover { color: var(--accent-on-dark); }
.site-footer ul { margin: 0; padding: 0; list-style: none; }
.site-footer li { margin-bottom: 0.4rem; font-size: 0.875rem; color: var(--on-band-muted); }

/* Саме те, про що попереджає коментар біля --on-band-muted, і сталося:
   у підвалі стоять class="muted", а .muted — це --muted, розрахований на
   світле тло. На темній смузі він давав 2,3:1 («відділ бронювання», опис
   санаторію під знаком). Тут — 7,7:1. */
.site-footer .muted { color: var(--on-band-muted); }

.site-footer__bottom {
  border-top: 1px solid rgb(255 255 255 / 0.14);
  padding: 1.25rem 0;
  font-size: 0.8rem;
  color: var(--on-band-muted);
}

/* ===================================================================
   РУХ. Перенесено з попередньої версії сайту один в один — замовник
   бачив і схвалив саме це.
   =================================================================== */

[data-reveal] {
  opacity: 0;
  transition:
    opacity var(--reveal-duration) var(--ease-glide),
    transform var(--reveal-duration) var(--ease-glide);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}

[data-reveal="up"]    { transform: translateY(40px); }
[data-reveal="left"]  { transform: translateX(-40px); }
[data-reveal="right"] { transform: translateX(40px); }
[data-reveal="zoom"]  { transform: scale(0.94); }
[data-reveal="fade"]  { transform: none; }

[data-reveal].is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* Шторка: полотно кольору тла з'їжджає вбік і відкриває знімок.
   Напрям задається прив'язкою — left:0 йде ліворуч, right:0 праворуч. */
.curtain { position: relative; overflow: hidden; }

.curtain::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  height: 100%;
  background-color: var(--curtain-color, var(--surface));
  z-index: 5;
  transition: width var(--curtain-duration) var(--ease-glide);
  transition-delay: var(--reveal-delay, 0ms);
}

.curtain[data-from="right"]::after { inset: 0 0 0 auto; }
.curtain.is-visible::after { width: 0%; }

/* Кадр виходить із масштабу повільніше за шторку — різна швидкість дає
   відчуття глибини, а не плаского прямокутника. */
.curtain img {
  transform: scale(1.08);
  transition: transform calc(var(--curtain-duration) * 1.6) var(--ease-glide);
  transition-delay: var(--reveal-delay, 0ms);
}

.curtain.is-visible img { transform: scale(1); }

.hover-lift { transition: transform 0.6s var(--ease-glide); }
.hover-lift:hover { transform: translateY(-4px); }

.zoom-frame { overflow: hidden; }
.zoom-frame img { transition: transform 0.9s var(--ease-glide); }
.card:hover .zoom-frame img { transform: scale(1.06); }

.arrow-slide { display: inline-block; transition: transform 0.6s var(--ease-glide); }
.card:hover .arrow-slide,
a:hover > .arrow-slide { transform: translateX(8px); }

.underline-sweep { position: relative; }
.underline-sweep::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 0%; height: 1px;
  background-color: currentColor;
  transition: width 0.6s var(--ease-glide);
}
.underline-sweep:hover::after,
.card:hover .underline-sweep::after { width: 100%; }

/* На дотикових екранах рух лише заважає: сторінку гортають швидко, і
   половина анімацій не встигає відпрацювати. Ховери там не існують. */
@media (max-width: 1024px) {
  .hover-lift, .zoom-frame img, .arrow-slide, .underline-sweep::after {
    transition: none;
  }
}

/* Для декого рух — не прикраса, а нудота й мігрень. Зміст лишається. */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal].is-visible,
  .curtain::after,
  .curtain img,
  .curtain.is-visible img {
    transition: none !important;
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
  }
  .curtain::after { width: 0% !important; }
}

/* ===================================================================
   ПЕРЕГЛЯДАЧ ФОТО
   =================================================================== */

.lightbox {
  width: 100vw; max-width: 100vw;
  height: 100dvh; max-height: 100dvh;
  margin: 0; padding: 0; border: 0;
  background: transparent;
  overflow: hidden;
  color: #fff;
}

.lightbox::backdrop {
  background: rgb(15 31 44 / 0.94);
  opacity: 0;
  animation: lb-fade 0.3s var(--ease-glide) forwards;
}

.lightbox.is-closing::backdrop {
  animation: lb-fade 0.28s var(--ease-glide) reverse forwards;
}

.lightbox__inner {
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto;
  height: 100%;
  padding: 3.5rem 1rem 1rem;
  opacity: 0;
  animation: lb-in 0.4s var(--ease-glide) forwards;
}

.lightbox.is-closing .lightbox__inner {
  animation: lb-in 0.28s var(--ease-glide) reverse forwards;
}

.lightbox__figure {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0; /* без цього grid не дасть картинці стиснутись по висоті */
  margin: 0;
}

.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 0.5rem;
  animation: lb-next 0.55s var(--ease-glide) both;
}

.lightbox__img[data-dir="prev"] { animation-name: lb-prev; }

.lightbox__btn {
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem; height: 2.75rem;
  border-radius: 9999px;
  background: rgb(255 255 255 / 0.1);
  font-size: 1.5rem;
  line-height: 1;
  transition: background 0.4s var(--ease-glide), transform 0.4s var(--ease-glide);
}

.lightbox__btn:hover { background: rgb(255 255 255 / 0.22); }
.lightbox__close { top: 1rem; right: 1rem; font-size: 1.1rem; }
.lightbox__nav { top: 50%; margin-top: -1.375rem; }
.lightbox__prev { left: 1rem; }
.lightbox__next { right: 1rem; }
.lightbox__prev:hover { transform: translateX(-4px); }
.lightbox__next:hover { transform: translateX(4px); }

.lightbox__bar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding-top: 1rem;
}

.lightbox__counter {
  margin: 0;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  color: rgb(255 255 255 / 0.7);
}

.lightbox__thumbs {
  display: flex;
  gap: 0.5rem;
  max-width: 100%;
  overflow-x: auto;
  padding-bottom: 0.25rem;
}

.lightbox__thumb {
  flex: 0 0 auto;
  width: 4.5rem; height: 3.25rem;
  overflow: hidden;
  border-radius: 0.25rem;
  opacity: 0.45;
  outline: 2px solid transparent;
  outline-offset: 2px;
  transition: opacity 0.4s var(--ease-glide), outline-color 0.4s var(--ease-glide);
}

.lightbox__thumb img { width: 100%; height: 100%; object-fit: cover; }
.lightbox__thumb:hover { opacity: 0.8; }
.lightbox__thumb.is-current { opacity: 1; outline-color: var(--accent); }

@keyframes lb-fade { to { opacity: 1; } }
@keyframes lb-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: none; }
}
/* Напрям в'їзду збігається з напрямом гортання — інакше рух суперечить
   натиснутій стрілці. */
@keyframes lb-next {
  from { opacity: 0; transform: translateX(40px); }
  to   { opacity: 1; transform: none; }
}
@keyframes lb-prev {
  from { opacity: 0; transform: translateX(-40px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 640px) {
  .lightbox__inner { padding: 3.25rem 0.5rem 0.75rem; }
  .lightbox__nav { display: none; } /* на телефоні гортають пальцем */
  .lightbox__thumb { width: 3.5rem; height: 2.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox::backdrop, .lightbox__inner, .lightbox__img {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ===================================================================
   СТОРІНКА НОМЕРА
   =================================================================== */

.room-layout {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 2.5rem;
}

@media (max-width: 900px) {
  .room-layout { grid-template-columns: 1fr; }
}

.room-thumbs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.room-price-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.room-price {
  margin: 0;
  font-family: var(--font-head);
  font-size: 1.875rem;
  color: var(--brand);
}

.room-facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
  text-align: center;
  padding: 1rem 0;
  margin: 0 0 1.5rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.room-facts dt {
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--muted);
}

.room-facts dd {
  margin: 0;
  font-family: var(--font-head);
  font-size: 1.25rem;
}

.amenities {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  color: var(--muted);
}

.amenities li { display: flex; align-items: center; gap: 0.5rem; }

.amenities li::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 9999px;
  background: var(--accent);
  flex: 0 0 auto;
}

/* --- фільтр каталогу ---------------------------------------------- */

.filter-bar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 1.5rem 0;
}

/* Пошук розтягнутий і по центру: це головна дія на сторінці каталогу,
   а притиснутий до лівого краю рядок дрібних полів читався радше як
   службова панель. */
.filter-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: 1rem;
}

/* Поля тягнуться, ділячи ширину порівну, але не вужчають за 10rem —
   нижче цього «Спершу дешевші» в списку вже не вміщується. Кнопка не
   росте: розтягнута на півекрана кнопка виглядає як помилка верстки. */
.filter-form > div {
  flex: 1 1 10rem;
  max-width: 15rem;
}

.filter-form .btn { flex: 0 0 auto; }

.filter-form label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  color: var(--muted);
}

.filter-form select,
.filter-form input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  background: var(--surface);
  font-size: 0.875rem;
}

@media (max-width: 640px) {
  /* На телефоні поля стають на всю ширину: два впівширини дають поля по
     7rem, у які не влазить ні дата, ні назва сортування. */
  .filter-form > div { flex: 1 1 100%; max-width: none; }
}

/* --- таблиця цін --------------------------------------------------- */

.table-wrap {
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.75rem;
}

.price-table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: 0.875rem;
  text-align: left;
}

.price-table thead {
  background: var(--brand-light);
  border-bottom: 1px solid var(--border);
}

.price-table th,
.price-table td { padding: 0.75rem 1.25rem; }
.price-table tbody tr { border-top: 1px solid var(--border); }
.price-table tbody tr:hover { background: rgb(240 232 216 / 0.5); }
.price-table .num { text-align: right; font-family: var(--font-head); color: var(--brand); }

/* --- форми заявок -------------------------------------------------- */

.lead-form { display: grid; gap: 0.75rem; }

.lead-form input,
.lead-form textarea {
  width: 100%;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  font: inherit;
  background: var(--surface);
}

.lead-form .note { font-size: 0.75rem; color: var(--muted); }

.notice-ok,
.notice-err {
  padding: 0.75rem 1rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
}

.notice-ok { background: #e8f5e9; border: 1px solid #a5d6a7; color: #1b5e20; }
.notice-err { background: #fdecea; border: 1px solid #f5a9a3; color: #8a1c13; }

/* ===================================================================
   ПЕРШИЙ ЕКРАН ЗІ СЛАЙД-ШОУ

   Текст лежить поверх фотографій, тому головне тут не краса, а те, щоб
   його було видно на БУДЬ-ЯКОМУ знімку, який завтра завантажить редактор.

   Пелена НЕЙТРАЛЬНА (20,20,20), не зелена. Зелена підфарбовувала знімки:
   дерев'яні меблі зеленіли, біла постіль ішла в болотяний відтінок. Колір
   палітри мають нести смуги й кнопки, а фотографії — лишатися собою.

   Щільність нерівномірна навмисно. Суцільна плівка на всю ширину — це
   спосіб загасити знімок цілком; натомість густа частина тримається там,
   де лежить текст (ліві ~55%), а праворуч сходить майже нанівець. Так
   фото лишається видимим, а літери все одно мають під собою темне.

   Розрахунок, а не «на око». Найгірший випадок — суцільно БІЛЕ фото.
   При 0.62 на білому виходить (109,109,109): контраст білого тексту
   ≈ 5,2:1, тобто AA проходить навіть дрібний підзаголовок. Саме тому
   густа частина не опускається нижче 0.62 — при 0.4 було б уже 3,4:1,
   і підзаголовок зник би на світлому знімку.

   Тінь під текстом — друга лінія оборони, а не оформлення: вона рятує
   те, що попало на світлу пляму всередині кадру, де середня щільність
   нічого не гарантує.

   Якщо колись повернетесь до світлих смуг — пелену треба ПЕРЕВЕРНУТИ
   (світла, текст темний), а не просто освітлити цю.
   =================================================================== */

.hero {
  position: relative;
  /* Висота — від ЕКРАНА, а не фіксоване число пікселів.

     Було `min-height: 780px` разом із `max-height: 90vh`, і ця пара не
     працювала в жодний бік. min-height у CSS сильніший за max-height,
     тому верхня межа не спрацьовувала ніколи: на ноутбуці з вікном 720px
     герой виходив 780px — на 8% вищий за екран, тож перший екран не було
     видно цілком і край наступного блоку не з'являвся. На моніторі 1440p
     ті самі 780px лишали півекрана порожнечі. Герой «підлаштовувався»
     лише під один-єдиний розмір вікна, якого ні в кого немає.

     100% — на весь екран, без світлої смуги під фотографією. Була спроба
     лишати знизу 12% наступного блоку як підказку «гортайте далі», але
     на екрані це читалося не як підказка, а як недомальований край.
     Що сторінка триває, кажуть крапки слайд-шоу й сам рух кадрів.

     svh, а не vh: на телефоні vh — це ВЕЛИКИЙ viewport, тобто висота
     вікна БЕЗ адресного рядка. Поки рядок видно (а при відкритті його
     видно завжди), 100vh — це більше, ніж є насправді: низ кадру разом
     із крапками йде за межу екрана, а коли рядок ховається — сторінка
     підстрибує. svh рахує від малого viewport, тому кадр правильний
     одразу. Рядок вище — запасний для браузерів без svh.

     Це МІНІМУМ, не фіксована висота: якщо заголовок перенесеться на
     більше рядків, ніж влазить, смуга виросте під текст, а не обріже
     його. Через це max-height тут і не потрібен. */
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-items: center;
  overflow: hidden;
  background: var(--brand-light);
}

.hero__slides {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.4s var(--ease-glide);
}

.hero__slide.is-active { opacity: 1; }

.hero__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Повільний наїзд, поки кадр показується: статична фотографія під
     текстом виглядає як заставка, а не як живий сайт. */
  transform: scale(1.04);
  transition: transform 7s linear;
}

.hero__slide.is-active img { transform: scale(1); }

/* Пелена світла, а читабельність тримає ТІНЬ під літерами.

   Шлях сюди був довгий, і проміжні спроби варто знати, щоб не ходити
   колом удруге.

   1. Спершу тут був один поперечний шар на всю висоту (0,74→0,66 до
      62% ширини). Контраст давав, але глушив і небо, і газон, де тексту
      немає. Замовник: «затемнення видно надто сильно».
   2. Потім — щільна еліптична пляма тільки під текстом. Кадр посвітлішав
      (0,551→0,399), контраст не впав. Але пляма стала ПОМІТНОЮ ЯК ФОРМА:
      крутизна краю 0,0361 проти 0,0222 у рівної вуалі. Замовник: «ріже око».
   3. Кутові варіанти (затемнення від краю, як віньєтка) виходять дуже
      плавними — 0,007, — але дають лише 2,2:1: надзаголовок стоїть на
      y 43%, куди затемнення від низу ще не дійшло. Не придатні.

   Глухий кут розмикає тінь: вона створює темряву ВПРИТУЛ до літери, тому
   загальну вуаль можна різко послабити. Тепер:

     вуаль   середня щільність 0,348 (стара 0,543), крутизна 0,0020
             (стара 0,0222) — як форму її вже не вловити;
     текст   6,0:1 на найгіршому місці найсвітлішого кадру.

   Числа — не на око: вуаль накладено попіксельно на всі п'ять кадрів із
   урахуванням object-fit: cover; щільність тіні біля гліфа взято
   ОБЕРЕЖНО (0,45, хоча розрахунок дає ~0,67).

   ВАЖЛИВО. WCAG тіней не зараховує. По самій лише вуалі формально
   виходить 2,28:1, і сувора перевірка доступності це позначить. Рішення
   свідоме: замовник двічі сказав, що вуаль заважає дивитись фотографію.
   Треба буде формальна відповідність — щільність плями піднімається до
   0,44/0,40 («світла M»), це дає 3,55:1 формально й 8,15:1 з тінню, але
   кадр знову темніє до 0,498.

   Текст героя — ЧИСТО БІЛИЙ. Раніше надзаголовок був 0,85, підзаголовок
   0,9 — приглушення коштувало цілого пункту контрасту задарма.

   Чорної смуги згори тут немає: відколи смуга меню напівпрозоро-зелена,
   цю роботу виконує вона. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(
      ellipse 140% 160% at 28% 58%,
      rgb(20 20 20 / 0.30) 0%,
      rgb(20 20 20 / 0.26) 75%,
      rgb(20 20 20 / 0) 100%
    ),
    linear-gradient(
      to right,
      rgb(20 20 20 / 0.14) 0%,
      rgb(20 20 20 / 0.11) 50%,
      rgb(20 20 20 / 0.04) 80%,
      rgb(20 20 20 / 0) 100%
    );
}

.hero__inner {
  position: relative;
  z-index: 2;
  padding: 4.5rem 0;
  max-width: 46rem;
  /* Друга лінія оборони: середня щільність пелени нічого не обіцяє на
     локальній світлій плямі всередині кадру. */
  text-shadow: 0 1px 14px rgb(0 0 0 / 0.45);
}

/* Тінь — це те, чим тримається читабельність при світлій вуалі (див.
   пояснення коло .hero__veil). Два шари: щільний впритул до літери й
   широкий розсіяний. Розмиття дрібному тексту менше — 18px навколо
   літери 12,8px читалося б як брудна пляма, а не як тінь.

   Щільність біля гліфа виходить ~0,75 (дрібний) і ~0,70 (заголовок),
   тоді як у розрахунку контрасту закладено обережні 0,45. Тобто
   справжній контраст вищий за виміряні 6,0:1, а не нижчий. */
.hero__eyebrow,
.hero__sub {
  text-shadow:
    0 1px 2px rgb(10 10 10 / 0.5),
    0 1px 10px rgb(10 10 10 / 0.5);
}

.hero__title {
  text-shadow:
    0 1px 2px rgb(10 10 10 / 0.45),
    0 2px 18px rgb(10 10 10 / 0.5);
}

.hero__eyebrow {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  /* Чисто біле, не 0,85: приглушення коштувало цілого пункту контрасту. */
  color: #fff;
}

.hero__title {
  margin: 0;
  font-size: 3rem;
  line-height: 1.12;
  color: #fff;
  text-wrap: balance;
}

.hero__sub {
  margin: 1.25rem 0 2rem;
  font-size: 1.05rem;
  /* Чисто біле, не 0,9 — з тієї ж причини, що й надзаголовок. */
  color: #fff;
}

.hero__cta { display: flex; flex-wrap: wrap; gap: 0.75rem; }

/* Крапки перемикання. Дрібні, але це єдиний спосіб зрозуміти, що кадрів
   кілька, і єдиний спосіб керувати ними з клавіатури. */
.hero__dots {
  position: absolute;
  z-index: 2;
  left: 0; right: 0; bottom: 1.5rem;
  display: flex;
  justify-content: center;
  gap: 0.5rem;
}

.hero__dot {
  width: 34px;
  height: 3px;
  border-radius: 99px;
  background: rgb(255 255 255 / 0.3);
  transition: background 0.5s var(--ease-glide);
}

.hero__dot.is-active { background: rgb(255 255 255 / 0.85); }
.hero__dot:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }

@media (max-width: 900px) {
  /* Окремих меж висоти тут більше немає: 88svh однаково правильні і на
     телефоні, і на моніторі, бо рахуються від екрана. Колишні 660px
     були на вузькому телефоні вищі за сам екран. */
  .hero__title { font-size: 2.1rem; }
  /* На телефоні текст займає майже всю ширину, тож плями під ним не
     зробиш — вуаль тут рівна. Але щільною їй бути вже не треба:
     читабельність, як і на моніторі, тримає тінь під літерами.

     Було 0,74→0,62 (5,1:1 самою лише вуаллю). Стало 0,28→0,22: разом із
     тінню це 4,8:1, а кадр світліший удвічі з гаком. Числа навмисно
     трохи щільніші за настільні — тут немає ні плями, ні широкого
     правого краю, куди можна було б відпустити.

     Знак і кнопка в шапці тіні не мають. Їх тримає сама смуга меню —
     вона напівпрозоро-зелена. Робитимете шапку прозорою — поверніть
     сюди смугу затемнення згори, інакше знак зникне на світлих кадрах. */
  .hero__veil {
    background: linear-gradient(
      100deg,
      rgb(20 20 20 / 0.28) 0%,
      rgb(20 20 20 / 0.25) 60%,
      rgb(20 20 20 / 0.22) 100%
    );
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__slide,
  .hero__slide img {
    transition: none;
  }
}
