/*
  Общий слой для всех страниц: сброс, типографика, шапка, подвал, кнопки.
  Опорный экран — лендинг: решения приняты здесь, остальные экраны берут их
  готовыми (см. docs/frontend-rules.md).

  Цвета, шрифты, кегли и скругления — только токенами из tokens.css.
  Отступы, толщины границ, тени и межстрочные интервалы шкалы не образуют
  (об этом сказано в конце tokens.css), поэтому они стоят теми же числами,
  какими стоят в прототипе, — ни одно не подобрано заново.
*/

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

/*
  Атрибут hidden должен прятать элемент всегда.
  Браузер задаёт ему display:none слабым правилом, и любой наш класс с
  display:flex или display:grid его перебивает — элемент остаётся на экране,
  хотя в коде он скрыт. Эту ловушку мы уже поймали на блоке подтверждения.
*/
[hidden] { display: none !important; }

html {
  scroll-behavior: smooth;

  /*
    Отступ прокрутки под шапку.

    Шапка выведена из потока (position: fixed), поэтому переход по якорю
    ставил начало раздела под неё: заголовок «Как проходят занятия»
    оказывался на 54–90 px, а шапка заканчивалась на 188 px — заголовок
    целиком скрыт, и выглядело это как «переход не сработал».

    Высоту шапки меряет header.js и кладёт в --header-height; на узком
    экране меню переносится, и значение меняется само. Запасные 100px — на
    случай, если прокрутка случится раньше первого замера.

    Действует и на родной переход по якорю, и на scrollIntoView в landing.js.
  */
  scroll-padding-top: var(--header-height, 100px);
}

body {
  margin: 0;
  font-family: var(--font-family);
  font-size: var(--font-size-body);
  color: var(--color-text-primary);
  background: var(--color-surface);
  -webkit-font-smoothing: antialiased;
}

/*
  Горизонтальную прокрутку убираем здесь, а не у body.
  overflow на body делает его областью прокрутки, и position: sticky у шапки
  перестаёт работать — она уезжает вверх вместе со страницей.
  Всё, что торчит за край, обрезается там, где торчит: у декора хиро и у ленты
  отзывов, у каждого свой overflow.
*/
html { overflow-x: hidden; }

a { color: var(--color-link); text-decoration: none; }
a:hover { color: var(--color-link-hover); }

button { font-family: inherit; border: none; background: none; cursor: pointer; }
input, select, textarea { font-family: inherit; }

h1, h2, h3 { margin: 0; }

/* Ширина содержимого одинакова во всех блоках прототипа. */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
}

/* --- Шапка ---------------------------------------------------------------- */

/*
  Полоса, в которой живёт шапка. Держится выше содержимого на всех страницах.

  position: fixed, а не sticky. Sticky держится только пока виден родитель:
  шапка лежит внутри фирменного блока страницы и уехала бы вверх вместе с ним.
  Fixed выводит её из потока совсем — она видна всегда, на любой прокрутке.

  Раз полоса вне потока, место под неё освобождает сам фирменный блок:
  отступ сверху ровно в её высоту. Высоту меряет header.js и кладёт в
  --header-height: на узком экране меню переносится, и полоса становится выше.

  Фона у полосы нет, пока страница не прокручена: под ней фирменный градиент
  самой страницы, и свой фон дал бы шов. После прокрутки под ней обычное
  содержимое — тогда фон появляется, иначе текст полез бы сквозь.
*/
.site-header-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
}

.site-header-bar--scrolled {
  background: linear-gradient(135deg, var(--color-gradient-from) 0%, var(--color-gradient-to) 100%);
  box-shadow: 0 8px 32px rgba(12, 34, 51, 0.16);
}

/* Фирменные блоки страниц: под ними начинается содержимое, сверху — шапка. */
.hero,
.auth-top,
.stub-header,
.cabinet-top,
.admin-top {
  padding-top: var(--header-height, 100px);
}

