/* === FONTS === */
@font-face {
  font-family: 'HistoryPro';
  src: url('../assets/fonts/HistoryPro-Two.woff2') format('woff2'),
       url('../assets/fonts/HistoryPro-Two.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Thin.woff') format('woff');
  font-weight: 100;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Light.woff') format('woff');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Medium.woff') format('woff');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Semibold.woff') format('woff');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Farabee';
  src: url('../assets/fonts/Farabee-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* === VARIABLES === */
:root {
  --color-bg: #0c0b17;
  --color-bg-dark: #101115;
  --color-gold: #c69d4f;
  --color-white: #ffffff;
  --color-light: #e4e4e4;
  --color-muted: #d7d7d7;

  --font-heading: 'HistoryPro', Arial, sans-serif;
  --font-body: 'Farabee', Arial, sans-serif;

  --header-height: 5.75rem;
  --container-width: 75rem;
  --border-radius: 0.9375rem;

  --btn-frame-fill: rgba(12, 11, 23, 0.78);
  --btn-frame-left: url('../assets/img/button-left.svg');
  --btn-frame-right: url('../assets/img/button-right.svg');

  --transition-default: 0.2s ease-in-out;
}

/* === RESET & BASE === */
*,
*::before,
*::after {
  box-sizing: border-box;
}

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

html {
  scroll-behavior: smooth;
  scrollbar-gutter: stable;
  /* Backstop, not the fix itself (that's .mobile-menu's own overflow:hidden,
     see its comment) — a page this animation-heavy (off-canvas menu,
     parallax, cutscene overlays, hscroll-wrap) will likely grow another
     off-viewport-by-transform element eventually, and without this any one
     of them silently makes the *entire page* horizontally scrollable, which
     shifts every fixed-width section relative to the frame and reads as
     that section's own content being randomly cropped. Nothing in this
     design is meant to scroll sideways, so there's no real layout this
     could break. */
  overflow-x: hidden;
  /* Fluid scale: design is pixel-perfect at 2000px (1rem = 16px there).
     Below 2000px every rem-based size shrinks in lockstep with the
     viewport down to 920px. */
  font-size: clamp(7.36px, 0.8vw, 16px);
}

/* Below 980px (this codebase's own mobile-layout threshold — see the
   max-width:980/639/479 blocks throughout) the fluid scale above would
   keep shrinking rem sizes toward an unreadable floor. Components with
   dedicated mobile overrides in those blocks (all raw px) are unaffected
   either way, but the many components that only use rem sizing (body
   copy, buttons, nav, footer, and every programs/*.html detail page via
   program.css) were silently collapsing to ~46% of their intended size
   on phones. Locking the root back to a normal 16px here restores their
   designed values. */
@media (max-width: 980px) {
  html {
    font-size: 16px;
  }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

body {
  animation: fadeIn 0.5s ease-in-out both;
  background-color: var(--color-bg);
  color: var(--color-white);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.55;
  overflow-x: hidden; /* belt-and-braces alongside html's — see its comment */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
  font-weight: 700;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
  transition: color var(--transition-default);
}

a:hover {
  color: var(--color-muted);
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}

/* === CONTAINER === */
.container {
  width: 100%;
  max-width: var(--container-width);
  margin: 0 auto;
  padding: 0 1.25rem;
}

/* === HEADER === */
.header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* На единицу выше .mobile-menu (100000): бургер обязан остаться кликабельным
     поверх открытого меню — именно он и превращается в крестик. z-index
     поднят на .header, а не на .burger, потому что .header со своим z-index
     создаёт стековый контекст, и ребёнок из него не выпрыгнет. */
  z-index: 100001;
  height: var(--header-height);
  background: transparent;
  display: flex;
  align-items: center;
}


.header__inner {
  width: 100%;
  max-width: 81.25rem;
  margin: 0 auto;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 2.5rem;
}

.header__logo {
  position: absolute;
  top: 50%;
  left: 2.5rem;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.header__logo img {
  height: 5rem;
  width: auto;
}

.header__nav {
  display: none;
  align-items: center;
  gap: 3.125rem;
}

.header__nav-link {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--color-white);
  text-transform: uppercase;
  transition: color var(--transition-default);
}

.header__nav-link:hover {
  color: var(--color-muted);
}

.header__socials {
  display: none;
  align-items: center;
  gap: 0.875rem;
}

.header__social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  transition: opacity var(--transition-default);
}

.header__social-link:hover {
  opacity: 0.75;
}

.header__social-link svg {
  width: 2.75rem;
  height: 2.75rem;
}

/* === BURGER === */
.burger {
  position: absolute;
  top: 50%;
  right: 2.5rem;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 3.5rem;
  height: 3.5rem;
  background-color: rgba(12, 11, 23, 0.5);
  border: 1.5px solid var(--color-gold);
  border-radius: 50%;
  cursor: pointer;
}

/* Раньше здесь было opacity:0 — бургер прятался, потому что закрывал меню
   крестик внутри панели. Теперь крестик — это сам бургер, так что кнопка
   остаётся на месте и видимой, только линии складываются в X (ниже). */
.burger.is-active {
  border-color: var(--color-white);
}

.burger__line {
  display: block;
  width: 1.75rem;
  height: 0.125rem;
  background-color: var(--color-gold);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.15s ease-in-out;
}

.burger__line + .burger__line {
  margin-top: 0.375rem;
}

.burger.is-active .burger__line:nth-child(1) {
  transform: translateY(0.5rem) rotate(45deg);
}

.burger.is-active .burger__line:nth-child(2) {
  opacity: 0;
}

.burger.is-active .burger__line:nth-child(3) {
  transform: translateY(-0.5rem) rotate(-45deg);
}

/* === MOBILE MENU === */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: flex;
  justify-content: flex-end;
  align-items: flex-start;
  visibility: hidden;
  /* Никакого opacity-фейда на обёртке: он раньше перекрывал первую треть
     анимации панели (влёт круглой плашки), и открытие читалось как резкий
     поп. Прячем только через visibility, с задержкой на время закрытия. */
  transition: visibility 0s linear 0.45s;
  /* .mobile-menu__panel sits translateX(100%) off its own right edge while
     closed — a deliberate off-canvas slide-in. Without overflow:hidden HERE
     (on the exactly-viewport-sized fixed wrapper), that translated panel's
     box still counts toward the page's real scrollable width in Chromium,
     even though .mobile-menu itself is `position:fixed; inset:0`. On narrow
     viewports that's real, draggable horizontal scroll on the *whole page*
     — every fixed-width section then visibly shifts as that scroll offset
     changes, which is what actually produced the various "cropped edge"
     reports this session, not any single section's own layout. */
  overflow: hidden;
}

.mobile-menu.is-open {
  visibility: visible;
  transition-delay: 0s;
}

.mobile-menu__overlay {
  position: absolute;
  inset: 0;
  background-color: transparent;
}

.mobile-menu__panel {
  position: relative;
  z-index: 1;
  width: min(21.25rem, calc(100vw - 5rem));
  height: auto;
  max-height: calc(100vh - var(--header-height) - 1.5rem);
  max-height: calc(100dvh - var(--header-height) - 1.5rem);
  /* Раскрывается из бургера: правый край панели совпадает с правым краем
     кнопки (.burger: right 2.5rem), верх — сразу под шапкой. Вместе с
     transform-origin: 100% 0 это даёт рост ровно из-под кнопки. */
  margin: calc(var(--header-height) - 0.5rem) 2.5rem auto auto;
  /* НИКАКОГО backdrop-filter здесь. blur() на движущемся элементе заставляет
     браузер каждый кадр заново размывать всё, что под ним (а под ним — hero
     с видео и параллаксом). Стекло включается одним кадром после анимации,
     см. menu-glass-in. */
  background: rgba(12, 11, 23, 0.92);
  border: 1px solid rgba(198, 157, 79, 0.3);
  border-radius: 1.75rem;
  padding: 1.875rem 1.5rem;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  /* Анимируются только transform и opacity — их гонит композитор на GPU.
     Любой морфинг border-radius / width / height здесь означает перерисовку
     блока каждый кадр в одном потоке с GSAP и просадку до единиц fps. */
  transform: scale(0.05);
  transform-origin: 100% 0;
  opacity: 0;
  backface-visibility: hidden;
  transition: transform 0.28s cubic-bezier(0.4, 0, 1, 0.5),
    opacity 0.2s ease-in 0.08s;
}

.mobile-menu.is-open .mobile-menu__panel {
  animation: menu-scale-in 0.42s cubic-bezier(0.22, 1, 0.36, 1) forwards,
    menu-glass-in 0.01s linear 0.42s forwards;
  will-change: transform;
}

@keyframes menu-scale-in {
  0% {
    transform: scale(0.05);
    opacity: 0;
  }
  20% {
    opacity: 1;
  }
  100% {
    transform: scale(1);
    opacity: 1;
  }
}

/* Стекло появляется одним кадром, когда панель уже стоит на месте: фон
   разжижается с 0.92 до 0.7 ровно в тот момент, когда включается blur, —
   суммарная плотность почти не меняется, переключение незаметно. */
@keyframes menu-glass-in {
  to {
    background: rgba(12, 11, 23, 0.7);
    backdrop-filter: blur(0.625rem);
  }
}

.mobile-menu__panel > * {
  opacity: 0;
  transition: opacity 0.12s ease-in;
}

.mobile-menu.is-open .mobile-menu__panel > * {
  animation: menu-content-in 0.26s ease-out 0.2s forwards;
}

@keyframes menu-content-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu.is-open .mobile-menu__panel,
  .mobile-menu.is-open .mobile-menu__panel > * {
    animation: none;
    opacity: 1;
  }
  .mobile-menu.is-open .mobile-menu__panel {
    transform: none;
  }
}

/* Крестик внутри панели не нужен: закрывает сам бургер — его линии
   складываются в X по .burger.is-active. Элемент оставлен в разметке
   (он в index.html и во всех programs/*.html), просто скрыт. */
.mobile-menu__close {
  display: none;
}

.mobile-menu__logo {
  margin-bottom: 2rem;
}

.mobile-menu__logo img {
  height: 3.75rem;
  width: auto;
}

.mobile-menu__nav {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.mobile-menu__nav-link {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  color: var(--color-white);
  padding: 0.625rem 0;
  transition: color var(--transition-default);
}

.mobile-menu__nav-link:hover {
  color: #f7f7f7;
}

.mobile-menu__socials {
  margin-top: 2rem;
  display: flex;
  gap: 0.75rem;
}

.mobile-menu__social-link {
  display: flex;
  align-items: center;
  width: 2.625rem;
  height: 2.625rem;
  transition: opacity var(--transition-default);
}

.mobile-menu__social-link:hover {
  opacity: 0.75;
}

.mobile-menu__social-link svg {
  width: 2.625rem;
  height: 2.625rem;
}

/* === HERO === */
/* Matches #hero's own height at all times (see the comment in the markup —
   this keeps reserving that space in normal flow while main.js switches
   #hero itself to position:fixed for the intro). */
.hero-pin-wrap {
  position: relative;
  height: 100vh;
  min-height: 56.25rem;
}

.hero {
  position: relative;
  min-height: 56.25rem;
  height: 100vh;
  /* z-index: 50 is applied inline by main.js only while #hero is switched
     to position:fixed for the intro (needed there — .ba-section, later in
     the DOM and also positioned, would otherwise paint on top of it, since
     fixed alone doesn't win a stacking fight against later DOM order at the
     same z-index: auto level). NOT set here permanently: .ba-section__title
     overlaps up into this section's box (see its own negative margin), and
     a standing z-index here would bury it under hero every time. */
  display: flex;
  align-items: flex-end;
  justify-content: center;
  overflow: hidden;
}

.hero__bg {
  position: absolute;
  inset: 0;
  background-color: #101115;
  z-index: 0;
}

.hero__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Full-bleed flex column spanning the whole hero, title group at the top
   and the CTA + promo ribbon pinned to the bottom via .hero__bottom {
   position: absolute; bottom: 0 } — .hero__top and .hero__bottom are the
   only two children. Kept as ONE .hero__content element (not split across
   separate top/bottom siblings of .hero) because main.js fades this exact
   class as a unit during the scroll-into-portfolio cutscene — see the
   `content` var in main.js. */
.hero__content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  text-align: center;
  /* Drives ::before/::after's opacity below — a plain CSS var (not a
     transition) because main.js's hero cutscene tweens it directly with
     GSAP, in step with the title/CTA/promo fading out and back in, instead
     of the wash sitting there fixed while everything else around it fades.
     Desktop only in practice (only that cutscene ever touches it); mobile
     never scrolls past 1 since nothing writes to it there. */
  --hero-wash-opacity: 1;
}

/* Top wash + soft radial shadow under the title — plain gradients only.
   rgba(7, 6, 14, ...) instead of a near-black: same dark-navy tone the rest
   of the site's darkening overlays already use for their partial-opacity
   stops (.ba-section__gradient, .ouija-section__gradient, .children-section__
   overlay, .footer-bg-wrap__overlay, .team-section__overlay all key off this
   exact rgb triplet) — was rgba(4, 3, 10, ...) here only, which reads as
   flat black instead of matching that navy cast. */
.hero__content::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: var(--hero-wash-opacity, 1);
  background: linear-gradient(
    to bottom,
    rgba(7, 6, 14, 0.55) 0%,
    rgba(7, 6, 14, 0.3) 12%,
    rgba(7, 6, 14, 0.12) 28%,
    rgba(7, 6, 14, 0.03) 42%,
    rgba(7, 6, 14, 0) 58%
  );
}

/* Sized/positioned to sit right on the title + subtitle block specifically
   (center ~18rem down, vertical radius ~15rem covers from the ornament
   through the subtitle's bottom edge) rather than a generic top dome. */
.hero__content::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 32rem;
  z-index: 0;
  pointer-events: none;
  opacity: var(--hero-wash-opacity, 1);
  background: radial-gradient(
    ellipse 40rem 15rem at 50% 18rem,
    rgba(7, 6, 14, 0.6) 0%,
    rgba(7, 6, 14, 0.4) 35%,
    rgba(7, 6, 14, 0.18) 65%,
    rgba(7, 6, 14, 0) 100%
  );
}

.hero__content .btn-frame {
  --btn-frame-h: auto;
}

.hero__top {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 60.5rem;
  padding: calc(var(--header-height) + 1rem) 1.5rem 0;
}

.hero__bottom {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  width: 100%;
}

.hero__cta {
  padding: 0 1.5rem 2rem;
}

/* Crown + flanking flourish above the title (assets/icons/lines.svg,
   recolored gold in the file itself — same convention as
   assets/img/button-left/right.svg, which also hardcode #c69d4f rather
   than relying on CSS to recolor). Its own viewBox aspect ratio
   (1907.7 x 293.7) is preserved via height: auto. */
.hero__ornament {
  display: block;
  width: min(28rem, 88%);
  height: auto;
  margin: 0 auto 1rem;
}

.hero__title {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.05;
  text-transform: uppercase;
  margin: 0 0 1rem;
}

.hero__title-line {
  display: block;
  font-size: 1.875rem;
  color: var(--color-white);
  letter-spacing: 0.12em;
}

.hero__title-accent {
  display: block;
  margin-top: 0.5rem;
  font-size: 3.375rem;
  color: #EFB956;
  letter-spacing: 0.05em;
}

.hero__title-rule {
  position: relative;
  display: block;
  width: min(17.5rem, 72%);
  height: 0.0625rem;
  margin: 0 auto 1.25rem;
  background: var(--color-gold);
}

.hero__title-rule::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0.3125rem;
  height: 0.3125rem;
  border: 1px solid var(--color-gold);
  transform: translate(-50%, -50%) rotate(45deg);
}

.hero__subtitle {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.35;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-white);
  margin: 0 0 2rem;
}

/* Running promo ribbon, full-bleed edge-to-edge under the CTA button at the
   very bottom of hero (last thing in .hero__bottom, which is pinned to
   .hero__content's bottom edge — see position: absolute on .hero__bottom).
   above). Track holds the item list twice back to back; animating it from
   translateX(0) to translateX(-50%) loops seamlessly since both halves are
   identical. */
.hero__promo {
  width: 100%;
  height: 5rem;
  overflow: hidden;
  background: rgba(12, 11, 23, 0.72);
  border-top: 1px solid rgba(198, 157, 79, 0.55);
  border-bottom: 1px solid rgba(198, 157, 79, 0.55);
  transition: background-color 0.35s ease, box-shadow 0.35s ease;
}

.hero__promo:hover {
  background: rgba(198, 157, 79, 0.14);
  box-shadow: inset 0 0 2.5rem rgba(198, 157, 79, 0.35);
}

.hero__promo-track {
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  animation: hero-promo-scroll 30s linear infinite;
  will-change: transform;
}

.hero__promo:hover .hero__promo-track {
  animation-play-state: paused;
}

.hero__promo-item {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  white-space: nowrap;
  padding: 0 2.25rem;
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.hero__promo-item-a {
  color: var(--color-white);
  margin-right: 2.25rem;
}

.hero__promo-item-b {
  color: var(--color-gold);
}

.hero__promo-sep {
  display: block;
  width: 0.5rem;
  height: 0.5rem;
  flex-shrink: 0;
  margin: 0 2.25rem;
  border: 1px solid var(--color-gold);
  transform: rotate(45deg);
}

@keyframes hero-promo-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .hero__promo-track {
    animation: none;
  }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.375rem;
  text-transform: uppercase;
  color: var(--color-white);
  cursor: pointer;
  transition: color var(--transition-default), transform var(--transition-default);
  text-decoration: none;
}

.btn:hover {
  color: #c9c9c9;
  transform: scale(0.96);
}

/* Gold corner border — button-left/right.svg caps, open center gap */
.btn-frame {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  justify-content: center;
  background: var(--btn-frame-fill);
  isolation: isolate;
  --btn-frame-h: 2.75rem;
  min-height: var(--btn-frame-h);
  max-width: 100%;
  overflow: visible;
}

.btn-frame__border {
  position: absolute;
  inset: 0 -0.0625rem 0 0;
  pointer-events: none;
  z-index: 2;
  overflow: visible;
}

.btn-frame__border::before,
.btn-frame__border::after {
  content: '';
  position: absolute;
  top: 0;
  height: 100%;
  width: auto;
  background-repeat: no-repeat;
  background-size: auto 100%;
  pointer-events: none;
}

.btn-frame__border::before {
  left: 0;
  aspect-ratio: 71.4 / 36.1;
  background-image: var(--btn-frame-left);
  background-position: left center;
}

.btn-frame__border::after {
  right: 0;
  aspect-ratio: 71.4 / 36.1;
  background-image: var(--btn-frame-right);
  background-position: right center;
}

.btn-frame .btn,
.btn-frame .contact-form__input,
.btn-frame .contact-form__select,
.btn-frame .contact-form__phone {
  position: relative;
  z-index: 1;
}

.btn-frame .btn {
  padding: 0.875rem 2.5rem;
  background: transparent;
  border: none;
  white-space: nowrap;
  line-height: 1.2;
  box-sizing: border-box;
}

/* Framed CTA — PNG/SVG frame + text overlay */
.btn-framed {
  position: relative;
  display: inline-block;
  max-width: 100%;
  line-height: 0;
  text-decoration: none;
  vertical-align: top;
  border: none;
  padding: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
}

.btn-framed__frame {
  display: block;
  pointer-events: none;
  user-select: none;
  transition: transform var(--transition-default);
}

.btn-framed__text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 10%;
  font-family: var(--font-heading);
  font-size: 1.0625rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.2;
  white-space: nowrap;
}

.btn-framed--gold .btn-framed__text {
  color: var(--color-gold);
  font-size: 1.1875rem;
  letter-spacing: 0.12em;
  padding: 8% 10% 4%;
}

.btn-framed--light .btn-framed__text {
  color: var(--color-white);
  padding: 8% 10% 4%;
}

.btn-framed--hero .btn-framed__frame {
  width: min(26.25rem, calc(100vw - 3rem));
  height: auto;
}

.btn-framed--wide .btn-framed__frame {
  width: min(23.1875rem, calc(100vw - 3rem));
  height: auto;
}

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

.btn-framed--block .btn-framed__frame {
  width: 100%;
  height: auto;
}

.btn-framed:hover .btn-framed__text {
  color: #e8c878;
}

.btn-framed--light:hover .btn-framed__text {
  color: #f0f0f0;
}

.btn-framed:hover .btn-framed__frame {
  transform: scale(0.98);
}

/* === SECTION COMMON === */
.section {
  position: relative;
  overflow: hidden;
}

/* === HORIZONTAL SCROLL: pinned panel-swap transitions ===
   Desktop only (matches the 980px nav breakpoint). GSAP ScrollTrigger pins
   .hscroll-wrap and translates .hscroll-track sideways by exactly one panel
   width as the user scrolls, so the first panel slides out while the next
   slides in from the right instead of stacking below it. Below 980px this
   collapses back to a plain vertical stack (see media query) and a beam
   divider reappears between the two sections. Reused for two independent
   pin pairs: portfolio -> ouija, and programs -> boosters. */
.hscroll-seam {
  display: none;
}

@media (min-width: 981px) {
  .hscroll-wrap {
    position: relative;
    overflow: hidden;
  }

  .hscroll-track {
    position: relative;
    display: flex;
    align-items: stretch;
    width: 200vw; /* two panels @ 100vw — update if a panel is added/removed */
    height: 100vh; /* explicit (not content-derived), so both panels fill the
      pinned viewport with no gap and the seam column below has a definite
      height to size against */
    will-change: transform;
  }

  .hscroll-panel {
    flex: 0 0 100vw;
    width: 100vw;
    min-width: 0;
  }

  /* Each panel's section normally sizes itself off its own content/aspect
     ratio; inside the pinned scroll it needs to match .hscroll-track's 100vh
     exactly or the bottom of the viewport shows empty space instead of its
     background. */
  .hscroll-wrap .ba-section,
  .hscroll-wrap .programs-section,
  .hscroll-wrap .boosters-section {
    height: 100vh;
    min-height: 100vh;
  }

  .hscroll-seam {
    display: block;
    position: absolute;
    top: -50%; /* 2x size, grown symmetrically so it still centers on the seam */
    left: 100vw; /* the panel boundary, in the track's own coordinate space */
    transform: translateX(-50%);
    height: 200%;
    width: auto;
    z-index: 10;
    pointer-events: none;
  }
}

.hscroll-mobile-only {
  display: none;
}

@media (max-width: 980px) {
  .hscroll-mobile-only {
    display: block;
  }
}

/* Режим правок CMS (?cms_edit=1; класс ставится инлайновым скриптом в <head>
   index.html). Там не работает ни одна скролл-механика — ни катсцены, ни
   пин горизонтального свайпа (см. guard'ы в js/main.js), — а значит, никто
   не сдвигает .hscroll-track и вторая панель каждой пары (ouija, boosters)
   навсегда осталась бы за краем .hscroll-wrap с его overflow: hidden.
   Раскладываем пары обратно в обычный вертикальный стек — ровно та же
   форма, что у сайта ниже 980px, где правила блока выше просто не
   применяются. Специфичность (0,2,1) перебивает исходные (0,1,0)
   независимо от порядка в файле. На живом сайте класса нет — эти правила
   не участвуют вообще. */
html.cms-edit-static .hscroll-wrap {
  overflow: visible;
}

html.cms-edit-static .hscroll-track {
  display: block;
  width: auto;
  height: auto;
  transform: none;
  will-change: auto;
}

/* Ширину панель отдаёт потоку, а вот высоту сохраняет: в пине её задавала
   .hscroll-track (height: 100vh + align-items: stretch), и без неё панель
   съезжала бы к высоте своего содержимого (ouija — 814px вместо 900px),
   т.е. редактор показывал бы не то, что видит посетитель. Правило про
   .ba-section/.programs-section/.boosters-section из @media (min-width: 981px)
   продолжает работать здесь как есть — специально его не переопределяем. */
html.cms-edit-static .hscroll-panel {
  width: auto;
  min-height: 100vh;
}

/* Декоративный шов между панелями — в стеке ему нечего маскировать, а
   position: absolute + left: 100vw увели бы его за край страницы. */
html.cms-edit-static .hscroll-seam {
  display: none;
}

/* Разделительные балки остаются скрытыми, как на живом десктопе: панели в
   стеке идут на всю высоту экрана и стыкуются встык, маскировать нечего, а
   появившаяся здесь мобильная балка была бы элементом, которого посетитель
   на этой ширине не видит никогда. */

/* Найдено при QA-прогоне 2026-08-29: .hero__promo-track едет непрерывно
   (animation: hero-promo-scroll 30s linear infinite), и в отличие от
   катсцен/пина её ничего не гасило в режиме правок — только :hover самого
   .hero__promo. Зеркальные поля внутри (home:hero:span-4/5, см.
   docs/markup-guide.md) редактируемы, а плывущий под курсором текст ломает
   клик и каретку. Останавливаем ровно так же, как уже останавливает hover —
   тем же свойством, не наравне с overflow/display правилами hscroll выше. */
html.cms-edit-static .hero__promo-track {
  animation-play-state: paused;
}

/* === BEFORE/AFTER WIDGET === */
.ba-section {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 90vh;
  min-height: 90vh;
  padding: 2rem 1.25rem;
  overflow: hidden;
  box-sizing: border-box;
}

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

.ba-section__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ba-section__gradient {
  position: absolute;
  inset: 0;
  background: linear-gradient(0deg, rgba(7, 6, 14, 0) 0%, rgba(7, 6, 14, 0.2) 55%, rgba(4, 7, 21, 0.5) 100%);
  z-index: 1;
  pointer-events: none;
}

.ba-section__content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding: 0 1.25rem;
  display: flex;
  justify-content: center;
}

.ba-section__title {
  position: relative;
  z-index: 3;
  /* Pre-existing -220px pulled the title above .ba-section's own box —
     harmless before, since nothing landed the viewport exactly at this
     section's top edge, but the hero intro cutscene now does exactly that
     (see main.js), and .ba-section's overflow: hidden clipped the title's
     upper half the instant it did. -20px keeps some of the original
     pulled-up tightness while measuring a safe ~24px clear of the section's
     own top at the 981px+ breakpoint where that centering applies (checked
     against the real post-cutscene layout, custom heading font loaded). */
  margin: -1.25rem 0 1.75rem;
  font-family: var(--font-heading);
  font-size: 3.125rem;
  font-weight: 600;
  line-height: 1.05;
  color: var(--color-white);
  text-align: center;
  text-transform: uppercase;
}

/* Before/After comparison */
.ba-item {
  position: relative;
  width: 28.2875rem;
  height: 37.5938rem;
  flex-shrink: 0;
}

.ba-item__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

.ba-item .ultra-ba {
  position: absolute;
  left: 2.175rem;
  top: 2.7rem;
  width: 24.0125rem;
  height: 32.2688rem;
  z-index: 1;
}

.ultra-ba {
  position: relative;
  overflow: hidden;
  user-select: none;
}

.ultra-ba-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ultra-ba-before {
  clip-path: inset(0 50% 0 0);
}

.ultra-ba-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 0.125rem;
  /* gold seam that fades into the painting's edges instead of a hard white
     rule — matches the gilded frame around this section */
  background-image: linear-gradient(
    to bottom,
    rgba(198, 157, 79, 0) 0%,
    rgba(198, 157, 79, 0.75) 12%,
    #e6c98a 50%,
    rgba(198, 157, 79, 0.75) 88%,
    rgba(198, 157, 79, 0) 100%
  );
  box-shadow: 0 0 0.75rem rgba(198, 157, 79, 0.35);
  transform: translateX(-50%);
  cursor: ew-resize;
  z-index: 4;
}

.ultra-ba-handle {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 2.75rem;
  height: 2.75rem;
  background:
    radial-gradient(circle at 50% 30%, rgba(198, 157, 79, 0.22), rgba(12, 11, 23, 0.82) 70%),
    rgba(12, 11, 23, 0.82);
  border: 1px solid rgba(198, 157, 79, 0.65);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 0 0 0.25rem rgba(12, 11, 23, 0.35),
    0 0 1.25rem rgba(198, 157, 79, 0.28),
    0 8px 25px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(2px);
  transition: transform 0.25s, box-shadow 0.25s, border-color 0.25s;
  /* Зацикленный лёгкий бонс привлекает внимание к слайдеру без наведения —
     по наведению анимация снимается (не просто на паузу — иначе анимация
     всё равно перебивала бы transform ниже) и рука фиксируется в
     увеличенном размере, см. правило :hover. */
  animation: ultra-ba-handle-bounce 1.8s ease-in-out infinite;
}

@keyframes ultra-ba-handle-bounce {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50%      { transform: translate(-50%, -50%) scale(1.08); }
}

.ultra-ba:hover .ultra-ba-handle {
  animation: none;
  transform: translate(-50%, -50%) scale(1.12);
  border-color: rgba(230, 201, 138, 0.9);
  box-shadow:
    0 0 0 0.25rem rgba(12, 11, 23, 0.35),
    0 0 1.75rem rgba(198, 157, 79, 0.5),
    0 8px 25px rgba(0, 0, 0, 0.35);
}

@media (prefers-reduced-motion: reduce) {
  .ultra-ba-handle { animation: none; }
}