/*
  Полоса под шапкой на экранах без своего фирменного блока: вход, регистрация,
  восстановление пароля и все пять экранов записи.

  Правило стоит здесь, а не в auth.css, где было раньше. Имя обманывало:
  блок называется auth-top, но принадлежит не экранам входа, а общей шапке —
  выше он уже перечислен вместе с .hero и .cabinet-top. Экраны записи
  auth.css не подключают, и полоса на них оставалась светлой, а логотип,
  телефон и имя на ней нарисованы белым: шапка была нечитаемой на
  booking-service, booking-teacher, booking-time, booking-done и booking-card.
*/
.auth-top {
  background: linear-gradient(135deg, var(--color-gradient-from) 0%, var(--color-gradient-to) 100%);
}

.site-header {
  position: relative;
  z-index: 3;
  max-width: 1200px;
  margin: 0 auto;
  padding: 28px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
/* Кегль логотипа — из прототипа. */
.site-header__logo {
  font-size: var(--font-size-logo);
  font-weight: var(--font-weight-bold);
  color: var(--color-text-inverse);
}
.site-header__logo:hover { color: var(--color-text-inverse); }

.site-nav { display: flex; gap: 16px; flex-wrap: wrap; }

.site-nav__link {
  color: var(--color-text-inverse);
  font-size: var(--font-size-body-lg);
  border: 1px solid var(--color-border-inverse);
  border-radius: var(--radius-pill);
  padding: 8px 18px;
}
.site-nav__link:hover {
  color: var(--color-text-inverse);
  border-color: var(--color-text-inverse);
  background: rgba(255, 255, 255, 0.08);
}

/*
  Перенос обязателен. Без него содержимое правой части шапки не умещалось на
  узком экране и уезжало за правый край: при 392px имя и кружок с инициалами
  начинались на 400px, то есть были за границей экрана целиком и нажать их
  было нельзя. На широком экране перенос ничего не меняет — места хватает.
*/
.site-header__side { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }

.site-header__phone {
  color: var(--color-text-inverse);
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-medium);
}

/*
  Выбор раздела для тех, у кого ролей больше одной.

  Две ссылки в одной обводке: видно и то, где человек сейчас, и то, куда
  он может перейти. Одиночная кнопка этого не показывала бы — по ней не
  понять, что есть второй раздел и в котором ты находишься.

  Шапка всегда лежит на фирменном градиенте: либо на блоке самой страницы,
  либо на своём фоне после прокрутки. Поэтому цвета здесь «обратные» —
  белый текст и полупрозрачная белая обводка, те же, что у кнопки рядом.
  Новых значений не заведено.
*/
.role-switch {
  display: flex;
  border: 2px solid var(--color-border-inverse);
  border-radius: var(--radius-pill);
  padding: 2px;
}

.role-switch__item {
  height: 36px;
  padding: 0 16px;
  display: flex;
  align-items: center;
  border-radius: var(--radius-pill);
  color: var(--color-text-inverse);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}
.role-switch__item:hover {
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-text-inverse);
}

/* Текущий раздел залит — он читается как нажатое положение переключателя. */
.role-switch__item--current {
  background: var(--color-surface);
  color: var(--color-link);
}
.role-switch__item--current:hover {
  background: var(--color-surface);
  color: var(--color-link);
}

/* Кнопка регистрации в шапке — того же роста, что и «Войти» рядом. */
.site-header__register {
  height: 44px;
  padding: 0 24px;
  font-size: var(--font-size-body);
}

/* Вошедший клиент: имя и аватар, как в шапке кабинета из прототипа. */
.site-header__account {
  display: flex;
  align-items: center;
  gap: 12px;
}
.site-header__account:hover .site-header__name { color: var(--color-text-inverse); }

.site-header__name {
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-inverse);
}