/* mask instead of <img> so the arrow can carry the site's gold gradient */
.ba-icon {
  display: block;
  width: 1.0625rem;
  height: 1.0625rem;
  background-image: linear-gradient(180deg, #f0dca8 0%, var(--color-gold) 55%, #a97f36 100%);
  -webkit-mask: url('../assets/icons/double-arrow.svg') no-repeat center / contain;
  mask: url('../assets/icons/double-arrow.svg') no-repeat center / contain;
  transition: transform 0.25s;
}

.ultra-ba:hover .ba-icon {
  transform: scaleX(1.12);
}

/* === STONE DIVIDER === */
.divider-stone {
  position: relative;
  z-index: 5;
  line-height: 0;
  /* percentage margin resolves against the containing block's width, which
     scales 1:1 with this full-width image's rendered height — so this stays
     proportional to the image's own transparent edge padding (irregular
     stone silhouette) at any viewport size, fully hiding it into the
     adjacent sections instead of leaving the page background peeking through */
  margin: -2.2% 0;
  pointer-events: none;
}

.divider-stone img {
  width: 100%;
  display: block;
  height: auto;
}

/* Castle hall → sky transition between contact-help and adventure map. */
.divider-stone--bg-transition {
  position: relative;
  height: 0;
  margin: 0;
  overflow: visible;
  z-index: 10000;
  pointer-events: none;
}

/* Ставится/снимается из js/main.js (CONTACT -> ADVENTURE CUTSCENE) —
   см. комментарий у #bgTransitionDivider в index.html. visibility, а не
   display, чтобы не трогать раскладку (у блока и так height: 0). */
.divider-stone--cutscene-pending {
  visibility: hidden;
}

.divider-stone--bg-transition img {
  position: absolute;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  top: 0;
  transform: translateY(calc(-50% - 9.375rem));
  pointer-events: none;
}

/* Cloud transition: zero layout height so no page background shows through;
   image overlaps adventure (top) and team (bottom) via absolute positioning. */
.divider-stone--clouds {
  position: relative;
  height: 0;
  margin: 0;
  overflow: visible;
  z-index: 10000;
}

.divider-stone--clouds img {
  position: absolute;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  top: 0;
  transform: translateY(calc(-42% - 12.5rem));
  pointer-events: none;
}

.divider-stone--beam {
  position: relative;
  height: 0;
  margin: 0;
  overflow: visible;
  z-index: 6;
  pointer-events: none;
  line-height: 0;
}

.divider-stone--beam img {
  position: absolute;
  left: 0;
  width: 100%;
  height: auto;
  display: block;
  top: 0;
  transform: translateY(-68%);
  pointer-events: none;
}

.divider-stone--beam-after-ouija img {
  transform: translateY(-55%);
}

.divider-stone--order {
  z-index: 6;
  margin: -2.2% 0;
}

/* Mobile: double the visual thickness of the stone/beam block dividers by
   growing the <img>'s own box height (2x each texture's natural aspect
   ratio) and letting object-fit:cover crop it — the img's width stays at
   100%, so nothing bleeds past the viewport. (An earlier version zoomed
   via width:200%+margin-left:-50%, but that overflows horizontally, and
   .hscroll-wrap/.hscroll-track — which the ouija-section beam divider sits
   inside — only get overflow:hidden at the desktop breakpoint, so on
   mobile the bleed became real page-level horizontal scroll.) Excludes
   --bg-transition/--clouds, which use their own hand-tuned pixel offsets
   for the cutscene and would misalign if resized. */
@media (max-width: 980px) {
  .divider-stone:not(.divider-stone--beam):not(.divider-stone--bg-transition):not(.divider-stone--clouds) img {
    height: 16.95vw; /* 2x divider-stone.webp's natural 217/2560 aspect ratio */
    object-fit: cover;
  }
  .divider-stone--beam img {
    height: 6.98vw; /* 2x балка.webp's natural 67/1920 aspect ratio */
    object-fit: cover;
  }

  /* .divider-stone--clouds/--bg-transition img's transforms
     (calc(-42% - 12.5rem), calc(-50% - 9.375rem)) were tuned for the
     desktop image height, where the fixed rem part is a minor nudge. At
     mobile widths the image itself is only ~125px tall, so that same fixed
     150-200px drags it well off the seam — clouds miss the adventure->team
     seam entirely (hard cut into the dark team-section), and bg-transition
     sits inside the castle-hall art instead of bridging into the adventure
     intro card below it. Center both on the seam instead — no fixed
     component needed. */
  .divider-stone--clouds img,
  .divider-stone--bg-transition img {
    transform: translateY(-50%);
  }
}

/* Contact -> adventure video-like transition (desktop only — see
   js/main.js "CONTACT -> ADVENTURE CUTSCENE"). Hidden at rest; shown as a
   fixed, full-viewport overlay only for the scripted frame-sequence flight,
   so it needs no reserved layout space of its own like .hero-pin-wrap does.
   z-index sits above every other in-page layer (adventure's own panel at
   10002 is the highest) but below .header's 100000, so the nav stays
   visible through the flight, matching how #hero's own z-index:50 during
   its cutscene never covers the header either. */
.contact-transition-overlay {
  position: fixed;
  inset: 0;
  z-index: 20000;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.contact-transition-overlay img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Order form + footer share one seamless background image (no per-section
   repeat/seam) with a shared parallax drift — see .footer-bg-wrap below. */
.footer-bg-wrap {
  position: relative;
  overflow: hidden;
}

.footer-bg-wrap__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.footer-bg-wrap__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.footer-bg-wrap__overlay {
  position: absolute;
  inset: 0;
  background: rgba(7, 6, 14, 0.45);
  z-index: 1;
}

.footer-bg-wrap .contact-section--wow,
.footer-bg-wrap .footer {
  position: relative;
  z-index: 2;
}

.ba-section__sliders {
  display: flex;
  gap: 23.3125rem;
  position: relative;
  z-index: 2;
  margin-top: 9.375rem;
}

@media (max-width: 1550px) {
  .ba-section__sliders { gap: 120px; }
}

/* Below this, even a zero gap can't fit two 565.5px-wide frames side by
   side (1131px + padding) — stack them instead of letting them clip. */
@media (max-width: 1300px) {
  .ba-section__sliders { flex-direction: column; gap: 48px; align-items: center; }
}

/* === OUIJA SECTION === */
.ouija-section {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.25rem;
  padding: 3.25rem 1.25rem 3rem;
  overflow: hidden;
}

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

.ouija-section__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ouija-section__gradient {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  pointer-events: none;
}

.ouija-section__gradient--top {
  top: 0;
  height: 17.5rem;
  opacity: 0.85;
  background: linear-gradient(0turn, rgba(7, 6, 14, 0) 0%, rgba(7, 6, 14, 0.75) 37%, rgba(4, 7, 21, 1) 100%);
}

.ouija-section__gradient--bottom {
  bottom: 0;
  height: 17.5rem;
  opacity: 0.85;
  background: linear-gradient(0turn, rgba(7, 6, 14, 0) 0%, rgba(7, 6, 14, 0.75) 49%, rgba(4, 7, 21, 1) 100%);
  transform: rotate(180deg);
}

.ouija-section__leaves {
  position: absolute;
  top: calc(-6% + 9.375rem);
  right: calc(-4% - 3.125rem);
  z-index: 4;
  width: min(38.75rem, 34%);
  height: auto;
  pointer-events: none;
  user-select: none;
  will-change: transform;
}

.ouija-section__header {
  position: relative;
  z-index: 2;
  text-align: center;
  width: 100%;
  max-width: 56.5625rem;
  padding: 0 1.25rem;
}

.ouija-section__heading {
  font-family: var(--font-heading);
  font-size: 3rem;
  font-weight: 700;
  line-height: 1.05;
  color: #ffedbe;
  text-transform: uppercase;
  margin: 0 0 1rem;
}

.ouija-section__label {
  font-family: var(--font-heading);
  font-size: 1.75rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--color-white);
  opacity: 0.9;
  margin: 0 0 1.125rem;
}

.ouija-section__line {
  width: min(43.125rem, 100%);
  height: 0.0625rem;
  margin: 0 auto 1.25rem;
  background: #ffedbe;
  opacity: 0.85;
  border-radius: 1rem;
}

.ouija-section__desc {
  width: 100%;
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--color-white);
}

.ouija-section__board {
  position: relative;
  width: min(41.0625rem, calc(100% - 2.5rem));
  margin: 0 auto;
  transform: translateY(calc((1 - var(--reveal, 0)) * var(--reveal-distance, 2.5rem)));
  z-index: 2;
}

.ouija-section__desk {
  width: 100%;
  height: auto;
  display: block;
}

.ouija-section__arrow-btn {
  position: absolute;
  top: 15.125rem;
  right: -9rem;
  width: 12.1875rem;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  transform: translate(0, 0);
  transition: transform 0.9s ease-in-out;
}

.ouija-section__arrow-btn.is-playing {
  cursor: default;
  pointer-events: none;
}

.ouija-section__arrow {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .ouija-section__arrow-btn { transition: none; }
}

.ouija-section__card {
  position: relative;
  z-index: 2;
  width: min(40.25rem, calc(100% - 2.5rem));
  min-height: 20rem;
  padding: 3rem 2.5rem 2.75rem;
  background: rgba(12, 11, 23, 0.7);
  border: 1px solid rgba(198, 157, 79, 0.3);
  border-radius: 1.25rem;
  backdrop-filter: blur(0.625rem);
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
}

.ouija-section__card-title {
  font-family: var(--font-heading);
  font-size: 1.375rem;
  font-weight: 400;
  line-height: 1.2;
  color: #eeeeee;
  margin: 0;
}

.ouija-section__card-sub {
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 300;
  line-height: 1.35;
  color: #f0f0f0;
  opacity: 0.9;
  margin: 0;
  max-width: 26.375rem;
}

.ouija-section__form {
  width: 100%;
  max-width: 28.125rem;
  height: 3.875rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0;
  margin-top: 0.5rem;
}

.ouija-section__field-frame {
  flex: 1;
  min-width: 0;
  height: 3.875rem;
  --btn-frame-h: 3.875rem;
}

.ouija-section__input {
  width: 100%;
  height: 100%;
  background: transparent;
  border: none;
  border-radius: 0;
  outline: none;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--color-white);
  text-align: center;
  padding: 0 1.375rem;
  box-sizing: border-box;
  position: relative;
  z-index: 1;
}

/* Native outline removed above (matches every other input on this page) —
   restored here via the same inset-border treatment
   .contact-form__select-trigger already uses, so keyboard focus stays
   visible (WCAG 2.4.7). Invisible until actually focused: no change to the
   field's resting appearance. */
.ouija-section__input:focus-visible {
  box-shadow: inset 0 0 0 0.0625rem var(--color-gold);
}

.ouija-section__input::placeholder {
  color: rgba(255, 255, 255, 0.45);
}

.ouija-section__input.hint {
  color: #e67e22;
}

.ouija-section__input.shake {
  animation: ouija-shake 0.4s;
}

@keyframes ouija-shake {
  0% { transform: translateX(0); }
  20% { transform: translateX(-0.3125rem); }
  40% { transform: translateX(0.3125rem); }
  60% { transform: translateX(-0.3125rem); }
  80% { transform: translateX(0.3125rem); }
  100% { transform: translateX(0); }
}

.ouija-section__submit {
  flex-shrink: 0;
  padding: 0;
  border: none;
  background: transparent;
  cursor: not-allowed;
  opacity: 0.5;
  transition: opacity 0.2s ease;
}

.ouija-section__submit.is-active {
  cursor: pointer;
  opacity: 1;
}

.ouija-section__submit img {
  height: min(8vw, 8vh, 3.75rem);
  width: auto;
  display: block;
  user-select: none;
}

/* 981–1699px: within the pinned horizontal-scroll range (see @media
   (min-width: 981px) above — .hscroll-track forces height:100vh here),
   but not yet wide enough to comfortably fit the full-size heading/board/
   card stack inside typical laptop viewport heights (~800–950px) at this
   width. justify-content:center then centers an over-tall stack that
   overflows both the top and the bottom of the fixed 100vh box, and
   .ouija-section's own overflow:hidden clips both ends evenly (owner
   report 15.09.2026 — heading crammed against the top, card crammed
   against the bottom). Below 980px this doesn't apply at all: the pin
   deactivates (mobile fallback stack, see @media max-width:980px further
   down), height goes back to auto and nothing is forced into one screen.
   Fix: shrink the vertical rhythm (gaps, board/card size, heading/label)
   so the stack actually fits, and bias the section's own padding so the
   fitted stack sits lower rather than dead-centre (more top padding than
   bottom) — pulls the card closer to the board at the same time, since
   less total height means less to clip either way. */
@media (min-width: 981px) and (max-width: 1699px) {
  .ouija-section { padding: 3.75rem 1.25rem 1.75rem; gap: 1.5rem; }
  .ouija-section__heading { font-size: 2.5rem; }
  .ouija-section__label { font-size: 1.5rem; }
  .ouija-section__desc { font-size: 1.125rem; }
  .ouija-section__board { width: min(34rem, calc(100% - 2.5rem)); }
  .ouija-section__card {
    width: min(33rem, calc(100% - 2.5rem));
    min-height: 16rem;
    padding: 2rem 2rem 1.5rem;
    gap: 0.875rem;
  }
}

/* === CHILDREN SECTION === */
.children-section {
  position: relative;
  min-height: 56.25rem;
  height: 100vh;
  overflow: hidden;
}

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

.children-section__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.children-section__overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: min(71.1875rem, 60%);
  height: 100%;
  background: linear-gradient(0.75turn, rgba(7, 6, 14, 0) 0%, rgba(7, 6, 14, 0.75) 27%, rgba(4, 7, 21, 1) 100%);
  opacity: 0.85;
  z-index: 1;
  pointer-events: none;
}

.children-section__text {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.children-section__title {
  position: absolute;
  top: calc(50vh - 17.3438rem);
  left: 7.8125rem;
  margin: 0;
  font-family: var(--font-heading);
  font-size: 2.625rem;
  font-weight: 700;
  line-height: 1.25;
  text-transform: uppercase;
  color: #ffedbe;
  white-space: nowrap;
}

.children-section__subtitle {
  position: absolute;
  top: calc(50vh - 13.7188rem);
  left: 14.9375rem;
  margin: 0;
  font-family: var(--font-heading);
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.25;
  text-transform: uppercase;
  color: var(--color-white);
  white-space: nowrap;
}

.children-section__desc-block {
  position: absolute;
  top: calc(50vh - 10.9063rem);
  left: 12.8125rem;
  width: 31.0625rem;
  text-align: center;
}

.children-section__line {
  width: 31.25rem;
  max-width: 100%;
  height: 0.0625rem;
  margin: 0 auto 1.125rem;
  border-radius: 1rem;
  background: #ffedbe;
  opacity: 0.85;
}

.children-section__desc-lead {
  margin: 0 0 0.5rem;
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.2;
  color: #e4e4e4;
}

.children-section__desc {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.2;
  color: #c7c7c7;
}

.children-section__portrait {
  position: absolute;
  z-index: 2;
  top: calc(50vh - 26.125rem);
  left: calc(50% + 5.375rem);
  width: 25.5625rem;
  height: 36.875rem;
  overflow: hidden;
  cursor: pointer;
}

.children-section__portrait-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Canvas melt-перехода постер → видео: лежит над видео, под кнопкой play.
   Видим только на время перехода (~0.9 с), дальше JS снимает .is-active. */
.children-section__portrait-melt {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  display: none;
  pointer-events: none;
}

.children-section__portrait-melt.is-active {
  display: block;
}

/* Кнопка play: остаётся поверх лупа всегда, открывает попап со звуком. */
.children-section__portrait-toggle {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  padding: 0;
  border-radius: 50%;
  border: 1.5px solid var(--color-gold);
  background: radial-gradient(circle at 50% 50%, rgba(12, 11, 23, 0.72), rgba(5, 5, 9, 0.6));
  box-shadow: 0 0 0 1px rgba(198, 157, 79, 0.18), 0 10px 30px rgba(0, 0, 0, 0.5),
    inset 0 0 20px rgba(198, 157, 79, 0.18);
  transform: translate(-50%, -50%);
  cursor: pointer;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

.children-section__portrait-toggle-icon {
  width: 0;
  height: 0;
  margin-left: 0.3125rem;
  border-style: solid;
  border-width: 0.6875rem 0 0.6875rem 1.1875rem;
  border-color: transparent transparent transparent var(--color-gold);
  transition: border-left-color 0.25s ease;
}

.children-section__portrait-toggle-pulse {
  position: absolute;
  inset: -0.3125rem;
  border-radius: 50%;
  border: 1px solid rgba(198, 157, 79, 0.5);
  animation: promoPlayPulse 2.6s ease-out infinite;
  pointer-events: none;
}

@keyframes promoPlayPulse {
  0% { transform: scale(1); opacity: 0.65; }
  70% { transform: scale(1.3); opacity: 0; }
  100% { transform: scale(1.3); opacity: 0; }
}

.children-section__portrait-toggle:hover,
.children-section__portrait-toggle:focus-visible {
  transform: translate(-50%, -50%) scale(1.08);
  background: radial-gradient(circle at 50% 50%, rgba(28, 22, 12, 0.8), rgba(9, 8, 14, 0.7));
  box-shadow: 0 0 0 1px rgba(198, 157, 79, 0.42), 0 14px 40px rgba(0, 0, 0, 0.58),
    inset 0 0 28px rgba(198, 157, 79, 0.3);
  outline: none;
}

.children-section__portrait-toggle:hover .children-section__portrait-toggle-icon,
.children-section__portrait-toggle:focus-visible .children-section__portrait-toggle-icon {
  border-left-color: #f0d79a;
}

@media (prefers-reduced-motion: reduce) {
  .children-section__portrait-toggle-pulse { animation: none; }
}

/* --- Попап промо-ролика --- */
.promo-modal {
  position: fixed;
  inset: 0;
  /* Выше .header (100000) и мобильного меню — иначе шапка перекрывает крестик,
     который теперь стоит в правом верхнем углу рамки. */
  z-index: 100010;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}

.promo-modal.is-open {
  opacity: 1;
  visibility: visible;
}

.promo-modal__backdrop {
  position: absolute;
  inset: 0;
  border: none;
  padding: 0;
  background: rgba(5, 5, 9, 0.94);
  cursor: pointer;
}

.promo-modal__dialog {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(0.75rem) scale(0.98);
  transition: transform 0.25s ease;
}

.promo-modal.is-open .promo-modal__dialog {
  transform: translateY(0) scale(1);
}

/* Рамка держит пропорции самого ролика: --promo-ar-num выставляет JS по
   videoWidth/videoHeight, 0.5625 (9/16) — дефолт до loadedmetadata. Высота
   упирается либо в высоту экрана, либо в ширину — что меньше — и в --frame-h
   считается один раз; ширина выводится из того же --frame-h, а не отдельно
   через CSS `aspect-ratio` + `max-width`: на iOS Safari та связка на
   вертикальном видео у самого края экрана давала рамку шире вьюпорта —
   крестик в её углу уезжал за правый край и обрезался (не баг крестика,
   баг обсчёта рамки). max-width/max-height ниже — просто подстраховка,
   при таком выводе ширины они уже никогда не должны сработать. */
.promo-modal__frame {
  position: relative;
  --frame-h: min(calc(100vh - 3rem), calc((100vw - 3rem) / var(--promo-ar-num, 0.5625)));
  height: var(--frame-h);
  width: calc(var(--frame-h) * var(--promo-ar-num, 0.5625));
  max-height: calc(100vh - 3rem);
  max-width: calc(100vw - 3rem);
  border-radius: var(--border-radius);
  overflow: hidden;
  border: 1px solid rgba(198, 157, 79, 0.35);
  background: #000;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(198, 157, 79, 0.12);
}

/* В попап переезжает тот же элемент, что стоит в портрете, поэтому правило
   навешано на его класс: внутри рамки он растягивается на неё целиком и
   показывается целиком (contain), а не обрезается как в портрете. */
.promo-modal__frame .children-section__portrait-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

/* Крестик внутри рамки: при вертикальном ролике на высоту экрана снаружи
   для него места не остаётся. */
.promo-modal__close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(198, 157, 79, 0.45);
  background: rgba(5, 5, 9, 0.6);
  color: rgba(255, 255, 255, 0.9);
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

.promo-modal__close:hover,
.promo-modal__close:focus-visible {
  color: var(--color-gold);
  border-color: var(--color-gold);
  background: rgba(12, 11, 23, 0.8);
  outline: none;
}

.promo-modal__close svg {
  display: block;
  width: 1.375rem;
  height: 1.375rem;
}

/* --- Попап "Заявка отправлена" (js/main.js, единый узел на всех формах
   .contact-form--help — главная и модалки заказа программ). Та же
   структура/повадки, что у .promo-modal: fixed-оверлей, .is-open
   переключает opacity+visibility, диалог тем же scale-in. --- */
.lead-success-modal {
  position: fixed;
  inset: 0;
  z-index: 100020;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s ease;
}

.lead-success-modal.is-open {
  opacity: 1;
  visibility: visible;
}

.lead-success-modal__backdrop {
  position: absolute;
  inset: 0;
  border: none;
  padding: 0;
  background: rgba(5, 5, 9, 0.92);
  cursor: pointer;
}

.lead-success-modal__dialog {
  position: relative;
  z-index: 1;
  width: min(26rem, 100%);
  text-align: center;
  padding: 2.75rem 2.5rem 2.5rem;
  background: rgba(12, 11, 23, 0.92);
  border: 1px solid rgba(198, 157, 79, 0.35);
  border-radius: calc(var(--border-radius) + 0.25rem);
  backdrop-filter: blur(0.625rem);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(198, 157, 79, 0.12);
  transform: translateY(0.75rem) scale(0.98);
  transition: transform 0.25s ease;
}

.lead-success-modal.is-open .lead-success-modal__dialog {
  transform: translateY(0) scale(1);
}

.lead-success-modal__close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem;
  border: none;
  background: transparent;
  color: rgba(255, 255, 255, 0.7);
  cursor: pointer;
  transition: color 0.2s ease;
}

.lead-success-modal__close:hover,
.lead-success-modal__close:focus-visible {
  color: var(--color-gold);
  outline: none;
}

.lead-success-modal__close svg {
  display: block;
  width: 1.5rem;
  height: 1.5rem;
}

.lead-success-modal__icon {
  display: inline-flex;
  width: 3.5rem;
  height: 3.5rem;
  margin: 0 0 1.25rem;
  color: var(--color-gold);
}

.lead-success-modal__icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.lead-success-modal__title {
  margin: 0 0 0.5rem;
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.lead-success-modal__text {
  margin: 0;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--color-muted);
}

@media (max-width: 768px) {
  .children-section__portrait-toggle {
    width: 3.5rem;
    height: 3.5rem;
  }

  .children-section__portrait-toggle-icon {
    border-width: 0.5625rem 0 0.5625rem 0.9375rem;
  }

  .promo-modal { padding: 1rem; }

  /* Тот же --frame-h, что и в базовом правиле, просто с полями 2rem вместо
     3rem — width считается из --frame-h ниже по каскаду, так что если
     здесь переопределить только height (как было раньше), width останется
     посчитан по «взрослому» --frame-h с 3rem и разъедется с реальной
     высотой рамки. */
  .promo-modal__frame {
    --frame-h: min(calc(100vh - 2rem), calc((100vw - 2rem) / var(--promo-ar-num, 0.5625)));
    max-height: calc(100vh - 2rem);
    max-width: calc(100vw - 2rem);
  }
}

.children-section__frame {
  position: absolute;
  z-index: 3;
  top: calc(50vh - 28rem);
  left: calc(50% + 1.6875rem);
  width: 31.1875rem;
  height: auto;
  pointer-events: none;
}

.children-section__kid {
  position: absolute;
  z-index: 4;
  height: auto;
  pointer-events: none;
  --reveal-distance: 8.75rem;
}

.children-section__kid--1 {
  top: calc(100vh - 35.125rem);
  left: calc(50% - 7.4688rem);
  width: 12.9375rem;
}

.children-section__kid--2 {
  top: calc(100vh - 33.9375rem);
  left: calc(50% + 2rem);
  width: 17.875rem;
}

.children-section__kid--3 {
  top: calc(100vh - 32.5625rem);
  left: calc(50% + 18.5rem);
  width: 12.625rem;
}

.children-section__kid--4 {
  top: calc(100vh - 34.25rem);
  left: calc(50% + 31.25rem);
  width: 11.25rem;
}

/* Fixed behind the page; shows through boosters-section and contact-section--help
   (both stay free of their own opaque background so this is visible), giving the
   two blocks one continuous, non-scrolling image with no seam at their boundary.
   Sections outside that range paint their own opaque background/overlay on top,
   hiding it. */
.page-bg-fixed {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.page-bg-fixed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.programs-section {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  min-height: max(100vh, calc(100vw * 945 / 1680));
  overflow: hidden;
}

.programs-section__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url('../assets/img/photo.webp');
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}

.programs-section__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(7, 6, 14, 0.85) 0%, rgba(7, 6, 14, 0.45) 30%, rgba(7, 6, 14, 0) 60%);
  pointer-events: none;
}

.programs-section__inner {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 93.75rem;
  margin: 0 auto;
  padding: 5.5rem 4.5rem 4.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  box-sizing: border-box;
}

.programs-section__header {
  position: relative;
  z-index: 2;
  pointer-events: none;
  align-self: center;
  width: 100%;
  max-width: 100%;
  text-align: center;
}

.programs-section__title {
  position: relative;
  margin: 0 0 0.375rem;
  font-family: var(--font-heading);
  font-size: 3.375rem;
  font-weight: 700;
  line-height: 1.05;
  text-align: center;
  text-transform: uppercase;
  color: var(--color-white);
}

.programs-section__subtitle {
  position: relative;
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.25rem;
  font-weight: 300;
  line-height: 1.25;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.88);
}

.programs-section__tabs {
  position: relative;
  z-index: 3;
  --prog-tab-w: 10.875rem;
  --prog-tab-line-top: calc(var(--prog-tab-w) * 1041 / 993 + 6.75rem);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.1875rem 0.3125rem;
  max-width: 59rem;
  margin: 0.75rem auto 0;
  width: 100%;
  padding-top: 0.25rem;
}

.programs-section__tabs::before {
  content: '';
  position: absolute;
  top: var(--prog-tab-line-top);
  left: 8%;
  right: 8%;
  height: 0.125rem;
  background: linear-gradient(
    90deg,
    rgba(198, 157, 79, 0) 0%,
    rgba(198, 157, 79, 0.85) 12%,
    rgba(255, 237, 190, 0.95) 50%,
    rgba(198, 157, 79, 0.85) 88%,
    rgba(198, 157, 79, 0) 100%
  );
  pointer-events: none;
  z-index: 1;
}

.prog-tab {
  position: relative;
  flex: 0 0 auto;
  width: var(--prog-tab-w);
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  transition: transform 0.3s cubic-bezier(0.42, 0, 0.49, 1.2), opacity var(--transition-default);
  opacity: 0.85;
}

.prog-tab:hover,
.prog-tab.active {
  opacity: 1;
  transform: translateY(-0.75rem);
}

/* Свечение медальки: drop-shadow одной картинки почти не видно — медаль
   сама по себе тёмная бронза, alpha-контур узкий. Добавляем ореол отдельным
   слоем позади иконки (radial-gradient), это даёт заметное свечение
   независимо от формы alpha-канала картинки. */
.prog-tab::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--prog-tab-w);
  height: var(--prog-tab-w);
  transform: translateX(-50%) scale(0.82);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 237, 190, 0.75) 0%, rgba(198, 157, 79, 0.5) 45%, rgba(198, 157, 79, 0) 72%);
  filter: blur(0.375rem);
  opacity: 0;
  z-index: 1;
  pointer-events: none;
  transition: opacity var(--transition-default);
}

.prog-tab:hover::before,
.prog-tab.active::before {
  opacity: 1;
}

.prog-tab:hover .prog-tab__icon,
.prog-tab.active .prog-tab__icon {
  filter: drop-shadow(0 0 0.75rem rgba(255, 237, 190, 0.9));
}

.prog-tab__icon,
.prog-tab__label {
  width: var(--prog-tab-w);
  height: auto;
  display: block;
  pointer-events: none;
}

.prog-tab__icon {
  position: relative;
  z-index: 2;
  transition: filter var(--transition-default);
}

.prog-tab__label {
  position: relative;
  z-index: 0;
  margin-top: 0.125rem;
}