/* Аватара в базе нет — в кружке инициалы. Размер тот же, 40px. */
.site-header__avatar {
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: var(--radius-circle);
  background: var(--color-surface-accent);
  color: var(--color-surface-inverse);
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
}

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

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-card);
  font-size: var(--font-size-button);
  font-weight: var(--font-weight-semibold);
  text-align: center;
}

.button--accent {
  background: var(--color-button);
  color: var(--color-button-text);
}
.button--accent:hover {
  background: var(--color-button-hover);
  color: var(--color-button-text);
}

/* Обводка по белому — кнопка «Личный кабинет» в шапке на градиенте. */
.button--outline-inverse {
  height: 44px;
  padding: 0 24px;
  border: 2px solid var(--color-text-inverse);
  color: var(--color-text-inverse);
  font-size: var(--font-size-body);
}
.button--outline-inverse:hover {
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-text-inverse);
}

.button--outline {
  background: var(--color-surface);
  color: var(--color-link);
  border: 2px solid var(--color-link);
}
.button--outline:hover { background: var(--color-surface); color: var(--color-link); }

/* --- Сообщение об ошибке -------------------------------------------------- */

/*
  Ошибку от API человек должен прочитать на странице (правило 7).
  Цвета ошибки в токенах нет намеренно — в прототипе нет ни одного красного,
  поэтому сообщение выделено светло-голубой подложкой из палитры, а не цветом.
*/
.error-text {
  margin: 0;
  padding: 14px 20px;
  border-radius: var(--radius-card);
  background: var(--color-surface-accent);
  color: var(--color-text-primary);
  font-size: var(--font-size-body);
  line-height: 1.5;
}

.error-text[hidden] { display: none; }

/* --- Заглушка на месте данных, пока они грузятся -------------------------- */

/*
  Пока ответ не пришёл, на месте карточек стоят их пустые силуэты: страница
  не дёргается, когда данные приезжают, и не показывает пустое место.
*/
.skeleton {
  background: var(--color-surface-accent);
  border-radius: var(--radius-card);
  color: transparent;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
}

@keyframes skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .skeleton { animation: none; }
}

/* --- Подвал --------------------------------------------------------------- */

.site-footer {
  background: var(--color-surface-inverse);
  padding: 64px 24px 32px;
}

.site-footer__inner { max-width: 1200px; margin: 0 auto; }

.site-footer__columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 32px;
  margin-bottom: 48px;
}

.site-footer__logo {
  color: var(--color-text-inverse);
  font-size: var(--font-size-card-title);
  font-weight: var(--font-weight-bold);
  margin-bottom: 12px;
}

.site-footer__tagline {
  color: var(--color-text-secondary);
  font-size: var(--font-size-small);
  line-height: 1.6;
  margin: 0;
}

.site-footer__title {
  color: var(--color-text-inverse);
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-semibold);
  margin-bottom: 16px;
}

.site-footer__list { display: flex; flex-direction: column; gap: 10px; }

.site-footer__link,
.site-footer__note {
  color: var(--color-text-secondary);
  font-size: var(--font-size-small);
}
.site-footer__link:hover { color: var(--color-link-inverse); }

.site-footer__divider {
  height: 1px;
  background: var(--color-surface-inverse-alt);
  margin-bottom: 24px;
}

.site-footer__bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

/* --- Узкий экран ---------------------------------------------------------- */

/*
  Всё, что ниже, действует только на узких экранах. Настольная версия выше
  этой черты не меняется ни в одном правиле: порог стоит на 768px — это
  граница планшета и телефона, ниже неё блоки, стоявшие рядом, перестают
  помещаться в строку.

  Порог один на весь проект. Второй («телефон» и «маленький телефон») завести
  было бы можно, но сейчас ни одно правило в нём не нуждается: то, что чинится
  здесь, чинится одинаково и на 320px, и на 767px.

  Кегли берутся из tokens.css как есть — уменьшённых вариантов не заведено
  (правило 4: новых значений не добавляем). Где текст не помещается, ему дан
  меньший кегль из уже существующих, а не подобранный.
*/