/* === PROGRAM CAROUSEL (inside programs-section) === */
.programs-section__carousel-wrap {
  position: relative;
  z-index: 2;
  margin-top: 1rem;
  padding: 2.25rem 0 1.5rem;
  /* Full-bleed breakout: .programs-section__inner (its parent) caps out at
     93.75rem and centers, same as every other section's content column, but
     the slider itself should run edge-to-edge of the actual viewport at
     every width instead of staying inside that column — cards fill however
     much screen the visitor actually has. calc(50% - 50vw) is viewport-
     relative regardless of how deep this sits in the layout (unlike a
     negative margin sized to a specific ancestor's padding, which only
     cancels that one padding value), so it reaches the true edge whether
     .programs-section__inner is narrower than the screen (mobile/tablet,
     where it's 100% width already) or capped well short of it (wide desktop
     monitors, where this is the part that visibly differs from its parent).
     html's overflow-x:hidden backstop (see there) absorbs the usual 100vw-
     vs-scrollbar sub-pixel slop this trick can introduce. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

.carousel-content {
  display: none;
  position: relative;
  z-index: 2;
}

.carousel-content.active {
  display: block;
}

.carousel-content__header {
  text-align: center;
  margin-bottom: 2rem;
  padding: 0 1.5rem;
}

.carousel-content__title {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  margin: 0 0 0.5rem;
}

.carousel-content__desc {
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 300;
  color: rgba(255, 255, 255, 0.82);
  margin: 0 auto;
  max-width: 40rem;
  line-height: 1.35;
}

/* === PROGRAM CAROUSEL — unified slider (desktop + mobile) ===
   One JS-driven engine (js/main.js, "PROGRAM CAROUSEL") positions
   .prog-carousel__track via an integer card `index` + translateX() at every
   viewport size — there's no separate "desktop grid" mode any more. The clip
   window is .prog-carousel (overflow:hidden), never the track itself: the
   track is the element that moves, and clipping on a moving element clips
   relative to its own shifted box, so the visible window would slide along
   with the cards instead of staying put. transform: translateZ(0) +
   will-change promote that clip to its own compositor layer, which matters
   because the track gets a translateX() every drag frame while each
   .prog-card independently keeps rewriting its own --reveal transform on
   scroll (see "SCROLL REVEAL" below) — two transform sources committing on
   parent + child with no stable layer on the clipping ancestor is exactly
   the scenario where the overflow:hidden boundary can lag a frame, reading
   as a sliver of the next/prev card visible past the edge.
   overflow:hidden clips at the padding edge, not the content edge, so
   .prog-carousel's horizontal padding below is clip *slack* for the card's
   box-shadow (0 20px 60px) — without it the shadow (and, at odd widths, a
   sliver of the card) gets clipped flush with the container's outer edge. */
.prog-carousel {
  position: relative;
  /* No max-width cap — .programs-section__carousel-wrap below already
     breaks out to the full viewport width, and this fills 100% of that, so
     however many whole cards fit the visitor's actual screen show at once
     (JS measures real card width, not a hardcoded per-tier count). */
  margin: 0 auto;
  overflow: hidden;
  padding: 0 1.25rem;
  transform: translateZ(0);
  will-change: transform;
}

.prog-carousel__track {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 1.875rem;
  padding: 0.75rem 0 1.75rem;
  touch-action: pan-y; /* leaves a not-perfectly-horizontal swipe free to still scroll the page */
  cursor: grab;
  user-select: none;
  will-change: transform;
  /* Only animates a *committed* move (nav click, or a swipe past the commit
     threshold — js/main.js goTo()). A live drag writes transform directly
     every frame with this switched to `none`, so the card tracks the
     pointer 1:1 with zero lag; the transition only takes over for the final
     snap on release, which is what reads as a slide instead of a jump-cut. */
  transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

.prog-carousel__track.is-dragging { cursor: grabbing; transition: none; }

/* When a tab's cards all fit in one view (e.g. only 2 shows), JS toggles
   this instead of flex-start so the short row centers like a static grid
   rather than hugging the left edge with dead space on the right. */
.prog-carousel__track--fits { justify-content: center; }

.prog-card {
  flex: 0 0 17.5rem;
  width: 17.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  transition: transform 0.3s ease;
  transform: translateY(calc((1 - var(--reveal, 0)) * var(--reveal-distance, 2.5rem))) scale(var(--hover-scale, 1));
}

.prog-card:hover {
  --hover-scale: 1.03;
}

.prog-card > img {
  width: 17.5rem;
  height: 23.125rem;
  object-fit: cover;
  border-radius: var(--border-radius);
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}

.prog-card__title {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  margin: 0;
  text-align: center;
}

.prog-card__btn {
  width: min(100%, 13.75rem);
  min-width: 11.25rem;
}

.prog-card__btn .btn-framed__frame {
  width: 100%;
  height: auto;
}

.prog-card__btn .btn-framed__text {
  font-size: 0.9375rem;
  letter-spacing: 0.1em;
  padding: 4% 12% 8%;
}

.carousel-nav {
  display: flex;
  justify-content: center;
  gap: 1.25rem;
  margin-top: 1.25rem;
  position: relative;
  z-index: 2;
}

.carousel-nav__btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  width: 4.375rem;
  height: 4.375rem;
  transition: transform 0.2s ease;
}

.carousel-nav__btn:hover {
  transform: scale(1.1);
}

.carousel-nav__btn img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.carousel-nav__btn.is-disabled {
  opacity: 0.35;
  pointer-events: none;
}

/* === BOOSTERS/УСИЛИТЕЛИ ===
   Полноэкранная секция: .boosters-section__content — обязательный элемент
   для скролл-катсцены hero→adventure в js/main.js (см. комментарий в
   index.html) — теперь сам является полноэкранным слоем (inset:0), внутри
   .theatre-gallery заполняет его целиком, а .boosters-section__intro
   плавает поверх плашкой у верхнего края, как заголовок в оригинальном
   демо (tympanus.net/Tutorials/InfiniteCircularGallery). */
.boosters-section {
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
}

/* min-height больше 100vh — сознательный запас: карточки на дуге местами
   проседают ниже первого экрана, а overflow тут ДОЛЖЕН быть настоящим
   hidden (не visible/mixed clip+visible) — сторонний SmoothScroll.min.js
   (см. index.html, самый низ) сам решает, какой элемент скроллить, по
   признаку scrollHeight > clientHeight; overflow-y:visible технически
   даёт этот признак, даже когда сам браузер ничего не скроллит визуально
   (contentbox реально больше clientbox) — и библиотека начинает пытаться
   скроллить секцию вместо страницы, из-за чего колесо мыши переставало
   листать сайт вообще. Обычный hidden такого разбора не проходит (для
   него scrollHeight/clientHeight не значат «скроллимо»), поэтому запас
   высоты — единственный безопасный способ не резать карточки по живому. */
.boosters-section--fullscreen {
  /* vh на мобильных браузерах часто считается по МАКСИМАЛЬНОЙ высоте
     экрана (с учётом скрытой адресной строки) — секция физически выше
     видимой области, и до соседней снизу оставался пустой хвост фона.
     svh — «малая» высота вьюпорта, специально для этого случая; браузеры
     без её поддержки просто проигнорируют вторую строку и останутся на vh. */
  min-height: 112vh;
  min-height: 112svh;
  overflow: hidden;
}

.boosters-section__content {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.boosters-section__intro {
  position: absolute;
  top: 2.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  /* Тот же приём, что у .adventure-intro (css/adventure.css): тёмная
     подложка с золотой рамкой и блюром, чтобы текст читался поверх
     светлого фонового неба/арки. Держим здесь свою копию значений, а не
     общий класс: секции живут в разных файлах и у .adventure-intro своё
     позиционирование, которое сюда не нужно. */
  background: rgba(6, 12, 28, 0.88);
  border: 1px solid rgba(232, 184, 48, 0.4);
  border-radius: 22px;
  backdrop-filter: blur(12px);
  padding: 24px 40px;
  text-align: center;
  max-width: 40rem;
  box-sizing: border-box;
}

/* Внутри плашки отрицательный отступ подзаголовка не нужен — расстояние
   между строками задаёт сам блок. */
.boosters-section__intro .boosters-section__subtitle {
  margin: 8px 0 0;
  max-width: none;
}

.boosters-section__title {
  font-family: var(--font-heading);
  font-size: 2.625rem;
  font-weight: 700;
  line-height: 1;
  color: var(--color-white);
  text-align: center;
  text-transform: uppercase;
  margin: 0;
}

.boosters-section__subtitle {
  font-family: var(--font-body);
  font-size: 1.125rem;
  font-weight: 300;
  line-height: 1.35;
  color: rgba(255, 255, 255, 0.82);
  text-align: center;
  max-width: 40rem;
  margin: -1.25rem 0 0;
}

/* === THEATRE GALLERY (бесконечная дугообразная галерея героев, на весь экран) ===
   Заполняет .boosters-section__content целиком — обёртка сама на 100%,
   стрелки (сейчас скрыты) позиционируются уже от .circular-gallery. */
.theatre-gallery {
  position: absolute;
  inset: 0;
}

/* Рамка фокуса — только для клавиатурной навигации: указатель фокус сюда
   больше не ставит (pointerdown в js/circular-gallery.js гасит дефолт),
   иначе золотой контур вспыхивал вокруг всего экрана на каждом драге. */
.theatre-gallery:focus-visible {
  outline: 2px solid var(--color-gold);
  outline-offset: -6px;
}

/* === CIRCULAR GALLERY ===
   Порт infinite-circular-webgl-gallery на CSS-transform (без WebGL и без
   собственного фона — .circular-gallery__track прозрачен, сквозь зазоры
   между карточками виден фон секции). Каждый .circular-gallery__item —
   пара «картинка + подпись» (как Media+Number+Title в оригинальном app/) —
   в js/circular-gallery.js вращается и смещается ЦЕЛИКОМ, одним transform:
   в реальном демо подпись наклоняется вместе с фото, а не остаётся ровной.
   На .circular-gallery__img висит SVG-фильтр #cgRipple (feDisplacementMap,
   заведён в index.html) — не честная вершинная рябь шейдера оригинала
   (её на плоском <img> не сделать), но даёт тот же на вид «живой,
   подрагивающий» эффект: слабый в покое, сильнее во время драга — амплитуду
   крутит JS через #cgDisplace. До инициализации JS карточки лежат обычным
   потоком (flex-wrap) — это и есть no-js fallback. */
.circular-gallery {
  position: relative;
  width: 100%;
  height: 100%;
  /* Настоящий hidden на обеих осях — см. комментарий у
     .boosters-section--fullscreen про то, почему тут нельзя visible. */
  overflow: hidden;
  touch-action: pan-y;
  user-select: none;
  cursor: grab;
}

.circular-gallery:active { cursor: grabbing; }

.circular-gallery__track {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: flex-start;
  gap: 0.75rem;
  width: 100%;
  height: 100%;
  overflow: auto;
  padding: 4rem 1.25rem;
  box-sizing: border-box;
}

.circular-gallery.is-ready .circular-gallery__track {
  display: block;
  overflow: visible;
  padding: 0;
}

.circular-gallery__item {
  display: block;
  width: 13rem;
  margin: 0;
}

.circular-gallery__img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 4px;
  pointer-events: none;
  -webkit-user-drag: none;
  box-shadow: 0 1rem 2.25rem rgba(0, 0, 0, 0.55);
  filter: url(#cgRipple);
}

/* На мобиле фильтр снят целиком (запрос 30.08.2026 — жалоба на лаги
   галереи, две предыдущие правки JS её не сняли: значит дело не в
   бесполезной работе в простое, а в том, что feDisplacementMap реально
   пересчитывается на всех 24 карточках каждый кадр во время самого
   свайпа/драга, и мобильные GPU/софтверный рендер фильтров это не тянут).
   980px — тот же порог, что MOBILE_BREAKPOINT в js/circular-gallery.js:
   ровно там, где карточка занимает почти весь экран и лента становится
   тем самым «мобильным» режимом свайпа. На десктопе рябь остаётся. */
@media (max-width: 980px) {
  .circular-gallery__img {
    filter: none;
  }
}

/* Позиция/поворот — инлайн-стиль из js/circular-gallery.js на каждый rAF:
   .circular-gallery__item центрируется в точке (0, top) через left:50% +
   отрицательный margin (ширина/высота/margin тоже инлайн, считаются в
   updateLayout), дальше его двигает и крутит один translate3d+rotate —
   картинка и подпись поворачиваются вместе, как единая карточка. top не
   50% (геометрический центр запаса в 112vh), а выше — иначе между плашкой
   заголовка и лентой остаётся большой пустой зазор. */
.circular-gallery.is-ready .circular-gallery__item {
  position: absolute;
  top: 40%;
  left: 50%;
  will-change: transform;
}

.circular-gallery__meta {
  margin: 0.85rem 0 0;
  text-align: center;
  pointer-events: none;
}

.circular-gallery__title {
  display: block;
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 1.75rem;
  font-weight: 400;
  color: var(--color-white);
  text-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.8);
}

/* Стрелки стоят по бокам кадра, снаружи: inset с отрицательным
   горизонтальным значением выносит полосу за границы галереи ровно на
   ширину кнопки плюс зазор. Сама полоса кликов не ловит — иначе она
   перехватывала бы свайп по кадру; ловят только сами кнопки. */
.theatre-gallery__nav {
  position: absolute;
  inset: 0 -5.625rem;
  margin-top: 0;
  /* Убраны по просьбе — разметка и обработчики в js/circular-gallery.js
     остаются рабочими, достаточно снять display:none, чтобы вернуть. */
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 0;
  pointer-events: none;
}

.theatre-gallery__nav .carousel-nav__btn {
  pointer-events: auto;
  filter: drop-shadow(0 0.25rem 0.75rem rgba(0, 0, 0, 0.55));
}

/* === ADVENTURE SECTION === */
/* === TEAM SECTION === */
.team-section {
  position: relative;
  min-height: 48.75rem;
  height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

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

.team-section__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.team-section__overlay {
  position: absolute;
  inset: 0;
  background: rgba(7,6,14,0.75);
  z-index: 1;
}

.team-section__content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding: 5rem 1.25rem;
}

.team-section__layout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2.5rem;
  width: 100%;
  max-width: 72.5rem;
  margin: 0 auto;
}

.team-section__left {
  flex: 0 1 37.3125rem;
  width: min(37.3125rem, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.team-section__heading {
  text-align: center;
  margin-bottom: 2.5rem;
  width: 100%;
}

.team-section__label {
  font-family: var(--font-body);
  font-size: 1.125rem;
  color: var(--color-gold);
  margin: 0 0 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.125rem;
}

.team-section__title {
  font-family: var(--font-heading);
  font-size: 2.625rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  margin: 0;
  line-height: 1.15;
}

.team-section__card {
  width: 100%;
  background: rgba(12,11,23,0.7);
  border: 1px solid rgba(198,157,79,0.3);
  border-radius: 1.25rem;
  padding: 2.5rem;
  backdrop-filter: blur(0.625rem);
}

.team-section__photo-wrap {
  position: relative;
  flex: 0 0 30rem;
  width: 30rem;
  max-width: 48%;
  aspect-ratio: 735 / 976;
}

.team-section__photo {
  position: absolute;
  left: 7.69%;
  top: 7.18%;
  width: 84.89%;
  height: 85.84%;
  object-fit: cover;
  z-index: 1;
}

.team-section__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}

.team-section__info {
  flex: 1;
}

.team-section__name {
  font-family: var(--font-heading);
  font-size: 2rem;
  font-weight: 700;
  color: var(--color-white);
  margin: 0 0 0.5rem;
  text-align: center;
}

.team-section__role {
  font-size: 1rem;
  color: var(--color-gold);
  margin: 0 0 1.5rem;
  text-align: center;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid rgba(198,157,79,0.3);
}

.team-section__fact {
  text-align: center;
  margin-top: 1.25rem;
}

.team-section__fact-title {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  margin: 0 0 0.25rem;
}

.team-section__fact-desc {
  font-size: 0.9375rem;
  color: var(--color-light);
  margin: 0;
}

/* === CONTACT SECTION === */
.contact-section {
  position: relative;
  padding: 5.625rem 1.25rem;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.contact-section__content {
  position: relative;
  z-index: 2;
  width: 100%;
}

.contact-section__card {
  max-width: 47.5rem;
  margin: 0 auto;
  background: rgba(12, 11, 23, 0.7);
  border: 1px solid rgba(198, 157, 79, 0.3);
  border-radius: 1.25rem;
  padding: 2.75rem 3.125rem;
  backdrop-filter: blur(0.625rem);
}

.contact-section__title {
  font-family: var(--font-heading);
  font-size: 1.875rem;
  font-weight: 700;
  color: var(--color-white);
  text-align: center;
  margin: 0 0 0.75rem;
  line-height: 1.25;
}

.contact-section__sub {
  font-size: 1.125rem;
  color: var(--color-muted);
  text-align: center;
  margin: 0 0 1.875rem;
}

.contact-section__divider {
  border: none;
  border-top: 1px solid rgba(255,255,255,0.2);
  margin: 0 0 2.5rem;
}

.contact-form {
  max-width: 56.25rem;
  margin: 0 auto;
}

.contact-form__label {
  display: block;
  font-family: var(--font-body);
  font-size: 0.875rem;
  color: var(--color-muted);
  margin-bottom: 0.5rem;
}

.contact-form__field-frame {
  display: block;
  width: 100%;
  height: 3.875rem;
  --btn-frame-h: 3.875rem;
  flex-shrink: 0;
  background: transparent;
}

.contact-form__cell--submit {
  display: block;
  width: 100%;
  flex-shrink: 0;
}

.contact-form__field-frame .contact-form__input,
.contact-form__field-frame .contact-form__select {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  background: transparent;
  padding: 0 1.375rem;
  font-size: 0.9375rem;
  box-sizing: border-box;
  border: none;
  outline: none;
  font-family: var(--font-body);
  color: var(--color-white);
}

.contact-form__field-frame--select::after {
  content: '';
  position: absolute;
  right: 1.375rem;
  top: 50%;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 1.5px solid var(--color-gold);
  border-bottom: 1.5px solid var(--color-gold);
  transform: translateY(-65%) rotate(45deg);
  pointer-events: none;
  z-index: 3;
}

.contact-form__field-frame .contact-form__select {
  appearance: none;
  cursor: pointer;
  padding-right: 2.625rem;
}

.contact-form__input,
.contact-form__select {
  display: block;
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  padding: 0.75rem 1rem;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--color-white);
}

/* Инсет-рамки на фокусе у текстовых полей нет намеренно: она читалась как
   вторая обводка поверх золотых уголков .btn-frame. Индикатор фокуса для
   клавиатуры остаётся у .contact-form__select-trigger (кнопка, у неё нет
   каретки), а в text/tel фокус показывает сама каретка. */

.contact-form__select option {
  background: var(--color-bg);
  color: var(--color-white);
}

/* Custom-styled dropdown: replaces the native <select> popup (unstylable OS UI,
   see the blue highlight in Chrome/Edge) with a themed listbox. The real <select>
   stays in the DOM (hidden) so the form still submits name="event" as before;
   js/main.js drives the visible trigger + list and keeps them in sync. */
.contact-form__field-frame--select .contact-form__select {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

.contact-form__select-trigger {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  margin: 0;
  background: transparent;
  border: none;
  outline: none;
  padding: 0 2.625rem 0 1.375rem;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  text-align: left;
  color: var(--color-white);
  cursor: pointer;
}

.contact-form__select-trigger:focus-visible {
  box-shadow: inset 0 0 0 1px var(--color-gold);
}

.contact-form__field-frame--select.is-open::after {
  transform: translateY(-65%) rotate(225deg);
}

/* Рисуется в <body> (см. js/main.js), координаты и ширину задаёт JS по rect
   триггера — иначе overflow:hidden у .contact-section и overflow:auto у
   .program-order-modal__dialog обрезали бы список.
   z-index: выше .adventure-intro (10002) и .divider-stone (10000), которые
   иначе накрывают список следующей секцией, но ниже .contact-transition-overlay
   (20000) и .header (100000). */
.contact-form__select-list {
  position: fixed;
  z-index: 15000;
  margin: 0;
  padding: 0.375rem;
  list-style: none;
  max-height: 16.25rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(12, 11, 23, 0.96);
  border: 1px solid rgba(198, 157, 79, 0.35);
  border-radius: 0.625rem;
  backdrop-filter: blur(0.75rem);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.45);
}

.contact-form__select-list::-webkit-scrollbar {
  width: 0.375rem;
}

.contact-form__select-list::-webkit-scrollbar-thumb {
  background: rgba(198, 157, 79, 0.4);
  border-radius: 0.1875rem;
}

.contact-form__select-option {
  padding: 0.625rem 1rem;
  border-radius: 0.375rem;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  color: var(--color-white);
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}

.contact-form__select-option.is-active {
  background: rgba(198, 157, 79, 0.16);
  color: var(--color-gold);
}

.contact-form__select-option.is-selected {
  color: var(--color-gold);
}

/* Kill browser autofill's native white/blue fill on name & phone inputs.
   Long transition delay stalls Chromium's internal autofill repaint indefinitely,
   so background stays genuinely transparent instead of being covered by a solid patch. */
.contact-form__input:-webkit-autofill,
.contact-form__input:-webkit-autofill:hover,
.contact-form__input:-webkit-autofill:focus,
.contact-form__input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--color-white) !important;
  transition: background-color 600000s ease-in-out 0s, color 600000s ease-in-out 0s !important;
  caret-color: var(--color-white);
}

.contact-form__input:autofill {
  background-color: transparent !important;
  -webkit-text-fill-color: var(--color-white) !important;
  caret-color: var(--color-white);
}

.contact-form__checkboxes {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  flex: 1;
}

.contact-form__checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  cursor: pointer;
}

.contact-form__checkbox input {
  appearance: none;
  -webkit-appearance: none;
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.125rem;
  flex-shrink: 0;
  border: 1.5px solid var(--color-gold);
  border-radius: 0.25rem;
  background-color: rgba(198, 157, 79, 0.08);
  cursor: pointer;
  transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
}

.contact-form__checkbox input:hover {
  border-color: var(--color-white);
}

.contact-form__checkbox input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(198, 157, 79, 0.3);
}

.contact-form__checkbox input:checked {
  background-color: var(--color-gold);
  border-color: var(--color-gold);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath fill='none' stroke='%230c0b17' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' d='M1 4l3 3 5-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 0.625rem 0.5rem;
}

.contact-form__checkbox span {
  font-size: 0.8125rem;
  color: var(--color-muted);
  line-height: 1.4;
}

/* === CONTACT FORM HELP / WOW (Figma layout) === */
/* No margin-top here: at -12.5rem this used to pull the card up far enough
   to overlap .theatre-gallery__nav in #boosters above it (measured ~38px
   overlap at 1920px, ~94px at 390px — the two sections' own paddings
   already give a normal gap, unaided). */
@media (max-width: 980px) {
  .contact-section--help {
    /* Переход зал→небо (.divider-stone--bg-transition, на мобиле он
       единственный — катсцена только с 981px) стоит height:0 и поднимает
       свою картинку ровно на половину её высоты: в этом же тире у неё
       transform: translateY(-50%), без десктопного -9.375rem. Картинка
       1680x559 при width:100% даёт высоту 33.27vw, т.е. заезд наверх =
       16.6vw. Столько и компенсируем + 40px воздуха под кнопкой, вместо
       прежних фиксированных 450px, которые были посчитаны под десктопный
       сдвиг на 150px и на мобиле давали пустой зал почти в экран. */
    padding-bottom: calc(16.64vw + 40px);
  }
}

@media (min-width: 981px) {
  /* Десктоп: карточки дуги специально вылезают за границы секции — обрезка
     по её краю резала верхние/нижние углы соседних карточек. overflow тут
     обязан быть visible ПО ОБЕИМ ОСЯМ: смешанный режим (одна ось hidden,
     другая visible) CSS вычисляет как auto, а именно auto/scroll ищет
     SmoothScroll.min.js, выбирая, какой элемент скроллить колесом — тогда
     колесо начинало листать секцию вместо страницы. Чистый visible такого
     разбора не проходит, скролл остаётся на странице.
     Горизонтальный вылет за экран гасит overflow-x:hidden у html/body. */
  .boosters-section,
  .boosters-section--fullscreen,
  .theatre-gallery,
  .circular-gallery { overflow: visible; }

  /* Лента опущена на 100px относительно базовых 40% высоты секции — высоту
     самой секции это не трогает (карточки позиционируются absolute внутри
     неё, а с overflow:visible выше им ничего не мешает), так что нижний
     блок остаётся на месте. */
  .circular-gallery.is-ready .circular-gallery__item { top: calc(40% + 100px); }

  .contact-section--help {
    /* Пробег скролла между формой и стыком с #adventure. Триггер катсцены
       (js/main.js, CONTACT -> ADVENTURE CUTSCENE) взводится за
       REVEAL_TRIGGER_BUFFER до верха #smg-outer — с базовым padding'ом
       карточка едва успевала доехать до центра экрана, как перехват уже
       срабатывал и стартовал полёт. Лишняя высота внизу секции — это чистый
       запас скролла на .page-bg-fixed (фон fixed, пустой зал, никакого
       видимого провала), за который посетитель успевает прочитать и
       заполнить форму до того, как видео заберёт управление. */
    padding-bottom: 31.25rem;
  }

}

.contact-section--help .contact-section__card,
.contact-section--wow .contact-section__card {
  max-width: 71.25rem;
  padding: 3rem 3.5rem 3.25rem;
}

.contact-section--help .contact-section__title,
.contact-section--wow .contact-section__title {
  margin-bottom: 0.625rem;
  line-height: 1.2;
}

.contact-section--help .contact-section__title-gold,
.contact-section--wow .contact-section__title-gold {
  display: block;
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--color-gold);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.contact-section--help .contact-section__title-main,
.contact-section--wow .contact-section__title-main {
  display: block;
  font-size: 2.25rem;
  font-weight: 700;
  color: var(--color-white);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.contact-section--help .contact-section__sub--gold,
.contact-section--wow .contact-section__sub--gold {
  color: var(--color-gold);
  font-size: 1.125rem;
  margin-bottom: 1.75rem;
}

.contact-section--help .contact-section__divider,
.contact-section--wow .contact-section__divider {
  border-top-color: var(--color-gold);
  opacity: 0.85;
  margin-bottom: 2.25rem;
}

.contact-form--help {
  max-width: none;
}

/* Форма сокращена до одного поля (телефон) + кнопки — было 3 поля +
   2 чекбокса (запрос 31.08.2026). Прежняя 2-колоночная сетка (поле —
   minmax(0,1fr), т.е. во всю ширину карточки) растягивала прозрачную
   рамку поля до самого правого края — золотые уголки .btn-frame__border
   стоят только у левого/правого края рамки, и на такой ширине правый
   уголок оказывался далеко от текста в поле, читаясь как отдельная
   пустая рамка (жалоба владельца 31.08.2026, со скриншотом). Теперь оба
   элемента — узкие, в столбик, по центру карточки. */
.contact-form--help .contact-form__grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}

.contact-form--help .contact-form__cell {
  display: flex;
  flex-direction: column;
  width: min(28rem, 100%);
  min-width: 0;
}

.contact-form--help .contact-form__cell--checks {
  padding-top: 1.5625rem;
}

.contact-form--help .contact-form__cell--submit {
  width: min(17.5rem, 100%);
}

/* Пустая раньше выравнивала кнопку с полем "Мероприятие" в соседней
   колонке — при столбике под полем телефона она просто лишний зазор. */
.contact-form--help .contact-form__cell--submit .contact-form__label-spacer {
  display: none;
}

.contact-form--help .contact-form__label,
.contact-form--help .contact-form__label-spacer {
  display: block;
  height: 1.1875rem;
  margin-bottom: 0.375rem;
  flex-shrink: 0;
}

.contact-form--help .contact-form__label {
  color: var(--color-gold);
  font-size: 0.8125rem;
  line-height: 1.1875rem;
}

.contact-form--help .contact-form__phone {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  height: 100%;
  padding: 0 1.375rem;
  box-sizing: border-box;
}

.contact-form--help .contact-form__phone-prefix {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  flex-shrink: 0;
  font-size: 0.9375rem;
  color: var(--color-white);
  white-space: nowrap;
}

.contact-form--help .contact-form__flag {
  display: inline-block;
  width: 1.25rem;
  height: 0.875rem;
  border-radius: 0.125rem;
  background:
    linear-gradient(to bottom, #fff 0 33%, #0039a6 33% 66%, #d52b1e 66% 100%);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15);
}

.contact-form--help .contact-form__phone .contact-form__input {
  flex: 1;
  min-width: 0;
  height: auto;
  padding: 0;
}

.contact-form--help .contact-form__select {
  appearance: none;
  cursor: pointer;
  padding-right: 2.625rem;
}

.contact-form--help .contact-form__checkboxes {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
}

.contact-form--help .contact-form__checkbox span {
  color: var(--color-muted);
  font-size: 0.75rem;
  line-height: 1.35;
}

/* Ссылки на Согласие/Политику внутри текста чекбокса (запрос 15.09.2026) —
   базовый `a { color: inherit; text-decoration: none }` (style.css выше)
   иначе делает их неотличимыми от остального текста подписи. */
.contact-form__checkbox span a {
  text-decoration: underline;
}

.contact-form--help .contact-form__checkbox input {
  width: 1rem;
  height: 1rem;
}

.contact-form--help .btn-framed--block .btn-framed__text {
  font-size: 0.9375rem;
  letter-spacing: 0.04em;
}

@media (max-width: 1023px) {
  .contact-section--help .contact-section__card,
  .contact-section--wow .contact-section__card {
    padding: 36px 28px 40px;
  }

  .contact-form--help .contact-form__cell--checks {
    padding-top: 0;
  }
}

@media (max-width: 639px) {
  .contact-section--help .contact-section__title-gold,
  .contact-section--wow .contact-section__title-gold {
    font-size: 18px;
  }

  .contact-section--help .contact-section__title-main,
  .contact-section--wow .contact-section__title-main {
    font-size: 26px;
  }
}

/* === FOOTER UPDATES === */
/* === FOOTER === */
.footer {
  padding: 3.75rem 1.25rem;
}

.footer__inner {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 2.5rem;
  max-width: var(--container-width);
  margin: 0 auto;
  flex-wrap: wrap;
  background: rgba(12, 11, 23, 0.7);
  border: 1px solid rgba(198, 157, 79, 0.3);
  border-radius: 1.25rem;
  padding: 2.5rem;
  backdrop-filter: blur(0.625rem);
}

.footer__logo-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
}

.footer__logo img {
  width: 3.6875rem;
}

.footer__legal {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.footer__copy {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.4);
  margin: 0;
}

.footer__legal-link {
  font-size: 0.875rem;
  color: rgba(255,255,255,0.4);
  text-decoration: none;
}

.footer__legal-link:hover {
  color: rgba(255,255,255,0.7);
}

.footer__requisites {
  font-size: 0.75rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.28);
  margin: 0.375rem 0 0;
}

.footer__menu-title {
  font-family: var(--font-heading);
  font-size: 1rem;
  color: rgba(255,255,255,0.5);
  text-transform: uppercase;
  letter-spacing: 0.0625rem;
  margin: 0 0 1rem;
}