@media (max-width: 767px) {
  /* Поля страницы: 24px на 375px забирают восьмую часть ширины. */
  .container { padding: 0 16px; }

  /* --- Шапка -------------------------------------------------------------- */

  .site-header {
    padding: 16px;
    gap: 12px;
  }

  /*
    Порядок на узком экране: логотип, кнопка меню, вход — в одну строку,
    меню разделов уходит под них целой строкой. В разметке меню стоит раньше
    кнопки входа, поэтому порядок задан здесь, а не перестановкой в JS.
  */
  .site-header__toggle { order: 1; }
  .site-header__side { order: 2; gap: 12px; }
  .site-nav { order: 3; }

  /*
    Свёрнутое меню. Не display:none у ссылок, а невывод всего блока: так его
    не читает и скринридер, пока оно свёрнуто, — иначе он озвучивал бы пять
    ссылок, которых на экране нет.
  */
  .site-nav {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    gap: 8px;
  }

  .site-header--menu-open .site-nav { display: flex; }

  /* Ссылка раздела — во всю строку: в узкую таблетку труднее попасть пальцем. */
  .site-nav__link {
    padding: 12px 18px;
    text-align: center;
  }

  /*
    Телефон разрывался по одному символу в строку («+7 / 961- / 466- / 96- / 20»)
    — он попадал в колонку шириной с самое длинное слово. Запрет переноса
    ставит его в строку целиком.
  */
  .site-header__phone { white-space: nowrap; }

  /* --- Подвал ------------------------------------------------------------- */

  .site-footer { padding: 48px 16px 24px; }
  .site-footer__columns { gap: 24px; margin-bottom: 32px; }
}

/*
  Кнопка «Меню» существует только на узком экране: на широком все пять
  разделов стоят в шапке сами. Правило вне медиазапроса, чтобы настольная
  версия не зависела от порядка подключения файлов.
*/
.site-header__toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-border-inverse);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--color-text-inverse);
}

/*
  Три полоски. Средняя — сам элемент, крайние — его псевдоэлементы, поэтому
  в разметке кнопки лежит один пустой span, а не три.
  Цвет берётся от кнопки (currentColor): он у неё уже правильный — белый
  на фирменном градиенте.
*/
.site-header__burger,
.site-header__burger::before,
.site-header__burger::after {
  display: block;
  width: 22px;
  height: 2px;
  border-radius: var(--radius-pill);
  background: currentColor;
}

.site-header__burger { position: relative; }

.site-header__burger::before,
.site-header__burger::after {
  content: '';
  position: absolute;
  left: 0;
  transition: transform 0.2s ease, top 0.2s ease;
}

.site-header__burger::before { top: -7px; }
.site-header__burger::after { top: 7px; }

/*
  Раскрытое меню — крестик: кнопка показывает не то, что откроется, а то,
  что произойдёт по нажатию, и второй раз её ищут уже как «закрыть».
  Средняя полоска исчезает, крайние сходятся и поворачиваются.
*/
.site-header--menu-open .site-header__burger { background: transparent; }

.site-header--menu-open .site-header__burger::before {
  top: 0;
  transform: rotate(45deg);
}

.site-header--menu-open .site-header__burger::after {
  top: 0;
  transform: rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
  .site-header__burger::before,
  .site-header__burger::after { transition: none; }
}

@media (max-width: 767px) {
  .site-header__toggle { display: inline-flex; }
}

.site-header__toggle:hover {
  border-color: var(--color-text-inverse);
  background: rgba(255, 255, 255, 0.08);
}

/* Счётчик непрочитанных уведомлений на аватаре. Число приходит с сервера, в разметке его нет. */
.site-header__account { position: relative; }

.site-header__count {
  position: absolute;
  top: -8px;
  right: -8px;
  box-sizing: border-box;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--color-button);
  color: var(--color-button-text);
  font-size: var(--font-size-tag);
  font-weight: var(--font-weight-semibold);
}