.footer__nav {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.footer__nav-link {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  color: var(--color-white);
}

.footer__follow {
  text-align: left;
}

.footer__socials {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.footer__social-link {
  display: flex;
  width: 2.75rem;
  height: 2.75rem;
  transition: opacity var(--transition-default);
}

.footer__social-link:hover {
  opacity: 0.75;
}

.footer__social-link svg {
  width: 2.75rem;
  height: 2.75rem;
}

/* === RESPONSIVE === */
@media (max-width: 980px) {
  /* До 980px карточка галереи считается по мобильной ветке
     js/circular-gallery.js (дуга мелкая, просадка соседей — десятки
     пикселей), поэтому десктопный запас высоты в 112vh тут не нужен:
     с ним под лентой висел пустой хвост фона высотой до трети экрана.
     Ровно один экран. Точный вертикальный центр ленты тут дожимает
     js/circular-gallery.js инлайн-стилем top (карточка вместе с подписью
     центрируется в свободной полосе под плашкой заголовка) — фиксированный
     процент не годится: на маленьких телефонах он уводил подпись за нижний
     край, на планшетах не добирал. 50% ниже — только фолбэк до JS.
     Высоту секции это не трогает — нижний блок остаётся на месте. */
  .boosters-section--fullscreen { min-height: 100vh; min-height: 100svh; }
  .circular-gallery.is-ready .circular-gallery__item { top: 50%; }

  /* Mobile never runs the desktop frame-sequence cutscene (see main.js) —
     #heroTransitionFrame just sits at frame-001.webp forever there, so it's
     safe to paint over it with a dedicated mobile hero image instead. */
  .hero__bg {
    background-image: url('../assets/img/mb_hero.webp');
    background-size: cover;
    background-position: center;
  }
  .hero__bg img { display: none; }
  /* Балка-перегородка после hero (.divider-stone--beam, z-index: 6) —
     сестра .hero-pin-wrap, а сам .hero стоит на z-index: auto, поэтому
     она перекрывала бегущую акционную полосу. .hero__content — тот
     stacking context, в котором лежит полоса; поднимаем его над балкой.
     Внутри hero порядок не меняется (у ::before/::after wash'ей z-index: 0
     относительно этого же контекста), а наружу hero не выходит — у него
     overflow: hidden. */
  .hero__content { z-index: 7; }
  .hero__promo { height: 56px; }
  .hero__promo-item { padding: 0 16px; font-size: 14px; letter-spacing: 0.1em; }
  .hero__promo-item-a { margin-right: 16px; }
  .hero__promo-sep { margin: 0 16px; }
  /* The ellipse (ry 15rem centred at 18rem) reaches 33rem down, so the
     shorter mobile box used to clip it mid-gradient — that hard cut read as
     a rectangle edge across the hero. Ellipse is re-sized per breakpoint so
     it fades to 0 exactly at the box's bottom instead. */
  .hero__content::after {
    height: 30rem;
    background: radial-gradient(
      ellipse 32rem 15rem at 50% 15rem,
      rgba(7, 6, 14, 0.78) 0%,
      rgba(7, 6, 14, 0.62) 30%,
      rgba(7, 6, 14, 0.36) 60%,
      rgba(7, 6, 14, 0.12) 82%,
      rgba(7, 6, 14, 0) 100%
    );
  }
  .hero__ornament { width: min(22rem, 82%); margin-bottom: 0.75rem; }
  .hero__title-line { font-size: 20px; }
  .hero__title-accent { font-size: 38px; }
  .hero__title-rule { width: min(220px, 68%); margin-bottom: 18px; }
  .hero__subtitle { font-size: 17px; }
  .hero__cta { padding-bottom: 24px; }
  .btn-framed--hero .btn-framed__frame { width: min(360px, calc(100vw - 48px)); }
  .btn-framed--hero .btn-framed__text { font-size: clamp(12px, 2.4vw, 18px); letter-spacing: 0.1em; }
  .btn-framed--wide .btn-framed__frame { width: min(340px, calc(100vw - 48px)); }
  .btn-framed--wide .btn-framed__text { font-size: clamp(12px, 2.2vw, 16px); }

  .section__title { font-size: 42px; }

  .ba-section { height: auto; min-height: 90vh; padding: 36px 20px 40px; }
  .ba-section__title { font-size: 42px; margin: 12px 0 24px; }
  .ba-section__sliders { flex-direction: column; gap: 48px; align-items: center; }
  .ba-item { width: 329px; height: 437px; }
  .ba-item .ultra-ba { left: 25px; top: 31px; width: 279px; height: 377px; }

  .ouija-section { padding: 40px 20px 32px; gap: 24px; }
  .ouija-section__heading { font-size: 38px; }
  .ouija-section__label { font-size: 20px; }
  .ouija-section__desc { font-size: 18px; }
  .ouija-section__board { width: min(588px, calc(100% - 40px)); }
  .ouija-section__arrow-btn { top: 219px; right: -120px; width: 175px; }
  /* Скрыт на мобиле: лист налезал на заголовок и подзаголовок секции. */
  .ouija-section__leaves { display: none; }
  .ouija-section__card { width: min(614px, calc(100% - 40px)); min-height: 300px; padding: 40px 32px 36px; gap: 18px; }
  .ouija-section__submit img { height: 38px; }

  .children-section { min-height: 1080px; }
  .children-section__title { top: calc(450px - 291px); left: 103px; font-size: 42px; }
  .children-section__subtitle { top: calc(450px - 240px); left: 201px; font-size: 28px; }
  .children-section__desc-block { top: calc(450px - 174px); left: 201px; width: 459px; }
  .children-section__frame { top: 71px; left: calc(50% - 600px + 704px); width: 399px; }
  .children-section__portrait { top: 95px; left: calc(50% - 600px + 751px); width: 269px; height: 388px; }
  .children-section__kid--1 { top: calc(900px - 562px); left: calc(50% - 97px); width: 194px; }
  .children-section__kid--2 { top: calc(900px - 543px); left: calc(50% + 11px); width: 267px; }
  .children-section__kid--3 { top: calc(900px - 521px); left: calc(50% + 296px); width: 202px; }
  .children-section__kid--4 { top: calc(900px - 548px); left: calc(50% + 500px); width: 180px; }

  .programs-section { min-height: max(720px, calc(100vw * 945 / 1680)); }
  .programs-section__inner { padding: 44px 20px 32px; gap: 10px; }
  /* .programs-section__carousel-wrap's own full-bleed rule (base tier)
     already gets the slider to the full screen width here — nothing tier-
     specific needed. Its children re-apply an inset where they actually
     need one instead: .carousel-content__header keeps its own padding for
     the title/desc text, .prog-carousel keeps its own (smaller) padding as
     the shadow-gutter for the cards. */
  .programs-section__title { font-size: 46px; }
  .programs-section__subtitle { font-size: 18px; }
  .programs-section__tabs {
    --prog-tab-w: 147px;
  }
  .programs-section__tabs::before { left: 4%; right: 4%; }

  /* Below desktop width there's no room for 3 cards side by side, so this
     tier switches to 2-per-view — the slider engine itself (translateX by
     integer index) is the same one running at every width, defined once on
     the unmodified base .prog-carousel / .prog-carousel__track rules above.
     Only the numbers that need to shrink for a narrower screen live here:
     a tighter track gap, and cards sized to exactly N-per-view (flex-basis
     = (track width - 1 gap) / 2, not the desktop's fixed 17.5rem) so a
     settled slide always shows whole cards — a fixed width would leave a
     partial next card peeking in and getting clipped by the viewport edge
     whenever the screen wasn't an exact multiple of it. Gap in the formula
     matches the track's actual gap here (6px, not the base tier's 30px) so
     two cards + one gap tile exactly to 100% with no leftover slack. */
  .prog-carousel { padding: 0 20px; }
  .prog-carousel__track { gap: 6px; }
  .prog-card { width: auto; flex: 0 0 calc((100% - 6px) / 2); }
  /* The card slot always stays a whole 1/Nth of the track — that's what keeps
     the slider's pitch (`-index * pitch`, js/main.js) landing every card in
     the same place — so the image is inset *inside* its slot rather than the
     slot itself being narrowed. That inset is therefore also the visible
     spacing between two neighbouring cards: the gap a person actually sees is
     2 x the inset + the track's own gap, which is why this percentage, not
     `gap`, is the number that controls it (at 80% it worked out to ~80px on a
     390px phone against a 4px `gap` — 95% of the spacing came from here).
     Keep it high: the inset doubles as the card's breathing room at rest, so
     lowering the number widens the gap and shrinks the resting card together —
     they're the same measurement seen from two sides. */
  .prog-card > img { width: 92%; height: auto; aspect-ratio: 240 / 310; margin: 0 auto; }

  .boosters-section__intro { padding: 22px 28px; }
  .boosters-section__title { font-size: 38px; }
  .boosters-section__subtitle { font-size: 16px; margin-top: -8px; }
  .theatre-gallery__nav { inset: 0 -76px; }
  .theatre-gallery__nav .carousel-nav__btn { width: 60px; height: 60px; }

  .team-section { min-height: 720px; height: auto; }
  .team-section__layout { flex-direction: column-reverse; align-items: center; gap: 32px; }
  .team-section__left { flex: 1 1 auto; width: 100%; max-width: 597px; }
  .team-section__title { font-size: 32px; }
  .team-section__photo-wrap { flex: 0 0 auto; width: min(440px, 100%); max-width: 100%; align-self: center; }
  .team-section__card { padding: 30px 20px; }
  .team-section__label { font-size: 15px; }
  .team-section__name { font-size: 26px; }
  .team-section__role { font-size: 15px; margin-bottom: 20px; padding-bottom: 16px; }
  .team-section__fact-title { font-size: 16px; }
  .team-section__fact-desc { font-size: 14px; }

  /* .html's rem scale locks to a 7.36px root below 920px (see the comment
     on html{font-size:...} up top), so any rem-sized text without a raw-px
     override here collapses far below its intended size on mobile. The
     blocks below restore readable sizes for the pieces that only had their
     layout adjusted before, not their type scale. */
  .carousel-content__header { margin-bottom: 24px; padding: 0 16px; }
  .carousel-content__title { font-size: 22px; }
  .carousel-content__desc { font-size: 14px; }
  .prog-card__title { font-size: 17px; }

  .contact-section__title { font-size: 28px; }
  .contact-section__sub { font-size: 15px; margin-bottom: 24px; }
  .contact-form__label { font-size: 13px; }
  .contact-form__input,
  .contact-form__select,
  .contact-form__select-trigger { font-size: 16px; }
  .contact-form--help .contact-form__phone-prefix { font-size: 14px; }
  .contact-form--help .contact-form__checkbox span { font-size: 13px; }

  .footer__inner { flex-direction: column; align-items: center; text-align: center; padding: 40px 20px 20px; }
  .footer__logo-col { align-items: center; }
  .footer__nav { align-items: center; }
  .footer__follow { text-align: center; }
}

@media (max-width: 639px) {
  .hero-pin-wrap { min-height: 640px; height: 95vh; }
  .hero { min-height: 640px; height: 95vh; }
  .hero__content::after {
    height: 26rem;
    background: radial-gradient(
      ellipse 28rem 13rem at 50% 13rem,
      rgba(7, 6, 14, 0.78) 0%,
      rgba(7, 6, 14, 0.62) 30%,
      rgba(7, 6, 14, 0.36) 60%,
      rgba(7, 6, 14, 0.12) 82%,
      rgba(7, 6, 14, 0) 100%
    );
  }
  .hero__ornament { width: min(17rem, 78%); }
  .hero__title-line { font-size: 17px; }
  .hero__title-accent { font-size: 33px; }
  .hero__title-rule { width: min(180px, 64%); margin-bottom: 16px; }
  .hero__subtitle { font-size: 15px; letter-spacing: 0.04em; }
  .hero__top { padding-top: calc(var(--header-height) + 8px); }
  .hero__cta { padding-bottom: 18px; }
  .btn-framed--hero .btn-framed__frame { width: min(300px, calc(100vw - 48px)); }
  .btn-framed--hero .btn-framed__text { font-size: clamp(11px, 3.2vw, 15px); letter-spacing: 0.08em; }
  .btn-framed--wide .btn-framed__frame { width: min(300px, calc(100vw - 48px)); }
  .btn-framed--wide .btn-framed__text { font-size: clamp(11px, 3vw, 14px); letter-spacing: 0.08em; }
  .btn-framed--block .btn-framed__text { font-size: clamp(11px, 3vw, 14px); }

  .ba-section { height: auto; min-height: 90vh; padding: 28px 20px 32px; }
  /* Скрим под заголовок — тот же приём, что у .children-section__overlay
     и .hero__content::before: тёмный навигационный тон rgba(7, 6, 14)
     сверху вниз, до нуля примерно на середине секции, чтобы белый текст
     не тонул в подсвеченной свечами кладке. Базовый .ba-section__gradient
     (0deg, максимум 0.5 у верхней кромки) на мобиле слишком слаб —
     заголовок здесь крупнее относительно кадра и стоит выше по картинке. */
  .ba-section__gradient {
    background: linear-gradient(
      to bottom,
      rgba(4, 7, 21, 0.82) 0%,
      rgba(7, 6, 14, 0.6) 20%,
      rgba(7, 6, 14, 0.32) 40%,
      rgba(7, 6, 14, 0.1) 60%,
      rgba(7, 6, 14, 0) 78%
    );
  }

  /* Базовый margin-top -1.25rem задирал заголовок под балку-перегородку
     (.divider-stone--beam, её картинка заезжает вверх на 68% высоты).
     На мобиле уводим его вниз, в чистое поле под балкой. */
  .ba-section__title { font-size: 32px; margin: 24px 0 20px; }

  .ouija-section { padding: 32px 20px 24px; gap: 20px; }
  .ouija-section__heading { font-size: 26px; }
  .ouija-section__label { font-size: 18px; }
  .ouija-section__desc { font-size: 16px; }
  .ouija-section__board { width: min(335px, calc(100% - 40px)); }
  .ouija-section__arrow-btn { top: 132px; right: -40px; width: 100px; }
  .ouija-section__card { width: min(422px, calc(100% - 40px)); min-height: 280px; padding: 32px 24px 28px; gap: 16px; }
  .ouija-section__card-sub { font-size: 14px; }
  .ouija-section__form { height: 43px; }
  .ouija-section__field-frame { height: 43px; --btn-frame-h: 43px; }
  .ouija-section__input { font-size: 14px; padding: 0 16px; }
  .ouija-section__card-title { font-size: 16px; }
  .children-section { min-height: 900px; height: auto; }
  /* На мобиле текст лежит сверху, а не слева — градиент разворачиваем
     по вертикали, иначе тёмная сторона уходит за левый край экрана. */
  .children-section__overlay {
    width: 100%;
    background: linear-gradient(
      to bottom,
      rgba(4, 7, 21, 0.96) 0%,
      rgba(7, 6, 14, 0.82) 38%,
      rgba(7, 6, 14, 0.42) 62%,
      rgba(7, 6, 14, 0.12) 84%,
      rgba(7, 6, 14, 0) 100%
    );
  }
  .children-section__title {
    top: 68px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 26px;
    white-space: normal;
    text-align: center;
    /* Было 262px — «Дети - двигатель» не влезало в строку и переносилось
       на 3 строки вместо 2, наезжая на подзаголовок с фиксированным top
       ниже. 300px даёт первой строке место. */
    width: min(300px, calc(100% - 40px));
  }
  .children-section__subtitle {
    top: 156px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 18px;
    white-space: normal;
    text-align: center;
    width: min(280px, calc(100% - 40px));
  }
  .children-section__desc-block {
    top: 196px;
    left: 50%;
    transform: translateX(-50%);
    width: min(320px, calc(100% - 40px));
  }
  .children-section__line { width: 100%; }
  .children-section__desc-lead,
  .children-section__desc { font-size: 16px; }
  /* Разрывы <br> в разметке рассчитаны на широкий десктоп-контейнер (497px)
     и дают там 3 ровные строки. На мобильной ширине (320px) те же точки
     разрыва режут текст на огрызки по 1-2 слова — отключаем принудительные
     переносы, даём тексту обтекать естественно по словам. */
  .children-section__desc br { display: none; }
  .children-section__frame {
    top: 326px;
    left: 50%;
    transform: translateX(-50%);
    width: min(297px, calc(100% - 40px));
  }
  .children-section__portrait {
    top: 348px;
    left: 50%;
    transform: translateX(-50%);
    width: min(243px, calc(100% - 80px));
    height: 351px;
  }
  /* Крупнее ~на 15%; центры фигур сохранены, bottom опущен, чтобы прибавка
     в высоте не наехала на нижний край рамы портрета. */
  .children-section__kid--1 { top: auto; bottom: 8px; left: calc(50% - 192px); width: 115px; }
  .children-section__kid--2 { top: auto; bottom: 0; left: calc(50% - 114px); width: 161px; }
  /* z-index: у всех .children-section__kid он 4, порядок решает DOM —
     kid--4 идётпозже,  и перекрывал бы девочку слева от него. */
  .children-section__kid--3 { top: auto; bottom: 4px; left: calc(50% + 16px); width: 109px; z-index: 5; }
  .children-section__kid--4 { top: auto; bottom: 10px; left: calc(50% + 91px); width: 98px; }
  .programs-section { min-height: max(640px, calc(100vw * 945 / 1680)); }
  .programs-section__inner { padding: 32px 16px 24px; gap: 8px; }
  /* Narrower than the tablet 2-up tier above — 2 cards side by side would
     squeeze below the card-button's own min-width, so drop to 1 full,
     un-cropped card per view instead of a partial 2nd one peeking in. */
  .prog-card { flex-basis: 100%; }
  /* Карточка = 100% трека, поэтому её размер задаём боковыми полями самой
     .prog-carousel: 11% с каждой стороны → карточка ~78% экрана вместо
     почти полной ширины. Gap трека (6px) не трогаем — расстояние между
     карточками остаётся прежним. overflow:hidden клипает по padding-box,
     так что соседние карточки симметрично выглядывают в этих полях. */
  .prog-carousel { padding: 0 11%; }
  .programs-section__header { margin-bottom: 0; }
  .programs-section__title { font-size: 29px; }
  .programs-section__subtitle { font-size: 13px; }
  .programs-section__tabs {
    gap: 10px 6px;
    margin-top: 8px;
    --prog-tab-w: 96px;
  }
  /* Пятая медаль переносилась на отдельную строку и висела по центру одна.
     Скрываем её на мобиле — остаётся ровно один ряд из четырёх. Заодно
     убираем декоративную линию: её top считается от --prog-tab-line-top
     под второй ряд, без него она вылезала бы за низ контейнера. */
  #progtab-animation { display: none; }
  .programs-section__tabs::before { display: none; }
  .prog-tab {
    transform: none !important;
  }
  .prog-tab:hover,
  .prog-tab.active {
    transform: translateY(-6px) !important;
  }

  .boosters-section__intro { padding: 18px 20px; border-radius: 18px; max-width: calc(100vw - 40px); }
  .boosters-section__title { font-size: 28px; }
  .boosters-section__subtitle { font-size: 15px; margin-top: -6px; }
  /* На узких экранах подзаголовок переносится на 3 строки — плашка выше,
     и той же top:40%, что на десктопе, ленте уже не хватает, чтобы не
     наезжать на неё сверху. */
  .circular-gallery__title { font-size: 18px; }
  /* Снаружи места уже нет — стрелки ложатся поверх краёв кадра. */
  .theatre-gallery__nav { inset: 0; padding: 0 10px; box-sizing: border-box; }
  .theatre-gallery__nav .carousel-nav__btn { width: 50px; height: 50px; }

  .carousel-content__title { font-size: 19px; }
  .prog-card__title { font-size: 19px; }

  .team-section__name { font-size: 22px; }
  .team-section__role { font-size: 14px; margin-bottom: 16px; padding-bottom: 14px; }
  .team-section__fact-title { font-size: 15px; }
  .team-section__fact-desc { font-size: 13px; }

  .btn { font-size: 18px; }
}

@media (max-width: 479px) {
  .hero__content::after {
    height: 22rem;
    background: radial-gradient(
      ellipse 24rem 11rem at 50% 11rem,
      rgba(7, 6, 14, 0.78) 0%,
      rgba(7, 6, 14, 0.62) 30%,
      rgba(7, 6, 14, 0.36) 60%,
      rgba(7, 6, 14, 0.12) 82%,
      rgba(7, 6, 14, 0) 100%
    );
  }
  .hero__ornament { width: min(14rem, 74%); margin-bottom: 0.625rem; }
  .hero__title-line { font-size: 15px; }
  .hero__title-accent { font-size: 29px; }
  .hero__title-rule { width: min(150px, 60%); margin-bottom: 14px; }
  .hero__subtitle { font-size: 13px; }
  .hero__top { padding-top: calc(var(--header-height) + 5px); }
  .hero__cta { padding-bottom: 14px; }
  .hero__promo { height: 48px; }
  .hero__promo-item { padding: 0 12px; font-size: 12px; }
  .hero__promo-item-a { margin-right: 12px; }
  .hero__promo-sep { margin: 0 12px; }
  .btn { font-size: 18px; }
  .programs-section__tabs { --prog-tab-w: 80px; }
  .prog-carousel__track { padding: 20px 0 40px; gap: 4px; }
  .prog-card > img { aspect-ratio: 220 / 280; }

  /* То же поле, что и на тире 639px (см. комментарий там): оно задаёт
     ширину карточки и симметричный peek соседей. Чуть уже, потому что на
     самых узких экранах 7% с каждой стороны съедали бы слишком много. */
  .prog-carousel { padding: 0 9.5%; }

  .circular-gallery__title { font-size: 15px; }
  .theatre-gallery__nav { inset: 0; padding: 0 6px; }
  .theatre-gallery__nav .carousel-nav__btn { width: 42px; height: 42px; }
}

/* === SCROLL REVEAL (photos / cards / frames) ===
   --reveal is driven continuously by scroll position (js/main.js), not toggled once,
   so scrolling back up plays the reveal in reverse. :where() keeps zero specificity
   so elements with their own transform (ouija board, prog-card) can compose it in.
   Opacity is intentionally not used here — only text reveal fades via opacity. */
:where(.js-reveal-media) {
  --reveal: 0;
  --reveal-distance: 2.5rem;
  transform: translateY(calc((1 - var(--reveal, 0)) * var(--reveal-distance)));
}

@media (prefers-reduced-motion: reduce) {
  .js-reveal-media {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* === TEXT REVEAL (per-line, GSAP ScrollTrigger — see js/main.js) ===
   Pre-set the hidden state in CSS so lines don't flash visible before GSAP's
   fromTo() takes over on init; SplitType wraps each line in this markup. */
.hidden-perspective-scrub {
  width: 100%;
}

.hidden-perspective-scrub .line {
  opacity: 0;
  transform: perspective(43.75rem) translate3d(0, 2.5rem, 0) rotateX(80deg) scale(0.85);
}

/* === PARALLAX BACKGROUNDS === */
.js-parallax {
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .js-parallax {
    transform: none !important;
  }
}

/* === CUSTOM FORM VALIDATION ===
   Заменяет нативные пузыри браузера ("Заполните это поле"). Формы получают
   novalidate из js/main.js, поэтому нативный UI не показывается вообще, а
   .form-tip рисуется в body с position:fixed — так подсказка не режется
   overflow:auto у .program-order-modal__dialog и лежит выше него (z-index 210). */
:root {
  --color-error: #d9634e;
}

.form-tip {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 15100;   /* на ступень выше списка селекта, см. его правило ниже */
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: min(20rem, calc(100vw - 1rem));
  padding: 0.5625rem 0.875rem 0.5625rem 0.6875rem;
  border: 1px solid rgba(217, 99, 78, 0.55);
  border-radius: 0.5rem;
  background: linear-gradient(180deg, rgba(26, 14, 14, 0.98) 0%, rgba(14, 10, 16, 0.98) 100%);
  box-shadow: 0 0.75rem 1.75rem rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(198, 157, 79, 0.12) inset;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  line-height: 1.35;
  color: #f2e3d5;
  pointer-events: none;
  opacity: 0;
  transform: translateY(-0.375rem);
  transition: opacity 0.18s ease-out, transform 0.18s ease-out;
}

.form-tip--above {
  transform: translateY(0.375rem);
}

.form-tip.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Ромб с «!» — тот же геометрический язык, что у золотых уголков .btn-frame */
.form-tip__icon {
  position: relative;
  flex-shrink: 0;
  width: 1.125rem;
  height: 1.125rem;
  border: 1px solid var(--color-error);
  background: rgba(217, 99, 78, 0.18);
  transform: rotate(45deg);
}

.form-tip__icon::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0.1875rem;
  width: 1.5px;
  height: 0.4375rem;
  margin-left: -0.75px;
  background: var(--color-error);
  transform: rotate(-45deg);
  transform-origin: top center;
}

.form-tip__icon::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 0.1875rem;
  width: 1.5px;
  height: 1.5px;
  margin-left: -0.75px;
  background: var(--color-error);
}

/* Хвостик-выноска: --tip-arrow-x ставит js/main.js по центру поля */
.form-tip__arrow {
  position: absolute;
  left: var(--tip-arrow-x, 50%);
  width: 0.625rem;
  height: 0.625rem;
  margin-left: -0.3125rem;
  background: rgba(24, 13, 14, 0.98);
  border: 1px solid rgba(217, 99, 78, 0.55);
  transform: rotate(45deg);
}

.form-tip:not(.form-tip--above) .form-tip__arrow {
  top: -0.3125rem;
  border-right: none;
  border-bottom: none;
}

.form-tip--above .form-tip__arrow {
  bottom: -0.3125rem;
  border-left: none;
  border-top: none;
}

/* Невалидное поле: золотые уголки рамки перекрашиваются в красный фильтром
   (они background-image, перекрасить их иначе нельзя без второго набора SVG) */
.contact-form__field-frame.is-invalid {
  --btn-frame-fill: rgba(45, 16, 16, 0.78);
}

.contact-form__field-frame.is-invalid .btn-frame__border {
  filter: hue-rotate(-38deg) saturate(1.85) brightness(1.05);
}

.contact-form__field-frame.is-invalid .contact-form__input::placeholder {
  color: rgba(217, 99, 78, 0.75);
}

.contact-form__checkbox.is-invalid input {
  border-color: var(--color-error);
  background-color: rgba(217, 99, 78, 0.14);
}

.contact-form__checkbox.is-invalid span {
  color: #edc7bb;
}

.form-shake {
  animation: form-shake 0.34s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
}

@keyframes form-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
  .form-shake { animation: none; }
  .form-tip { transition: opacity 0.18s ease-out; transform: none; }
  .form-tip.is-visible { transform: none; }
}

/* Статус отправки — в той же палитре, вместо инлайновых цветов из main.js */
.contact-form__status {
  font-family: var(--font-body);
}

.contact-form__status--error { color: var(--color-error); }
.contact-form__status--ok { color: var(--color-gold); }

/* === ROLLING TEXT (навигация) ===
   Разметку строит js/main.js: в ссылку вкладывается .rolling-text с двумя
   одинаковыми .rolling-text__block, каждая буква — отдельный .letter со
   своей transition-delay. Контейнер высотой в одну строку с overflow:hidden,
   на ховере все буквы уезжают на -100% и снизу выкатывается вторая копия. */
.rolling-text {
  display: inline-block;
  overflow: hidden;
  /* height обязан совпадать с line-height до пикселя: вторая копия стоит
     ровно на одну строку ниже, и translateY(-100%) буквы должен попасть в
     неё. 1.15 — минимум, при котором кириллические «Д»/«Ц» не режутся. */
  height: 1.15em;
  line-height: 1.15;
  vertical-align: bottom;
}

.rolling-text__block {
  display: block;
  white-space: nowrap;
}

.rolling-text .letter {
  display: inline-block;
  transition: transform 0.6s cubic-bezier(0.76, 0, 0.24, 1);
}

/* Специфичность 0,3,0 — иначе :hover самой ссылки перебивает цвет копии. */
.rolling-text .rolling-text__block:last-child .letter {
  color: var(--color-gold);
}

a:hover .rolling-text .letter,
a:focus-visible .rolling-text .letter,
.rolling-text.is-playing .letter {
  transform: translateY(-100%);
}

@media (prefers-reduced-motion: reduce) {
  .rolling-text .letter {
    transition: none;
  }
}

/* === COOKIE CONSENT === */
.cookie-bar {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translate(-50%, calc(100% + 2rem));
  z-index: 20500; /* above .contact-transition-overlay (20000), below nothing critical */
  width: min(53.125rem, calc(100vw - 2rem));
  padding: 1.375rem 1.75rem;
  display: flex;
  background: rgba(12, 11, 23, 0.92);
  border: 1px solid rgba(198, 157, 79, 0.35);
  border-radius: 0.9375rem;
  -webkit-backdrop-filter: blur(0.75rem);
  backdrop-filter: blur(0.75rem);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.4s ease, opacity 0.4s ease;
}

.cookie-bar.is-visible {
  transform: translate(-50%, 0);
  opacity: 1;
  pointer-events: auto;
}

.cookie-bar__inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
}

.cookie-bar__text {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--color-muted);
}

.cookie-bar__actions {
  flex-shrink: 0;
}

.cookie-bar__btn {
  font-family: var(--font-heading);
  font-size: 0.9375rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-gold);
  background: transparent;
  border: 1px solid var(--color-gold);
  border-radius: 0.5rem;
  padding: 0.75rem 1.5rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--transition-default), color var(--transition-default);
}

.cookie-bar__btn:hover,
.cookie-bar__btn:focus-visible {
  background-color: var(--color-gold);
  color: var(--color-bg);
}

@media (max-width: 639px) {
  .cookie-bar {
    bottom: 0.75rem;
    padding: 1.125rem 1.25rem;
  }

  .cookie-bar__inner {
    flex-direction: column;
    align-items: stretch;
    gap: 1rem;
  }

  .cookie-bar__text {
    font-size: 0.875rem;
  }

  .cookie-bar__btn {
    width: 100%;
  }
}
