/* ============================================================================
   RedoSchool — styles.css
   ============================================================================

   Единый файл стилей. Раньше те же правила лежали в трёх местах: в инлайн-`<style>`
   в `<head>`, во внешнем styles.css и в втором инлайн-`<style>` внутри `<body>`.
   Внешний файл подключался между ними, поэтому часть его правил перебивалась
   инлайновыми, а часть — нет. Здесь всё в одном файле и в том же каскаде.

   ПОРЯДОК ПРАВИЛ — НЕ СЛУЧАЙНЫЙ, А ТОТ ЖЕ, ЧТО БЫЛ
   -----------------------------------------------------------------------
   Файл собран из трёх источников, идущих именно в таком порядке:

     1. первый инлайн-`<style>` в `<head>`   — база, типографика, общие части
     2. внешний styles.css                    — «неоновая» оболочка
     3. второй инлайн-`<style>` в `<body>`    — демо, скриншоты, секции, футер

   Каждый селектор перенесён на позицию ПОСЛЕДНЕГО своего объявления, поэтому
   каскад не изменился ни на один градус: то, что побеждало раньше, побеждает
   и сейчас. Это единственный безопасный способ сливать CSS-файлы — любая
   перестановка здесь молча поменяет стили.

   Все блоки `prefers-reduced-motion` собраны в самом конце файла. В старой
   вёрстке часть из них стояла выше по файлу, чем правила, которые отключение
   анимации должно было погасить, — из-за чего отключение не срабатывало.
   В конце файла такие переопределения всегда побеждают, как и должны.

   ШРИФТЫ И ТОКЕНЫ
   -----------------------------------------------------------------------
   На сайте ровно два шрифта, оба из assets/fonts: Harpseal (заголовки) и
   OpenRunde (текст). Запасных гарнитур в стеке нет намеренно — если файл
   шрифта не подгрузится, страница молча уехала бы на чужой шрифт. Поэтому
   при сбое загрузки останется системный sans-serif.

   Шкала отступов (`--rs-sp-1`…`--rs-sp-7`) описана у :root в начале файла.
   Подробное объяснение каждой ступени — в комментарии над ней; это единственное
   место в CSS, где оно нужно, остальные правила на неё ссылаются коротко.

   Порядок разделов ниже повторяет каскад, а не логику вёрстки: поэтому
   «Внешний styles.css» (неоновая оболочка кнопок) стоит между «Демо-секция»
   и «Квиз». Это цена слияния без перестановок; правила внутри блоков
   сгруппированы по назначению.
   ========================================================================= */

/* ============================ Шрифты ============================= */

/* Harpseal — заголовки, OpenRunde — текст. Запасных гарнитур в стеке нет
   намеренно: если файл не подгрузится, страница молча уехала бы на чужой
   шрифт. Поэтому при сбое загрузки останется системный sans-serif.

   font-display: swap — без него поведение неявное. По спецификации отсутствие
   этой строки равносильно font-display: auto, а браузеры трактуют auto
   по-разному: часть держит текст невидимым до загрузки шрифта (до трёх
   секунд на медленной сети), часть рисует запасным сразу. Явный swap
   делает поведение одинаковым везде: текст появляется сразу системным
   шрифтом и меняется на свой, когда тот пришёл. При этом меняются только
   строки текста, а не вся страница. */

@font-face {
      font-family: "Harpseal";
      src: url("assets/fonts/harpseal.otf") format("opentype");
      font-weight: 400;
      font-style: normal;
      font-display: swap;
    }

@font-face {
      font-family: "OpenRunde";
      src: url("assets/fonts/OpenRunde/OpenRunde-Regular.woff2") format("woff2");
      font-weight: 400;
      font-style: normal;
      font-display: swap;
    }

@font-face {
      font-family: "OpenRunde";
      src: url("assets/fonts/OpenRunde/OpenRunde-Medium.woff2") format("woff2");
      font-weight: 500;
      font-style: normal;
      font-display: swap;
    }

@font-face {
      font-family: "OpenRunde";
      src: url("assets/fonts/OpenRunde/OpenRunde-Semibold.woff2") format("woff2");
      font-weight: 600;
      font-style: normal;
      font-display: swap;
    }

@font-face {
      font-family: "OpenRunde";
      src: url("assets/fonts/OpenRunde/OpenRunde-Bold.woff2") format("woff2");
      font-weight: 700;
      font-style: normal;
      font-display: swap;
    }

/* ====================== Токены: цвета, шрифты, отступы ======================= */

/* Demo block — design from landing 2

   Отступы здесь дублируют правила из <style> в index.html: этот файл —
   тёмная тема, а инлайновые правила перекрашивают блок в светлый по макету.
   Значения держатся теми же ступенями шкалы (--rs-sp-*, объявлены в :root
   в index.html), чтобы при отключении инлайновых правил ритм не рассыпался. */
/* ==========================================================
   Neon buttons — единый стиль для всех кнопок на странице
   ========================================================== */
:root {
  /* Нужен переходу height у ::details-content: без него переход между
     height: auto (раскрытый ответ) и height: 0 (закрытый) невозможен —
     auto не является интерполируемым значением. Поддержка: Chrome/Edge
     131+, Safari 18+. Без него правило на ::details-content не применится
     и вопрос откроется штатно, без анимации. */
  interpolate-size: allow-keywords;

  /* Фон страницы. Был #060e1e — почти чёрный синий, L≈7%. Поднят до
     #0f1233: та же тёмная база, но на четыре ступени светлее и с уходом
     в индиго (тон 234° против 222°). Подъём небольшой — на белом фоне
     разница была бы заметной, на тёмной теме читается как «фон стал
     чуть менее мёртвым», а не как перекраска. Вверх не пошли специально:
     панели, плашки и обводки берут этот же токен, и на большем
     подъёме они начали бы сливаться с фоном.

     Токен, а не литерал в body: им задан и .section-light, и скроллбары,
     и градиентные растушёвки — иначе эти места остались бы на прежнем
     #060e1e и разошлись с фоном страницы. */
  --rs-panel: #1a2f84;
  --rs-panel-soft: #0a162d;

  /* Запас высоты параллакс-слоя .bg-parallax над экраном. Слой выше окна
     ровно на этот бюджет, поэтому при любом сдвиге видимая часть закрыта
     целиком: снизу не оголяется. Здесь — 300px, добор для страницы без JS:
     скрипт параллакса в script.js переписывает токен на расчёт по высоте
     страницы (K × прокручиваемая высота, ограничен потолком), чтобы
     движение переживало весь скролл, а не кончалось к середине. */
  --rs-bg-travel: 300px;

  /* Фон блоков с мелким текстом — тех, где космос гаснут в сплошную заливку:
     «Ваш ИИ-преподаватель», «Выбери, кто сейчас читает» и «Часто задаваемые
     вопросы». Отдельный токен, а не перекраска --rs-panel: последний держит
     фон страницы, .section-light и скроллбары, и смена оттенка здесь поехала
     бы по всей странице. Заливка #0a0d4e заметно темнее прежнего #1a2f84 —
     на фоне фотографии блок перестаёт спорить с картинкой и читается как
     спокойная подложка под мелкий текст. */
  --rs-panel-blue: #0a0d4e;
  --rs-accent: #4dd0e1;
  --rs-cta: #ffb04a;
  --rs-cta-hover: #f4620a;
  --rs-dialog: #003dff;
  --rs-pale: #bcf2ff;
  --rs-ink: #dfe9f7;
  --rs-muted: #a9c3d4;
  --rs-paper: #f4f8fc;
  --rs-paper-ink: #0b1b33;
  --rs-paper-muted: #416080;
  --rs-line: rgba(255,255,255,0.12);
  /* Белая трапециевидная «скобка» для плашек — переиспользуемый фон */
  --rs-clip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 70 14' preserveAspectRatio='none'%3E%3Cpath d='M3 0L67 0Q70 0 68.1 2.3L60.7 11.7Q58.8 14 55.8 14L14.2 14Q11.2 14 9.3 11.7L1.9 2.3Q0 0 3 0Z' fill='%23fff'/%3E%3C/svg%3E");
  /* Диалог: светлые «облака» по макету */
  --rs-chat-rita: #7ed4ea;
  --rs-chat-user: #dff0f8;
  --rs-chat-ink: #0d3a5c;
  /* На сайте ровно два шрифта, оба из assets/fonts: Harpseal (заголовки)
           и OpenRunde (текст). Запасных гарнитур в стеке нет намеренно: раньше
           там стояли Arial Rounded MT Bold / Trebuchet MS / Segoe UI / Tahoma,
           и если бы файл шрифта не подгрузился, страница молча уехала бы на
           чужой шрифт. Теперь при сбое загрузки останется системный
           sans-serif — это не конкретный шрифт, а запасной вариант браузера. */
  --rs-font-head: "Harpseal", sans-serif;
  --rs-font-body: "OpenRunde", sans-serif;
  /* Кегли заголовков заданы здесь, а правила ниже меняют только цвет,
           отступы и трекинг. Иначе у каждого заголовка был свой размер: у h2
           их было три (55px / 44px / 42px на широком экране), и стопка секций
           читалась неровно. */
  --rs-h1-size: clamp(2.4rem, 4.5vw, 4rem);
  --rs-h1-lh: 0.98;
  --rs-h2-size: clamp(1.6rem, 2.9vw, 2.5rem);
  --rs-h2-lh: 1.08;
  --rs-h2-ls: 0.01em;
  /* ---------- Шкала отступов ----------
           Раньше в вёрстке было около двадцати разных значений (2, 4, 5, 6,
           8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34,
           36, 48, 56…) — соседние блоки отстояли друг от друга на 22 и на 16
           px, карточки на 20 и на 24, панели на 26 и на 34. Теперь все
           расстояния на сайте берутся от этих восьми ступеней: шаг 4px от 4 до
           32 и один крупный шаг 48. Всё, что не совпало со ступенью, — либо
           намеренное исключение с комментарием (оптические отступы, линия
           таймлайна, 140px в шапке), либо ошибка округления, исправленная.

           Порядок ступеней снизу вверх по смыслу:
           4  — микро: точки-индикаторы, внутренние отступы значков,
                заголовок карточки и его подпись (одна смысловая пара)
           8  — группы: точки прогресса, строки внутри одного поля
           12 — списки и ряды: пункты списка, пары кнопок, чипы
           16 — внутренние блоки карточки (заголовок → текст)
           24 — между карточками и колонками
           32 — нижний отступ секции; вместе с верхним 96px он даёт
                одинаковые 128px между содержимым соседних секций
           48 — крупные разрывы: футер и разрыв между двумя колонками
                секции (текст + блок: .rita-grid, .python-layout,
                .audience-panel, .faq-container)

           Правило проверки: если два однотипных предмета на странице стоят на
           разных ступенях, одна из пар неверна. Расхождения, найденные такой
           сверкой и исправленные: отступ от заголовка секции до первого блока
           в #shots (48 → 32, как в #for и #faq), разрыв между колонками в
           .faq-container (32 → 48, как в остальных двухколоночных секциях),
           зазор между кнопками в карточках демо (8 → 12, как в герое и в
           финальной карточке), шаг плашек Python (10 + 2 рамки = 14 → 12 + 2
           рамки = 16) и ширина героя (1160 → 1180, чтобы текст начинался на
           одной вертикали со всеми остальными секциями). */
  --rs-sp-1: 4px;
  --rs-sp-2: 8px;
  --rs-sp-3: 12px;
  --rs-sp-4: 16px;
  --rs-sp-5: 24px;
  --rs-sp-6: 32px;
  --rs-sp-7: 48px;
  /* Верхняя отступка секции — две ступени sp-7. Отдельно от ступеней,
           потому что её нельзя менять вместе с остальным ритмом: она
           держит вертикальный центр экрана. */
  --rs-sec-top: 96px;
  /* Отступ от заголовка до подзаголовка под ним — одинаковый для h1
           в шапке-герое и для h2 во всех восьми секциях. */
  --rs-head-gap: 24px;
  /* Отступ от подзаголовка до первого блока секции (карточек, списка,
           сетки) — тоже один на все секции. */
  --rs-sec-gap: 32px;
  --rs-ease: ease-out;
  --rs-t-base: 0.2s;
  /* Длительность появления блока при прокрутке. Долше --rs-t-base: блок
     въезжает снизу, и короткий переход читался бы как рывок. */
  --rs-t-reveal: 0.65s;
  /* Шаг лестницы появления: столько прибавляется к каждому следующему
     элементу в очереди. Один на всю страницу — сменишь здесь, сдвинется
     вся лестница, включая сдвинутую. */
  --rs-reveal-step: 90ms;
  /* Голубой неон — единственный токен старой неоновой оболочки, который
     до сих пор в работе: им подкрашены вкладки карусели кадров
     (.shots-tab). Остальные --rs-neon-* удалены как мёртвые: кнопки давно
     живут на --rs-btn-* ниже, а тёмные заливки, на которые ссылался
     комментарий про карусель и карточки Python, никто не использует. */
  --rs-neon-blue-glow: 0, 179, 255;

  /* ---------- Кнопки по макету (скрины 1–4) ----------

     Оранжевая: заливка #FF791A 80%, обводка #FFD67E, тень снаружи
     0 0 13px 3px #FF9C3A 80%, тень внутрь 0 0 10px 3px #FF772D 80%.
     Синяя: заливка #0092ED 86%, обводка #60F3FE, тень снаружи
     0 0 10px 3px #00D9FF 80%, тень внутрь 0 0 10px 3px #2DC7FF 80%.

     Заливки полупрозрачные — как в макете, сквозь них видно фон
     секции. Обводка и обе тени непрозрачные на 100% и 80%.

     Это отдельные токены, а не переопределение --rs-neon-blue-glow: он
     занят вкладками карусели кадров, и менять его вместе с кнопками
     нельзя.

     ВНИМАНИЕ, контраст: белый текст на #FF791A даёт ~2,6:1, а на
     смеси 80% оранжевого с тёмно-синим фоном секции — ~3,6:1. Для
     обычного текста нужно 4,5:1, поэтому на оранжевой кнопке белым
     по макету контраст не проходит WCAG AA. Раньше заливку затемняли
     до #8a3d04 специально ради этого, но тот токен давно удалён —
     если проверка важнее макета, возвращайте тёмную заливку. */
  --rs-btn-orange-fill: rgba(255, 121, 26, 0.8);
  --rs-btn-orange-fill-hover: rgba(255, 133, 44, 0.85);
  /* Светлый вариант — только для кнопки «Открыть игру» в финальном
     блоке. Там тёмная секция и самая крупная кнопка на странице, и на
     макетной заливке 80% она читалась вяло. Здесь светлее и плотнее. */
  --rs-btn-orange-fill-light: rgba(255, 143, 62, 0.94);
  --rs-btn-orange-fill-light-hover: rgba(255, 156, 82, 0.97);
  --rs-btn-orange-stroke: #ffd67e;
  --rs-btn-orange-drop: rgba(255, 156, 58, 0.8);
  --rs-btn-orange-inner: rgba(255, 119, 45, 0.8);
  --rs-btn-blue-fill: rgba(0, 146, 237, 0.86);
  --rs-btn-blue-fill-hover: rgba(0, 158, 249, 0.9);
  --rs-btn-blue-stroke: #60f3fe;
  --rs-btn-blue-drop: rgba(0, 217, 255, 0.8);
  --rs-btn-blue-inner: rgba(45, 199, 255, 0.8);

  /* Подложка «стеклянных» карточек: rgba(10,22,45,.72) поверх --rs-panel.

     Раньше жил только на .audience-window, где нужен был, чтобы фон
     полосы вкладок и фон карточки под ней совпали до пикселя — иначе на
     стыке виднелась линия. Теперь тем же материалом делаются и подвал,
     и .demo-card, поэтому токен вынесен в :root: иначе в футере он не
     разрешился бы и карточка осталась бы без подложки.

     Задаётся слоем, а не готовым цветом, и всегда поверх --rs-panel:
     при смене фона страницы поедет и стык, а не останется. */
  --rs-tab-surface:
    linear-gradient(rgba(10, 22, 45, 0.72), rgba(10, 22, 45, 0.72)),
    var(--rs-panel);

  /* Свечение букв на кнопках — отключено.

     Изначально здесь стоял белый слой с размытием 5px, а по макету
     и blur 9px на 50%. Ореол не давал эффекта: насыщенная заливка
     кнопки плюс подсветка букв читались как неоновая надпись поверх
     неоновой кнопки, и контур слов размывался. Свечение самой кнопки
     (её box-shadow и внешняя тень) осталось — буквы просто перестали
     светиться.

     Токен оставлен, а не удалён: значение повторялось в шести местах
     (.btn, .btn-primary, .btn-secondary, .shots-tab.is-active,
     .audience-btn.is-active:hover, .demo-card .btn-cta), и вернуть
     ореол теперь можно одной строкой. */
  --rs-btn-text-shadow: none;
}


/* ===================== Сброс и базовая типографика ===================== */

* {
  box-sizing: border-box;
}

/* Авторский display перебивает [hidden] из UA-стилей, из-за чего
       скрытые кнопки оставались видимыми. Возвращаем им display:none. */
[hidden] {
  display: none !important;
}

/* Текст только для скринридера: остаётся в дереве доступности, но не
   занимает места и не виден. Приём стандартный — не display:none (тогда
   исчезнет и из дерева доступности) и не visibility:hidden, а схлопывание
   в одну строку. Нужен там, где глазу показывать нечего, а слуху — да:
   сейчас это подпись «Модуль N» рядом с номером карточки Python. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: 90px;
}

body {
  margin: 0;
  font-family: var(--rs-font-body);
  font-size: 17px;
  line-height: 1.6;
  color: var(--rs-ink);
  /* Сплошная подложка: баннер и его затемнение живут в .bg-parallax ниже.
     Сама заливка необходима за слоем — сквозь полупрозрачные плашки и
     до первых кадров картинки пользователь обязан видеть ровный цвет,
     а не белый лист. */
  background-color: var(--rs-panel);
  -webkit-text-size-adjust: 100%;
}

/* Параллакс-фон всей страницы. Слой стоит position:fixed, а движение даёт
   transform в script.js: при прокрутке космос уезжает вверх медленнее
   контента. Раньше фон стоял на body с attachment:fixed — картинка не
   ехала вовсе; на мобильном Safari фиксированное вложение не работает и
   деградировало до прокрутки. С transform слоем параллакс есть и там.

   Высота = экран + --rs-bg-travel: слой выше окна ровно на бюджет сдвига,
   поэтому слой может уехать вверх максимум на сам бюджет — окно целиком
   останется закрытым при любом translate. Покой даёт transform: none:
   верхняя кромка картинки совпадает с верхней кромкой окна, и весь запас
   высоты лежит снизу — съедается поднимающимся верхом слоя по мере
   прокрутки. И состояние без JS, и состояние с prefers-reduced-motion
   — это та же центральная ось по горизонтали и верх по вертикали:
   одинаковый, предсказуемый вид вместо двух разных.

   Затемнение слоя — то же, что в герое (см. .hero): плотное слева под
   текстом, слабое справа. Градиент обязан лежать на этом же слое,
   поверх картинки: если оставить его на body, по порядку отрисовки
   он окажется под слоем и перестанет гасить космос. */
.bg-parallax {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: calc(100vh + var(--rs-bg-travel));
  z-index: -1;
  background:
          linear-gradient(100deg, rgba(5, 11, 25, 0.94) 16%, rgba(5, 11, 25, 0.72) 48%, rgba(5, 11, 25, 0.4) 100%),
          url("assets/img/bg/banner-2.jpg") center center / cover no-repeat;
  will-change: transform;
}

/* Растушёвка общего фото в сплошной синий на трёх блоках с мелким
   текстом: «Ваш ИИ-преподаватель», «Выбери, кто сейчас читает» и
   «Часто задаваемые вопросы». Обратная операция к #demo: там картинка
   проступает в середине блока, здесь наоборот — гасится середина, где
   мелкий текст, а по краям остаётся космос.

   Границы в px, а не в процентах: процент от высоты блока у блоков
   разной высоты давал бы то 20px, то 120px перехода.

   У #python и #try растушёвки нет вовсе — они прозрачные целиком, космос
   виден в них полностью (см. .section-light и .final).

   Длина перехода 96px — две ступени шкалы (--rs-sp-7 равен 48px). */
:root {
  --rs-fade: linear-gradient(180deg,
          transparent 0,
          var(--rs-panel-blue) calc(var(--rs-sp-7) * 2),
          var(--rs-panel-blue) calc(100% - var(--rs-sp-7) * 2),
          transparent 100%);
}

/* Растушёвка — слой ::before на трёх блоках с мелким текстом.

   Отступы секций (96/32) при этом не меняются: переход живёт отдельным
   слоем, а не фоном секции. Иначе симметричный переход по 96px не
   поместился бы в нижний отступ 32px, и пришлось бы дописать секции
   padding-bottom: 96px — тогда зазор после этих блоков стал бы 192px
   против 128px у остальных. */
#rita,
#for,
#faq {
  position: relative;
  isolation: isolate;
}

#rita::before,
#for::before,
#faq::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  /* Вылет вниз на 64px = разница между верхним (96px) и нижним (32px)
     отступом секции. Нужен, чтобы нижний переход был такой же длины,
     как верхний, и блок не читался срезанным снизу.

     64px уходят в верхний отступ СЛЕДУЮЩЕЙ секции (96px), поэтому до
     её текста слой не достаёт: снизу он гаснет до прозрачности, а до
     содержимого соседа остаётся 32px.

     Почему не height: 200%: такой слой уходил вниз на всю высоту
     секции и накрывал соседей вместе с их текстом. Вылет здесь
     ограничен 64px, а не высотой блока. */
  bottom: calc(-1 * (var(--rs-sp-7) * 2 - var(--rs-sp-6)));
  z-index: -1;
  pointer-events: none;
  /* Симметричные переходы по 96px — по две ступени шкалы с обеих сторон.
     Заливка — --rs-panel-blue (см. токен в :root), а не --rs-panel: блок
     должен быть темнее фона страницы, иначе растушёвка почти не читается. */
  background: linear-gradient(180deg,
          transparent 0,
          var(--rs-panel-blue) calc(var(--rs-sp-7) * 2),
          var(--rs-panel-blue) calc(100% - var(--rs-sp-7) * 2),
          transparent 100%);
}

/* Единственное место, где задаётся кегль заголовков: h1 — герой,
       h2 — все секции разом. Индивидуальные правила ниже трогают только
       цвет, отступы и трекинг, поэтому все восемь h2 одинаковые.

       Обнуление отступов здесь обязательно: у h2 в светлых секциях
       (они с классом .h-fancy, а не .h2) не было своего правила, и они
       оставались с браузерным отступом снизу 0.83em — на широком экране
       это 33.2px против нуля у тёмных секций. Из-за этого под одними
       заголовками текст стоял на 24px ближе, чем под другими. Теперь
       отступ под заголовком задаёт следующий за ним элемент, и он
       одинаковый у всех секций: var(--rs-head-gap). */
h1 {
  margin: 0;
  font-size: var(--rs-h1-size);
  line-height: var(--rs-h1-lh);
}

h2 {
  margin: 0;
  font-size: var(--rs-h2-size);
  line-height: var(--rs-h2-lh);
  letter-spacing: var(--rs-h2-ls);
}

/* h3 и h4 — заголовки внутри карточек (шаг урока, плишка Python, чек-лист,
       подпись награды, шапка полки). У них не было своего интерлиньяжа, и они
       наследовали от body 1.6 — из-за чего в одних карточках заголовок стоял
       на 4px выше ожидаемого, а в других на 4px ниже: лишний leading попадал
       именно в зазор до текста под заголовком, и этот зазор «плавал» от 0 до
       16px. Теперь у всех заголовков карточек один интерлиньяж, 1.2 — как у
       .audience-panel h3 и .python-card h3; у двух крупных заголовков
       (.journey-step h3, .final-panel h2) он плотнее, и они переопределяют
       значение своим правилом.

       Подпись награды и название модуля — h3, а не h4: секции над ними
       закрыты h2, и h4 после h2 перепрыгивал уровень. h4 остался только
       у шапок полок сортировки — там над ними h3 карточки, порядок верный. */
h3,
h4 {
  line-height: 1.2;
}

/* Кнопки в браузере не наследуют шрифт страницы: им в стилях по умолчанию
       прописан Arial, и переключатель кадров набирался чужой гарнитурой.
       Наследуем только family — размер, начертание и интерлиньяж у кнопок
       свои, их трогать нельзя. */
button,
input,
select,
textarea {
  font-family: inherit;
}

/* ---------- Скроллбар в стиле сайта ----------
       Тот же оранжевый, что у кнопок и у скроллбара в чате,
       чтобы ползунок не выглядел чужеродным элементом. */
::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

::-webkit-scrollbar-track {
  background: var(--rs-panel-soft);
  border-left: 1px solid rgba(255, 255, 255, 0.06);
}

::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #ffc46b 0%, var(--rs-cta) 45%, var(--rs-cta-hover) 100%);
  border: 2px solid var(--rs-panel);
  border-radius: 999px;
  box-shadow: 0 0 12px rgba(255, 176, 74, 0.45);
  transition: box-shadow 0.2s var(--rs-ease, ease-out);
}

::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, #ffd79a 0%, #ffbe63 45%, var(--rs-cta-hover) 100%);
  box-shadow: 0 0 20px rgba(255, 176, 74, 0.8);
}

/* Горизонтальный ползунок встречается редко, но пусть тоже будет в тон */
::-webkit-scrollbar-corner {
  background: var(--rs-panel);
}

@supports not selector(::-webkit-scrollbar) {
  /* Firefox не знает ::-webkit-scrollbar, там только стандартные свойства.
         Важно: задавать их безусловно нельзя — Chrome 121+ их тоже понимает
         и, согласно спецификации, отдаёт им предпочтение, из-за чего
         оформление выше (градиент, свечение, скругление) не применялось бы.
         Поэтому включаем стандартные свойства лишь там, где нет webkit-варианта. */
  html {
    scrollbar-width: thin;
    scrollbar-color: var(--rs-cta) var(--rs-panel-soft);
  }

}
img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

p {
  margin: 0;
}

ol,
ul {
  margin: 0;
  padding: 0;
}


/* ===================== Контейнер страницы ===================== */

.wrap {
  width: min(1180px, calc(100% - 32px));
  margin: 0 auto;
}


/* ===================== Шапка ===================== */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 80;
  padding: var(--rs-sp-3) 0;
  border-bottom: 1px solid transparent;
  /* background из перехода убран: подложка едет отдельным слоем .nav::before
     (см. ниже), и переходить тут больше нечему. backdrop-filter переехал
     туда же и тоже не анимируется — у none и у blur(14px) нет общей
     промежуточной формы. */
  transition: border-color .35s ease, padding .35s ease;
  background: transparent;
}

/* Подложка прокрученной шапки — отдельный слой, а не фон самой шапки.

   Почему не фон: --rs-tab-surface состоит из двух слоёв — rgba(10,22,45,.72)
   поверх --rs-panel. Переход по сокращённому background браузер разбирает на
   background-color и background-image и интерполирует их по-разному: цвет
   идёт от прозрачного к #1a2f84 плавно, а картинка переключается сразу. В
   итоге первую половину перехода шапка была полупрозрачно-синей поверх
   синей страницы — ровно тот старый оттенок, который мы и убирали. Особенно
   заметно, когда листаешь снизу вверх: класс .scrolled на 14px от верха
   снимается, и шапка полсекунды мигает старым цветом.

   Теперь материал лежит здесь и появляется через opacity: интерполируется
   только прозрачность, цвет в переходе не участвует — мигать нечему.

   z-index: -1 держит подложку ПОД логотипом, пунктами и кнопкой: ::before
   позиционирован, а позиционированные потомки рисуются поверх обычного
   текста родителя, и без минуса тёмная плашка закрыла бы шапку. Наружу она
   при этом не выходит, потому что .nav сам создаёт стек (position: fixed +
   z-index: 80).

   inset: 0 — по padding-боксу шапки, поэтому нижняя граница
   (border-bottom-color) остаётся поверх подложки, а не под ней.

   backdrop-filter оставлен: при непрозрачном фоне он сейчас ничего не
   делает, но если фон снова станет полупрозрачным, размытие под ним
   окажется к месту, и не придётся вспоминать, что его уже снимали. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--rs-tab-surface);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  opacity: 0;
  /* Подложка ничего не принимает: иначе она перехватывала бы клики по
     пунктам меню, пока ещё не проявилась. */
  pointer-events: none;
  transition: opacity .35s ease;
}

/* Прокрученная шапка — того же тёмного материала, что и карточка футера
   (--rs-tab-surface на .nav::before выше). Раньше здесь стоял
   var(--rs-panel) (#1a2f84), и на странице шапка читалась яркой синей
   полосой, которой больше нигде нет: подвал и все карточки лежат на
   --rs-tab-surface, а шапка выбивалась из ряда.

   Токен задаётся слоем поверх --rs-panel, поэтому при смене фона страницы
   поедет и шапка — ровно так же, как подвал. */
.nav.scrolled {
  border-bottom-color: var(--rs-line);
  padding: var(--rs-sp-2) 0;
}

.nav.scrolled::before {
  opacity: 1;
}

/* Шапка: 32px — это зазор между её тремя группами (логотип, пункты,
       кнопка), а 24px — между самими пунктами меню. Два соседних
       отступа держат иерархию: группа отстоит дальше, чем элемент внутри
       группы. Раньше здесь было 34px и 28px — оба вне шкалы. */
.nav .wrap {
  display: flex;
  align-items: center;
  gap: var(--rs-sp-6);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--rs-sp-3);
  flex: 0 0 auto;
  color: #fff;
}

.brand img {
  width: 36px;
  height: 36px;
  display: block;
  filter: drop-shadow(0 12px 26px rgba(69, 147, 255, 0.2));
  transition: width 0.35s ease, height 0.35s ease;
}

.nav.scrolled .brand img {
  width: 28px;
  height: 28px;
}

.brand-name {
  font-family: var(--rs-font-head);
  font-size: clamp(1.8rem, 2vw, 2.2rem);
  line-height: 1;
  letter-spacing: 0.02em;
  color: #fff;
}

.brand-name span {
  color: var(--rs-accent);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--rs-sp-5);
  margin-left: auto;
  /* nowrap, а не wrap: пунктам не хватало места на 921…1000px, и список
           рвался на два ряда — хедер становился вдвое выше. Сжимать список
           нельзя, поэтому в этом диапазоне отступы плотнее (ниже), а если
           места всё же не хватит, лучше переполнение, чем вторая строка. */
  flex-wrap: nowrap;
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--rs-sp-3);
  flex: none;
}

.nav-actions .btn {
  min-height: 44px;
}

/* Список пунктов — по центру шапки на десктопе.

   Раньше стоял только margin-left: auto, и пункты прижимались к кнопке
   справа. Авто-margin с двух сторон центрировал бы их лишь в остатке
   между логотипом и кнопкой: логотип шире кнопки примерно на 60px, и
   список уезжал влево от середины на половину этой разницы.

   Поэтому позиционируем абсолютно от центра .wrap. Wrap центрирован
   сам (width: min(1180px, 100% − 32px); margin: 0 auto), так что его
   середина совпадает с серединой экрана на всех десктопных ширинах.

   Только на десктопе: ниже 920px links становится выпадающим меню
   с собственным left/right (см. медиазапрос ниже), и это правило его
   перебивало бы. */
@media (min-width: 921px) {
  .nav .wrap {
    position: relative;
    /* Список ушёл из потока, и в flex остались только логотип и кнопка —
       без этого они сдвинулись бы влево вплотную друг к другу. */
    justify-content: space-between;
  }

  .nav-links {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: 0;
    transform: translate(-50%, -50%);
  }
}

.nav-links a {
  color: var(--rs-muted);
  font-weight: 600;
  font-size: 0.95rem;
  white-space: nowrap;
  transition: color .25s ease;
}

.nav-links a:hover {
  color: #fff;
}

/* Бургер: на десктопе скрыт, появляется в media-запросе ниже */
.nav-burger {
  display: none;
  width: 44px;
  height: 44px;
  margin-left: auto;
  /* прижимаем к правому краю, до кнопки */
  padding: 0;
  border: 1px solid var(--rs-line);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.04);
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* 5px — не ступень шкалы, а оптический отступ: полоски бургера почти
           смыкаются, и на ступень 4px или 8px значок разваливается. */
  gap: 5px;
  transition: background-color .25s ease, border-color .25s ease;
}

.nav-burger:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: var(--rs-accent);
}

.nav-burger span {
  display: block;
  width: 20px;
  height: 2px;
  border-radius: 2px;
  background: #fff;
  transition: transform .3s ease, opacity .2s ease;
}

/* Открытое состояние: три полоски складываются в крестик */
.nav-burger[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-burger[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.nav-burger[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.nav-burger:focus-visible {
  outline: 2px solid var(--rs-accent);
  outline-offset: 3px;
}

.btn:active {
  transform: translateY(1px);
}


/* ===================== Кастомный курсор ===================== */

/* ---------- Custom cursor (from 2nd landing) ---------- */
.cursor-dot,
.cursor-ring {
  display: none;
}

body.cursor-on .cursor-dot,
body.cursor-on .cursor-ring {
  display: block;
}

body.cursor-on,
body.cursor-on .chip,
body.cursor-on .shelf,
body.cursor-on a,
body.cursor-on button,
body.cursor-on select,
body.cursor-on summary {
  cursor: none;
}

body.cursor-on input,
body.cursor-on textarea {
  cursor: auto;
}

body.cursor-on.cursor-text .cursor-dot,
body.cursor-on.cursor-text .cursor-ring {
  opacity: 0;
}

.cursor-dot {
  position: fixed;
  left: 0;
  top: 0;
  opacity: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rs-accent);
  box-shadow: 0 0 12px var(--rs-accent);
  pointer-events: none;
  z-index: 500;
}

.cursor-ring {
  position: fixed;
  left: 0;
  top: 0;
  opacity: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 2px solid rgba(77, 208, 225, 0.65);
  pointer-events: none;
  z-index: 499;
  transition: width 0.22s ease-out, height 0.22s ease-out, border-color 0.22s ease-out, opacity 0.2s;
}

.cursor-ring.is-hover {
  width: 58px;
  height: 58px;
  border-color: var(--rs-cta);
}

.cursor-ring.is-down {
  width: 28px;
  height: 28px;
  border-color: #fff;
}

.cursor-fx {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 498;
}

.cursor-fx .ripple {
  position: fixed;
  border-radius: 50%;
  border: 2px solid var(--rs-accent);
  animation: ripple-out 0.5s ease-out forwards;
}

.cursor-fx .spark {
  position: fixed;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--c, var(--rs-accent));
  animation: spark-fly 0.55s ease-out forwards;
}


/* ===================== Первый экран ===================== */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  /* 140px сверху — не ступень шкалы: столько нужно, чтобы контент
           не залезал под липкую шапку. Снизу столько же, сколько у всех
           остальных секций: раньше здесь было 90px, и промежуток между
           героем и секцией «Как проходит урок» выходил 186px против 128px
           у всех остальных стыков. */
  padding: 140px 0 var(--rs-sp-6);
  overflow: hidden;
  /* Баннер героя — он в .bg-parallax, слое параллакса этой страницы, и его
     сдвиг согласован со скроллом в script.js, поэтому здесь картинки нет: в
     герое уехал бы второй слой того же баннера, и рамка секции читалась бы
     швом.

     Затемнение тоже не нужно своё — то самое, «как в герое», теперь лежит
     на body и уже накрывает всю страницу. Дублирующее линейное затемнение
     поверх складывалось с ним внахлёст: слева 0.94+0.94 давало 0.996, то
     есть чёрный, и космос в герое пропадал совсем.

     Остались радиальные подсветки по углам — они не затемняют, а добавляют
     глубину поверх уже положенного затемнения. */
  background:
          radial-gradient(circle at 15% 12%, rgba(93, 145, 255, 0.22), transparent 22%),
          radial-gradient(circle at 78% 18%, rgba(127, 108, 255, 0.22), transparent 28%);
}

.hero::after,
.hero::before {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
}

.hero::before {
  width: 440px;
  height: 440px;
  left: -150px;
  top: 100px;
  background: rgba(72, 238, 255, 0.12);
}

.hero::after {
  width: 520px;
  height: 520px;
  right: -170px;
  top: -30px;
  background: rgba(162, 74, 255, 0.12);
}

.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1.02fr;
  /* Разрыв между колонками героя — 32px, а не 48px, как у двухколоночных
           секций: справа не блок, а квадратная сцена 520px, и она центрируется
           в своей колонке, так что заявленный зазор и видимый воздух между
           текстом и планетой — разные числа. Ритм текста от этого не страдает. */
  gap: var(--rs-sp-6);
  align-items: center;
  min-height: 620px;
  /* Ширина — ровно как у .wrap (1180px и 32px полей). Здесь стояло
           1160px и 48px, из-за чего текст героя начинался на 8–10px правее,
           чем заголовки всех остальных секций: левая линия страницы рвалась
           на первом экране. */
  width: min(1180px, calc(100% - 32px));
  margin: 0 auto;
}

.hero-copy {
  max-width: 620px;
  position: relative;
  z-index: 2;
}

.hero h1 {
  margin: 0;
  font-family: var(--rs-font-head);
  /* кегль и интерлиньяж — из общих правил h1, здесь только трекинг */
  letter-spacing: 0.02em;
  color: #fff;
}

/* Градиент заголовка героя.

   Раньше он шёл от почти белого #f0d8ff к фиолетовому #d3b4ff, и на тёмно-синем
   фоне читался как блёклая серебристая надпись: белый оттенок первых
   ступеней съедал цвет, и розового в нём не было вовсе. Теперь это розовый →
   пурпурный: первые ступени ушли в насыщенный розовый (#ff5fb4, #ff5ccb),
   средние ведут через мадженту к фиолетовому, а конец оставлен
   сиренево-голубым, как был, — он связывает надпись с холодной палитрой
   страницы.

   Насыщенность и яркость держатся на одной паре HSL (L≈62%, S≈100%),
   меняется только тон: 330° → 315° → 300° → 288° → 275° → 250°. Поэтому
   переходы не дают «грязных» промежуточных оттенков, которых не бывает в
   самой палитре.

   Свечение переведено на тон между розовым и фиолетовым: при розовом
   начале градиента прежний холодный ореол rgba(163,129,255) выбивался бы
   из него и читался отдельным синим пятном. */
.hero h1 .grad {
  display: inline-block;
  background: linear-gradient(90deg,
    #ff5fb4 0%,
    #ff5ccb 18%,
    #ee5cea 35%,
    #b263ff 52%,
    #9166ff 67%,
    #8f86ff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 18px rgba(206, 93, 255, 0.34));
}

.lead {
  max-width: 58ch;
  /* Отступ от заголовка до подзаголовка. Раньше здесь стояло 22px —
           значение вне шкалы, и в светлых секциях у аналогичного отступа
           было 16px, а у заголовков в .h-fancy ещё и браузерные 33.2px.
           Теперь подзаголовок отстоит от заголовка одинаково везде. */
  margin-top: var(--rs-head-gap);
  color: var(--rs-muted);
  font-size: clamp(1.02rem, 1.55vw, 1.22rem);
  line-height: 1.6;
  text-shadow: 0 2px 20px rgba(3,5,14,.7);
}

/* Ряд кнопок в герое: 12px между кнопками (группа), 24px от
       подзаголовка сверху и 32px снизу — столько же, сколько от
       подзаголовка до первого блока в обычных секциях. */
.hero-actions {
  display: flex;
  gap: var(--rs-sp-3);
  flex-wrap: wrap;
  margin-top: var(--rs-head-gap);
  margin-bottom: var(--rs-sec-gap);
}

.hero-visual {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* сцена квадратная 520px — держим небольшой запас сверху и снизу */
  min-height: 560px;
  padding: var(--rs-sp-4) 0 var(--rs-sp-2);
}

/* Имитация космоса: планета в центре, две расходящиеся орбиты,
       звёздное поле и искры. Всё на процентах от квадратной сцены,
       поэтому масштабируется вместе с колонкой без ручных размеров. */
.hero-scene {
  position: relative;
  width: min(520px, 100%);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}

/* Далёкие звёзды: три слоя точек, каждый со своим периодом плитки —
       за счёт разных периодов точки не выглядят сеткой */
.hero-scene::after {
  content: "";
  position: absolute;
  inset: -12%;
  z-index: 0;
  pointer-events: none;
  background-image:
          radial-gradient(1.3px 1.3px at 20% 30%, rgba(255,255,255,.8), transparent 100%),
          radial-gradient(1px 1px at 72% 62%, rgba(255,255,255,.5), transparent 100%),
          radial-gradient(1.5px 1.5px at 44% 82%, rgba(255,255,255,.6), transparent 100%),
          radial-gradient(1px 1px at 88% 18%, rgba(180,225,255,.6), transparent 100%),
          radial-gradient(1.2px 1.2px at 8% 68%, rgba(255,255,255,.45), transparent 100%);
  background-size: 190px 190px, 137px 137px, 251px 251px, 173px 173px, 211px 211px;
  background-repeat: repeat;
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 55%, transparent 78%);
  mask-image: radial-gradient(circle at 50% 50%, #000 55%, transparent 78%);
}

/* Мягкое свечение за планетой */
.hero-scene::before {
  content: "";
  position: absolute;
  z-index: 0;
  width: 88%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 120, 225, 0.22), transparent 62%);
  filter: blur(14px);
  pointer-events: none;
}

/* Орбиты: пунктирные окружности, вращаются в разные стороны.
       Вращается рамка, а не круг, поэтому пунктир видно в движении. */
.hero-orbit {
  position: absolute;
  z-index: 0;
  border-radius: 50%;
  border: 1px dashed rgba(150, 200, 255, 0.22);
  pointer-events: none;
}

.hero-orbit--outer {
  inset: 0;
  animation: orbit-spin 90s linear infinite;
}

.hero-orbit--inner {
  inset: 11%;
  border-color: rgba(255, 170, 120, 0.18);
  animation: orbit-spin 60s linear infinite reverse;
}

/* Планета — центральный объект сцены. Это грид-элемент, а не
       абсолютно позиционированный: place-items центрирует его точно,
       и transform остаётся свободен под вращение. С inset и height:auto
       низ переопределялся бы, и планета уезжала бы вверх. */
.hero-planet {
  position: relative;
  z-index: 1;
  width: 70%;
  height: auto;
  opacity: .97;
  filter: drop-shadow(0 34px 80px rgba(255, 110, 220, 0.26));
  animation: planet-spin 200s linear infinite;
}

/* Ракета на третьей орбите.

   Вращается не ракета, а круг .hero-flight: он меньше сцены и центрирован,
   поэтому нос ракеты сам держится по касательной, а руками двигать его не
   нужно. Ракета стоит у верхнего края этого круга (top: 0), а её собственный
   поворот подбирает направление носа.

   Круг крутится против часовой стрелки (reverse). Обратить вращение нельзя
   «просто так»: контейнер разворачивает и положение ракеты, и её нос, так
   что нос автоматически развернулся бы НАЗАД по ходу движения. Ровно на это
   и сдвигает поворот на 180° — ракета продолжает лететь мордой вперёд,
   просто по орбите в другую сторону.

   Угол считается так: в исходнике нос смотрит на 211° от оси +x. После
   rotate(329deg) он смотрит на 211 + 329 = 540° ≡ 180°, то есть влево — так
   ракета летит в верхней точке орбиты, идя против часовой стрелки.

   Ракета центрируется НА линии орбиты через translate, а не прижатием
   верхнего края (top: 0). Разница в половину высоты ракеты — почти 110px:
   прижатая за верх она фактически летела вдвое ближе к планете и
   наполовину залезала на кольцо.

   Ширина 93% подобрана так, чтобы ракета читалась как спутник планеты и
   не задевала кольцо нигде по кругу. Ориентиры: у сцены нарисованы две
   пунктирные орбиты — внешняя 100% и внутренняя 78%; ракета летит между
   ними, ближе к внешней. Запас остался небольшой: 96% отодвигали совсем
   от планеты, 90% жалось к кольцу по бокам, где оно уходит шире всего.
   Ориентироваться стоит на эти две проверенные точки. */
.hero-flight {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 93%;
  aspect-ratio: 1;
  translate: -50% -50%;
  /* Выше всех: у звёзд свой стек (2 у .hero-star и 3 у .hero-twinkle), и
     ракета с тем же 2 стояла бы вровень с ними — при равенстве z-index
     решает порядок в разметке, а звёзды идут позже и ложились бы поверх.
     Теперь пролетающая ракета закрывает и звёзды, и искры. */
  z-index: 4;
  pointer-events: none;
  animation: orbit-spin 34s linear infinite reverse;
}

.hero-rocket {
  position: absolute;
  top: 0;
  left: 50%;
  /* Центрируем по обеим осям: ракета оказывается на линии орбиты, а не
     свешивается с неё. */
  translate: -50% -50%;
  transform: rotate(329deg);
  width: 40%;
  height: auto;
  filter: drop-shadow(0 0 16px rgba(255, 170, 60, 0.45));
}

/* Акцентные звёзды — крупные, медленно пульсируют */
.hero-star {
  position: absolute;
  z-index: 2;
  display: block;
  height: auto;
  pointer-events: none;
  filter: drop-shadow(0 0 18px rgba(255, 150, 70, 0.5));
  animation: twinkle 6.5s ease-in-out infinite;
}

.hero-star--1 {
  top: 9%;
  left: 12%;
  width: 7%;
}

.hero-star--2 {
  right: 14%;
  bottom: 12%;
  width: 5%;
  animation: twinkle 8.5s ease-in-out 1.2s infinite;
}

/* Искры: одна картинка в семи размерах и с разными задержками,
      чтобы поле не пульсировало синхронно */
.hero-twinkle {
  position: absolute;
  z-index: 3;
  display: block;
  pointer-events: none;
}

.hero-twinkle img {
  display: block;
  width: 100%;
  height: auto;
}

.hero-twinkle--1 {
  top: 4%;
  left: 32%;
  width: 6.5%;
  animation: twinkle 3.6s ease-in-out infinite;
}

.hero-twinkle--2 {
  top: 26%;
  right: 5%;
  width: 4.5%;
  animation: twinkle 4.8s ease-in-out .9s infinite;
}

.hero-twinkle--3 {
  top: 46%;
  left: 3%;
  width: 3.4%;
  animation: twinkle 5.4s ease-in-out 1.7s infinite;
}

.hero-twinkle--4 {
  bottom: 30%;
  right: 2%;
  width: 5.2%;
  animation: twinkle 4.1s ease-in-out .4s infinite;
}

.hero-twinkle--5 {
  bottom: 7%;
  left: 24%;
  width: 3.8%;
  animation: twinkle 6.1s ease-in-out 2.3s infinite;
}

.hero-twinkle--6 {
  top: 16%;
  right: 26%;
  width: 3%;
  animation: twinkle 5.7s ease-in-out 3.1s infinite;
}

.hero-twinkle--7 {
  bottom: 44%;
  left: 15%;
  width: 4.2%;
  animation: twinkle 4.4s ease-in-out 1.1s infinite;
}

.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: 26px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--rs-sp-3);
  color: rgba(208, 230, 255, 0.75);
  font-size: .72rem;
  letter-spacing: .28em;
  text-transform: uppercase;
}

.scroll-hint i {
  width: 1px;
  height: 44px;
  background: linear-gradient(#fff, transparent);
  display: block;
  overflow: hidden;
  position: relative;
}

.scroll-hint i::after {
  content: "";
  position: absolute;
  left: 0;
  top: -50%;
  width: 1px;
  height: 50%;
  background: var(--rs-cta);
  animation: drip 2.2s ease-in-out infinite;
}


/* ===================== Цифры ===================== */

/* Блок цифр — плашка на общем фоне: у него свой полупрозрачный тёмный
   фон, а не растушёвка. Растушёвка здесь давала бы две серых полосы
   поперёк блока — фон блока и без них отделяет его от соседей. */
.stats {
  border-top: 1px solid var(--rs-line);
  border-bottom: 1px solid var(--rs-line);
  background: rgba(7, 10, 26, 0.58);
}

.stats .wrap {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
}

.stat {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--rs-sp-3);
  min-height: 122px;
  padding: var(--rs-sp-4);
  border-right: 1px solid var(--rs-line);
  text-align: center;
}

.stat:last-child {
  border-right: none;
}

.stat b {
  font-family: var(--rs-font-head);
  font-size: clamp(2rem, 3vw, 3.2rem);
  line-height: 1;
  color: #fff;
  letter-spacing: .02em;
}

.stat span {
  max-width: 290px;
  color: var(--rs-pale);
  font-weight: 700;
  font-size: .92rem;
  line-height: 1.45;
}

/* Отступы секции: 96px сверху (две ступени sp-7) и 32px снизу.
       Вместе со ступенью снизу соседней секции это даёт одинаковые
       128px между секциями — одинаково для всех девяти секций и футера.

       Фона у секции нет: общий баннер на body виден сквозь неё сам,
       и гасить его растушёвкой здесь не нужно — растушёвка стоит
       только на блоках с мелким текстом (см. --rs-fade). */
.sec {
  padding: var(--rs-sec-top) 0 var(--rs-sp-6);
}

.sec-head {
  /* Отступ от подзаголовка до первого блока секции (сетки карточек,
           списка, плашек). Раньше здесь стояло 28px — на ступень шкалы
           не попадало и отличалось от аналогичного отступа в светлых
           секциях. */
  margin-bottom: var(--rs-sec-gap);
  max-width: 760px;
}

.h2 {
  margin: 0;
  font-family: var(--rs-font-head);
  /* кегль и интерлиньяж — из общего правила h2: у всех секций он один */
  color: #fff;
}


/* ===================== Как проходит урок: 4 шага ===================== */

.journey-wrap {
  position: relative;
  /* Отступ сверху задаёт .sec-head (var(--rs-sec-gap)); раньше тут ещё
           стояло 22px поверх него — лишнее значение вне шкалы. */
  margin-top: 0;
  /* Отступ (а не margin) — иначе он схлопнется с внешним и уведёт линию вниз.
           top у ::before = padding-top − 27.5, чтобы линия и кружки совпали.

           64px вместо прежних 100px. Столько нужно, чтобы в кружок с
           номером (52px) влечь зазор: он стоит над карточкой, и линия
           проходит через его центр. Лишние 36px были не нужны никому и
           давали зазор от подзаголовка до карточек 132px — почти столько
           же, сколько от блока цифр до заголовка (137px). Из-за этого
           секция читалась как два равных по воздуху промежутка, хотя
           один отделяет блоки, а другой — текст от его содержимого.

           Теперь от подзаголовка до карточек 96px, и зазор внутри секции
           визуально меньше межсекционного. */
  padding-top: 64px;
}

/* Прерывистая линия: центр линии = центр кружка (52px / 2 = 26px) */
.journey-wrap::before {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  /* top = padding-top − 27.5 → центр линии (top + 1.5) = центр кружка (26px) */
  top: 36.5px;
  height: 3px;
  z-index: 0;
  background: repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.55) 0 10px, transparent 10px 18px);
}

.journey-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--rs-sp-5);
  align-items: stretch;
}

.journey-step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--rs-sp-4);
  padding: var(--rs-sp-5);
  border-radius: 24px;
  /* Синяя плашка вместо тёмной рамки: светлый кант, градиент вглубь,
           верхняя кромка бликом и мягкая синяя тень */
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: linear-gradient(180deg, #2f9bea 0%, #1873c6 55%, #0c56a2 100%);
  box-shadow:
          0 24px 48px rgba(8, 52, 96, 0.55),
          inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

/* Белые «скобки» по центру верхнего и нижнего края плашки.
       Форма — трапеция со скруглёнными углами; сама фигура вынесена
       в переменную --rs-clip, чтобы её можно было ставить на другие блоки. */
.journey-step::after,
.journey-step::before {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: var(--rs-clip);
}

.journey-step::before {
  top: -8px;
  /* выходит на 8px вверх */
  width: 164px;
  height: 24px;
}

.journey-step::after {
  bottom: -8px;
  /* выходит на 8px вниз */
  width: 92px;
  height: 16px;
  transform: translateX(-50%) scaleY(-1);
  /* переворачиваем */
}

/* Кружок с номером — над карточкой, ровно по центру на линии */
.step-number {
  position: absolute;
  top: -52px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  /* Тот же приём, что у .quiz-num: line-height: 1 убирает полуинтерлиньяж
           от body (1.6), из-за которого цифра в кружке садилась ниже
           середины. Разбор и замеры — у .quiz-num, правило одно на оба
           кружка с номерами. */
  line-height: 1;
  border-radius: 50%;
  color: #ffffff;
  font-family: var(--rs-font-head);
  font-size: 1.15rem;
  font-weight: 700;
  /* тот же синий, что у плашки */
  background: linear-gradient(180deg, #2f9bea 0%, #1873c6 55%, #0c56a2 100%);
  border: 5px solid #ffffff;
  box-shadow: 0 12px 28px rgba(24, 115, 198, 0.5);
}

/* Картинки во весь свой размер, без обрезки */
.journey-step img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  border-radius: 18px;
  border: none;
}

.journey-step h3 {
  margin: 0;
  font-family: var(--rs-font-head);
  font-size: clamp(1.55rem, 1.9vw, 2rem);
  line-height: 1.05;
  color: #fff;
  text-shadow: 0 2px 12px rgba(3, 34, 66, 0.5);
}

.journey-step p {
  flex: 1;
  margin: 0;
  color: #dcefff;
  font-size: 0.96rem;
  line-height: 1.6;
}

.rita-grid {
  display: grid;
  grid-template-columns: 1fr 1.08fr;
  /* Две колонки с текстом и картинкой: разрыв «течёт» вместе с
           шириной экрана, но держится на ступенях шкалы — 32px на узких
           экранах и 48px на широких. Раньше верхняя граница была 56px,
           значение вне шкалы. */
  gap: clamp(var(--rs-sp-6), 4vw, var(--rs-sp-7));
  align-items: start;
}

.rita-copy .lead code {
  font-family: var(--rs-font-body);
  font-size: 0.9em;
  background: rgba(255, 179, 92, 0.08);
  border: 1px solid rgba(255, 179, 92, 0.3);
  color: #ffd9a0;
  /* Как у .bubble code: 1px/7px — микро-отступ «кода» внутри строки,
           7px вместо 8px компенсирует рамку в 1px. */
  padding: 1px 7px;
  border-radius: 6px;
}

.blist {
  list-style: none;
  /* Отступ от текста секции до списка — тот же, что у .sec-head */
  margin: var(--rs-sec-gap) 0 0;
  padding: 0;
  display: grid;
  /* Список пунктов внутри одной секции: ступень 12px, как у
           .check-list и .faq-grid. */
  gap: var(--rs-sp-3);
}

.blist li {
  display: flex;
  gap: var(--rs-sp-3);
  /* Значок по центру строки, а не по её верху: текст пункта — от одной до
     трёх строк, и при flex-start галочка всегда жалась к верхней кромке
     первой строки. По центру она встаёт в середину всего блока. */
  align-items: center;
  padding: var(--rs-sp-3) var(--rs-sp-4);
  border-radius: 16px;
  /* Граница и заливка подняты: пункт должен читаться отдельной карточкой.
     Прежние 7% и 2% белого подобраны под почти чёрный фон, а теперь за
     списком синяя заливка --rs-panel, и на ней пункт с такой рамкой
     сливался с секцией — контур терялся целиком. */
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.07);
  color: var(--rs-ink);
  font-size: 1rem;
  line-height: 1.55;
}

.blist svg {
  width: 20px;
  height: 20px;
  /* Смещения нет: прежде здесь было margin-top: 2px — оптическая правка
     под align-items: flex-start, значок приподнимался к cap-height первой
     строки. При align-items: center такая правка только сбивала бы его. */
  color: var(--rs-accent);
  flex: 0 0 auto;
}

.chat {
  position: relative;
  padding: 0;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(13, 58, 92, 0.14);
  box-shadow: 0 30px 60px rgba(3, 5, 17, 0.28);
  overflow: hidden;
}

.chat::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 20% 0%, rgba(255, 176, 74, 0.1), transparent 38%);
  pointer-events: none;
}

.chat-hd {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--rs-sp-3);
  padding: var(--rs-sp-3) var(--rs-sp-4);
  border-bottom: 1px solid rgba(13, 58, 92, 0.1);
  background: rgba(13, 58, 92, 0.03);
}

.ava {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--rs-cta);
  border: 2px solid var(--rs-cta);
}

.ava img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.who {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.who b {
  color: var(--rs-paper-ink);
  font-size: 0.94rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.who i {
  color: var(--rs-paper-muted);
  font-style: normal;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: lowercase;
}

.replay svg {
  width: 18px;
  height: 18px;
}

.chat-body {
  position: relative;
  z-index: 1;
  height: min(520px, 58vh);
  overflow-y: auto;
  padding: var(--rs-sp-4);
  display: flex;
  flex-direction: column;
  /* Реплики подряд — это «список», поэтому ступень 12px, как у
           .blist и .check-list. */
  gap: var(--rs-sp-3);
  background: var(--rs-paper);
}

@supports not selector(::-webkit-scrollbar) {
  /* Оранжевый скроллбар в чате — тот же, что у страницы, но на светлой
         подложке диалога: тёмная обводка ползунка заменена на оранжевую, иначе
         он читался чужеродным. Стандартные свойства — только для Firefox,
         см. комментарий у общего скроллбара: Chrome 121+ отдал бы им
         предпочтение и потерял скругление. */
  .chat-body {
    scrollbar-width: thin;
    scrollbar-color: var(--rs-cta) rgba(255, 176, 74, 0.16);
  }

}
.chat-body::-webkit-scrollbar {
  width: 12px;
}

.chat-body::-webkit-scrollbar-track {
  background: rgba(255, 176, 74, 0.16);
  border-radius: 999px;
}

.chat-body::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, #ffc46b 0%, var(--rs-cta) 45%, var(--rs-cta-hover) 100%);
  border: 2px solid var(--rs-paper);
  border-radius: 999px;
  box-shadow: 0 0 12px rgba(255, 176, 74, 0.45);
  transition: box-shadow 0.2s var(--rs-ease, ease-out);
}

.chat-body::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, #ffd79a 0%, #ffbe63 45%, var(--rs-cta-hover) 100%);
  box-shadow: 0 0 20px rgba(255, 176, 74, 0.8);
}

/* ---------- Диалог: светлые «облака» по макету ---------- */
.msg {
  display: flex;
  align-items: flex-end;
  /* аватар снизу, как на макете */
  gap: var(--rs-sp-3);
  max-width: 92%;
  animation: bpop .4s cubic-bezier(.2,.7,.3,1.3) both;
}

.msg.a {
  align-self: flex-start;
}

.msg.s {
  align-self: flex-end;
  flex-direction: row-reverse;
}

/* Аватар: круг в оранжевой обводке (брендовый цвет) */
.bav {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  overflow: hidden;
  flex: none;
  background: var(--rs-cta);
  border: 2px solid var(--rs-cta);
}

.bav img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.bubble {
  position: relative;
  border-radius: 20px;
  padding: var(--rs-sp-4) var(--rs-sp-5);
  font-size: 1.02rem;
  line-height: 1.4;
  /* Реплики читаются как высказывание, а не как абзац инструкции,
           поэтому текст жирный. Рамки нет: форму держат скругление и тень. */
  font-weight: 700;
  color: var(--rs-chat-ink);
  background: var(--rs-chat-rita);
  box-shadow: 0 10px 24px rgba(11, 27, 51, 0.1);
}

.msg.a .bubble {
  background: var(--rs-chat-rita);
  color: var(--rs-chat-ink);
  border-bottom-left-radius: 8px;
  /* «хвостик» в сторону аватара */
}

.msg.s .bubble {
  background: var(--rs-chat-user);
  color: var(--rs-chat-ink);
  border-bottom-right-radius: 8px;
  max-width: 82%;
}

.bubble code {
  font-family: var(--rs-font-body);
  font-size: .92em;
  background: rgba(255, 255, 255, .6);
  border: 1px solid rgba(13, 58, 92, .16);
  color: #0a2f4d;
  /* 1px по вертикали и 7px по горизонтали — не ступени шкалы: это
           «код» внутри строки, у него нужен минимальный отступ, и 7px вместо
           8px компенсируют рамку в 1px, чтобы текст не прилипал к ней. */
  padding: 1px 7px;
  border-radius: 7px;
  white-space: nowrap;
}

.msg.dots .bubble {
  display: flex;
  align-items: center;
  /* Три точки — не элемент списка, их зазор не должен попадать на
           ступень шкалы: на 4px они слипаются, на 8px расползаются. */
  gap: 5px;
  padding: var(--rs-sp-4) var(--rs-sp-5);
}

.msg.dots .bubble span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--rs-chat-ink);
  animation: blink 1s ease-in-out infinite;
}

.msg.dots .bubble span:nth-child(2) {
  animation-delay: .18s;
}

.msg.dots .bubble span:nth-child(3) {
  animation-delay: .36s;
}

/* Пометки-ремарки: компактный «чип» с оранжевой точкой */
.anno {
  align-self: flex-start;
  /* не растягиваем на всю ширину колонки */
  display: inline-flex;
  align-items: center;
  gap: var(--rs-sp-2);
  max-width: 100%;
  margin: 0;
  /* 5px по вертикали и 10px слева — не ступени шкалы: чип-ремарка
           должен быть ниже своих соседей по высоте, а точка внутри него
           — ровно на расстоянии 8px от левого края текста. */
  padding: 5px 13px 5px 10px;
  border-radius: 999px;
  background: rgba(255, 176, 74, 0.1);
  border: 1px solid rgba(245, 158, 11, 0.28);
  color: #92600c;
  font-size: 0.79rem;
  letter-spacing: 0.01em;
  line-height: 1.35;
  text-transform: none;
}

.anno i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
  flex: none;
  background: var(--rs-cta);
  box-shadow: 0 0 0 3px rgba(255, 176, 74, 0.28);
}

/* Блок с примером кода — светлая карточка с тёмным полем кода */
.ldemo {
  max-width: 100%;
  display: block;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(13, 58, 92, 0.12);
  padding: var(--rs-sp-3);
  box-shadow: 0 10px 24px rgba(11, 27, 51, 0.08);
}

/* Внутри демо-карточки три строки (заголовок, поле кода, ячейки
       переменных) идут с одинаковым зазором 8px — это ступень для групп
       внутри одного блока. Раньше между ними стояло по 9px. */
.lhd {
  display: flex;
  align-items: center;
  gap: var(--rs-sp-2);
  margin-bottom: var(--rs-sp-2);
  color: #b45309;
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.lhd .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rs-cta);
  box-shadow: 0 0 0 4px rgba(255, 176, 74, 0.22);
  animation: blink 1s ease-in-out infinite;
}

.lcode {
  display: block;
  /* Раньше здесь был стек ui-monospace/Consolas/monospace — третий шрифт,
           которого нет в assets/fonts. Код набран основной гарнитурой OpenRunde:
           отступы и структура читаются, а набор шрифтов на сайте остаётся
           из двух. */
  font-family: var(--rs-font-body);
  font-size: 0.9rem;
  color: #dbeafe;
  background: var(--rs-paper-ink);
  border-radius: 10px;
  padding: var(--rs-sp-2) var(--rs-sp-3);
  margin-bottom: var(--rs-sp-2);
}

.lslots {
  display: flex;
  gap: var(--rs-sp-2);
  margin-bottom: var(--rs-sp-2);
}

.slot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #eef3f9;
  border: 1px solid rgba(13, 58, 92, 0.12);
  transition: all .2s ease;
}

.slot i {
  font-style: normal;
  color: rgba(13, 58, 92, 0.38);
  font-family: var(--rs-font-body);
  font-size: 0.62rem;
}

.slot.on {
  background: var(--rs-cta);
  border-color: var(--rs-cta-hover);
  box-shadow: 0 0 0 4px rgba(255, 176, 74, 0.24);
}

.slot.on i {
  color: #2a1503;
}

.lst {
  color: var(--rs-paper-muted);
  font-size: 0.8rem;
}

@media (min-width: 921px) and (max-width: 1180px) {
  /* Промежуточная ширина: бургер ещё не нужен, но в базовых отступах
         (32px между блоками и 24px между пунктами) список не помещался в
         одну строку и переносился. Ужимаем отступы и кегль названия — на
         1180px+ места и так хватает, там действуют базовые значения. */
  .nav .wrap {
    gap: var(--rs-sp-4);
  }

  .nav-links {
    gap: var(--rs-sp-2);
    position: static;
    transform: none;
    margin: 0 auto;
  }

  .nav .nav-actions .btn {
    font-size: 0.875rem;
    padding: var(--rs-sp-3);
  }

  .nav-links a {
    font-size: 0.9rem;
  }

  .brand-name {
    font-size: 1.55rem;
  }

}
@media (max-width: 920px) {
  .nav .wrap {
    gap: var(--rs-sp-3);
  }

  /* Действия остаются рядом; бургер завершает строку шапки. */
  .nav-actions {
    order: 1;
    margin-left: auto;
  }

  .nav .nav-actions .btn {
    font-size: 0.875rem;
    padding: var(--rs-sp-3);
  }

  /* Бургер вместо горизонтальных ссылок */
  .nav-burger {
    display: flex;
    order: 2;
    margin-left: 0;
    /* базовое правило прижимало его вправо */
    /* Кнопку 44×44 нельзя сжимать: в тесноте шапки Flex отдавал
               недостающие 22px именно бургеру, и он превращался в две узкие
               полоски, высунутые за правый край экрана. */
    flex: none;
  }

  /* Логотип на узком экране уменьшается: «RedoSchool» в базовых
           1.8rem занимает 210px, и вместе с кнопкой и бургером шапка
           перестаёт помещаться в экран. */
  .brand-name {
    font-size: 1.5rem;
  }

  .nav-links {
    position: absolute;
    top: 100%;
    left: 16px;
    right: 16px;
    margin-left: 0;
    flex-direction: column;
    align-items: stretch;
    /* В раскрытом меню пункты идут вплотную друг к другу: каждый пункт —
               это строка во всю ширину панели, а зазор в 2px только отделяет
               подсветку при наведении. Это оптический отступ, не ступень шкалы. */
    gap: 2px;
    padding: var(--rs-sp-2);
    border-radius: 18px;
    border: 1px solid var(--rs-line);
    background: rgba(6, 9, 20, 0.97);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    box-shadow: 0 24px 50px rgba(0, 0, 0, 0.45);
    display: none;
    /* закрыто по умолчанию */
  }

  .nav.is-open .nav-links {
    display: flex;
    animation: nav-drop .25s ease-out;
  }

  .nav-links a {
    padding: var(--rs-sp-3) var(--rs-sp-4);
    border-radius: 12px;
    font-size: 1rem;
  }

  .nav-links a:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.06);
  }

  .hero-grid {
    grid-template-columns: 1fr;
  }

  .hero-copy {
    max-width: 100%;
  }

  .hero-visual {
    min-height: 440px;
  }

  /* Сцена квадратная и целиком в процентах, поэтому на узких экранах
           планета, орбиты и звёзды просто уменьшаются пропорционально —
           подгонять их вручную не нужно. */
  .journey-grid,
  .stats .wrap {
    grid-template-columns: 1fr 1fr;
  }

  /* В сетке из двух колонок третья цифра переносится на вторую строку, и
     одна ячейка в углу читалась сломанной — особенно из-за вертикальных
     перегородок: одна висела в конце первой строки без пары, а третья
     цифра стояла слева, наравне с колонками, а не по центру.

     Поэтому третья занимает строку целиком и отделяется сверху той же
     линией, какой соседние колонки разведены по вертикали, — направление
     просто меняется, материал остаётся тот же. */
  .stat:nth-child(2) {
    /* он последний в первой строке — перегородка справа была бы висячей */
    border-right: none;
  }

  .stat:last-child {
    grid-column: 1 / -1;
    border-right: none;
    border-top: 1px solid var(--rs-line);
  }

  /* Ниже 4 колонок линия не нужна — номера переносятся внутрь карточек */
  .journey-wrap::before {
    display: none;
  }

  .journey-wrap {
    padding-top: 0;
  }

  .step-number {
    position: static;
    transform: none;
    margin: 0 auto;
  }

  .rita-grid {
    grid-template-columns: 1fr;
  }

}

/* ---------- Адаптив: телефон ---------- */

@media (max-width: 640px) {
  html {
    scroll-padding-top: 128px;
  }

  .nav {
    /* На телефоне шапка всегда «прижатая» — как в состоянии .scrolled */
    padding: var(--rs-sp-2) 0;
  }

  .nav .wrap {
    flex-wrap: wrap;
    row-gap: var(--rs-sp-2);
  }

  .brand-name {
    font-size: clamp(1.15rem, 6vw, 1.5rem);
  }

  .nav .nav-actions .btn {
    font-size: clamp(0.75rem, 3.5vw, 0.875rem);
  }

  /* Обе кнопки доступны без раскрытия меню и не теснят логотип с бургером. */
  .nav-actions {
    order: 2;
    flex-basis: 100%;
    gap: var(--rs-sp-2);
  }

  .nav-actions .btn-primary {
    flex: 1;
  }

  .nav-burger {
    order: 1;
    margin-left: auto;
  }

  .hero {
    min-height: 700px;
  }

  .hero-actions {
    flex-direction: column;
    align-items: stretch;
  }

  .hero-actions .btn {
    width: 100%;
  }

  .journey-grid,
  .stats .wrap {
    grid-template-columns: 1fr;
  }

  .stat {
    border-right: none;
    border-bottom: 1px solid var(--rs-line);
  }

  .stat:last-child {
    border-bottom: none;
    /* Сбрасываем верхнюю линию, заданную в правиле для сетки из двух
       колонок: ниже 640px цифры стоят в одну колонку и разведены линиями
       снизу, а снизу и сверху одновременно линия была бы вдвое толще. */
    border-top: none;
  }

  .scroll-hint {
    bottom: 10px;
    font-size: 0.64rem;
  }

}
/* Правила для узкого экрана у вкладок лежат не здесь, а вместе с базой
   .audience-btn ниже: @media не добавляет специфичности, и перенесённое
   сюда правило проигрывало бы более поздней базе. */

/* ===================== Демо-секция: подложка и градиенты ===================== */

/* Растушёвка общего фото в сплошной синий — только на трёх блоках с
   мелким текстом: «Ваш ИИ-преподаватель», «Выбери, кто сейчас читает»
   и «Часто задаваемые вопросы». Внутри каждого блока картинки нет вовсе,
   космос остаётся только на верхнем и нижнем отступах.

   Обратная операция к #demo: там ::after гасит края и картинка проступает
   в середине, здесь гасится середина с текстом.

   Границы в px, а не в процентах: процент от высоты блока у блоков разной
   высоты давал бы то 20px, то 120px перехода. 96px — высота отступа секции,
   то есть растушёвка целиком ложится на пустую часть и текст всегда стоит
   на сплошном фоне.

   Селекторы по id, а не по классу: у #for и #faq есть .section-light со
   своим сплошным фоном, и он перебил бы общий класс по порядку. */
#rita,
#for,
#faq {
  background: var(--rs-fade);
}

/* #demo больше не рисует ничего: фона у секции нет, ::before с nebula и
   ::after с растушёвкой убраны. Раньше это был единственный блок с
   собственным изображением поверх общего фона — из-за него стыки сверху
   и снизу читались иначе, чем у остальных секций.

   Правило-обёртка осталось: isolation и z-index:-1 у соседних слоёв
   больше не нужны, но .chat внутри #demo объявлен position: relative и
   должен лежать поверх общего фона body — это и обеспечивает isolate. */
#demo {
  position: relative;
  isolation: isolate;
}

/* ---------------------------------------------------------------------------
   Тень «последней карточки» секции не должна обрезаться фоном следующей.
   Между секциями .sec всего 32px, а крупные тени (размытие 50-60px) вылезают
   за эти 32px на верх следующей секции. Когда у следующей секции был
   непрозрачный верх, тень там резко обрывалась горизонтальной чертой.

   Обе карточки уже объявлены position: relative, поэтому z-index работает:
   тень рисуется после подложки следующей секции и просто мягко ложится на её
   пустой верхний отступ, без обрыва.
   --------------------------------------------------------------------------- */
.chat,
.audience-panel {
  z-index: 2;
}


/* ===================== Кнопки: база (здесь) + неоновая оболочка (ниже, бывший внешний файл) ===================== */

/* Buttons — layout/base only. Neon skin (glow, colors) lives in styles.css */
/* --- База: белый текст с неоновым свечением --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  min-height: 48px;
  padding: var(--rs-sp-3) var(--rs-sp-5);
  border-radius: 14px;
  border: 2px solid transparent;
  font-family: var(--rs-font-head);
  font-size: 1rem;
  font-weight: 900;
  letter-spacing: 0.02em;
  cursor: pointer;
  text-decoration: none;
  transition: background-color .3s ease, border-color .3s ease,
          box-shadow .3s ease, text-shadow .3s ease, transform .12s ease-out;
  color: #fff;
  text-shadow: var(--rs-btn-text-shadow);
}


/* ===================== Неоновая оболочка кнопок, вкладок и переключателей ===================== */

/* --- Главная кнопка (оранжевая, по макету) --- */
.btn-primary {
  background-color: var(--rs-btn-orange-fill);
  color: #fff;
  border-color: var(--rs-btn-orange-stroke);
  box-shadow: 0 0 13px 3px var(--rs-btn-orange-drop),
      inset 0 0 10px 3px var(--rs-btn-orange-inner);
  text-shadow: var(--rs-btn-text-shadow);
}

.btn-primary:hover {
  background-color: var(--rs-btn-orange-fill-hover);
  color: #fff;
  transform: translateY(-2px);
  box-shadow: 0 0 20px 3px var(--rs-btn-orange-drop),
      inset 0 0 14px 3px var(--rs-btn-orange-inner);
}

/* --- Второстепенная кнопка (синяя, по макету) --- */
.btn-secondary {
  background-color: var(--rs-btn-blue-fill);
  color: #fff;
  border-color: var(--rs-btn-blue-stroke);
  box-shadow: 0 0 10px 3px var(--rs-btn-blue-drop),
      inset 0 0 10px 3px var(--rs-btn-blue-inner);
  text-shadow: var(--rs-btn-text-shadow);
}

.btn-secondary:hover {
  background-color: var(--rs-btn-blue-fill-hover);
  color: #fff;
  transform: translateY(-2px);
  box-shadow: 0 0 17px 3px var(--rs-btn-blue-drop),
      inset 0 0 14px 3px var(--rs-btn-blue-inner);
}

/* Крупная кнопка — та же оболочка, чуть раздутая: площадь больше,
   и без усиления свечение на ней теряется. */
.btn-big, .btn-big.btn-secondary{
  box-shadow: 0 0 16px 3px var(--rs-btn-blue-drop),
      inset 0 0 13px 3px var(--rs-btn-blue-inner);
}

.btn-big:hover {
  box-shadow: 0 0 26px 3px var(--rs-btn-orange-drop),
      inset 0 0 18px 3px var(--rs-btn-orange-inner);
}

.btn-big:hover, .btn-big.btn-secondary:hover{
  box-shadow: 0 0 24px 3px var(--rs-btn-blue-drop),
      inset 0 0 18px 3px var(--rs-btn-blue-inner);
}

/* Вкладки карусели («Модули», «Уроки», «Код-станция») — тот же синий
   неон по макету, что у .btn-secondary: заливка 0092ED 86%, обводка
   60F3FE, тень снаружи 0 0 10px 3px 00D9FF 80%, тень внутрь
   0 0 10px 3px 2DC7FF 80%. */
.shots-tab:hover {
  border-color: var(--rs-btn-blue-stroke);
  color: #fff;
  box-shadow: 0 0 14px 3px var(--rs-btn-blue-drop),
      inset 0 0 10px 3px var(--rs-btn-blue-inner);
}

.shots-tab.is-active {
  background-color: var(--rs-btn-blue-fill);
  border-color: var(--rs-btn-blue-stroke);
  color: #fff;
  box-shadow: 0 0 10px 3px var(--rs-btn-blue-drop),
      inset 0 0 10px 3px var(--rs-btn-blue-inner);
  text-shadow: var(--rs-btn-text-shadow);
}

/* Вкладка под курсором — как в браузере: без сдвига, вкладка всплывает из
   затемнения к цвету текста и подсвечивается изнутри. Подъём на 2px здесь
   ломал бы стык с карточкой у активной и строй полосы у остальных. */
.audience-btn:hover {
  background-color: rgba(0, 0, 0, 0.14);
  color: #fff;
  box-shadow: inset 0 0 10px 3px var(--rs-btn-blue-inner);
}

.audience-btn.is-active,
.audience-btn.is-active:hover {
  /* Активная вкладка — выступ окна: фон тот же, что у карточки под ней
     (--rs-tab-surface), поэтому внизу она с ней сливается без шва и читается
     как продолжение карточки, поднятое в таб-бар. Собственной обводки и
     светлой кромки у неё нет: и то и другое нарисовало бы контур кнопки
     поверх стыка.

     Светится вкладка ореолом из палитры кнопок: внешняя тень 00D9FF 80%
     обводит её поверх тёмного таб-бара, внутренняя 2DC7FF 80% подсвечивает
     изнутри. Нижняя половина ореола выходит на карточку — за счёт z-index
     она не срезается, и вкладка кажется подсвеченной из карточки. */
  background: var(--rs-tab-surface);
  color: #fff;
  box-shadow: 0 0 14px 2px var(--rs-btn-blue-drop),
      inset 0 0 10px 3px var(--rs-btn-blue-inner);
  text-shadow: var(--rs-btn-text-shadow);
}

/* --- Круглая кнопка "повтор" (в шапке диалога) ---

   Заливка сплошным оранжевым, стрелка белая. Раньше стоял
   полупрозрачный оранжевый 12% с коричневой стрелкой — на новом синем
   фоне диалога кнопка тонула и читалась как серая точка. */
.replay {
  margin-left: auto;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--rs-cta);
  background-color: var(--rs-cta);
  color: #fff;
  box-shadow: 0 0 12px rgba(255, 176, 74, 0.5);
  transition: transform 0.3s ease, border-color 0.3s ease,
      box-shadow 0.3s ease, color 0.3s ease, background-color 0.3s ease;
}

.replay:hover {
  transform: rotate(-90deg);
  border-color: #ffc46b;
  background-color: #ffc46b;
  color: #fff;
  box-shadow: 0 0 22px rgba(255, 176, 74, 0.8);
}

/* --- Видимая рамка фокуса с клавиатуры --- */
.audience-btn:focus-visible,
.btn:focus-visible,
.replay:focus-visible,
.shots-arrow:focus-visible,
.shots-play:focus-visible,
.shots-tab:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

@media (max-width: 640px) {
  .demo-card {
    padding: var(--rs-sp-5);
  }

  .sort-shelves {
    grid-template-columns: 1fr;
  }

}

/* ===================== Демо: квиз и сортировка (светлая тема по макету) ===================== */

.demo-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Между карточками — та же ступень 24px, что у .rewards */
  gap: var(--rs-sp-5);
  /* Отступ от заголовка секции до сетки карточек задаёт .sec-head
             (var(--rs-sec-gap) = 32px). Раньше здесь стояло ещё и 36px
             поверх него — значение вне шкалы. */
  margin-top: 0;
}

/* Светлая карточка демо — по макету. Отступы 24px — как у карточек
         наград в #shots и у панелей аудитории. */
.demo-card {
  transition: transform var(--rs-t-base) var(--rs-ease),
      border-color var(--rs-t-base) var(--rs-ease),
      box-shadow var(--rs-t-base) var(--rs-ease);
  background: #eef4fb;
  border: 1px solid rgba(13, 58, 92, 0.1);
  border-radius: 20px;
  padding: var(--rs-sp-5);
  /* колонка, чтобы кнопки прижались к низу карточки */
  display: flex;
  flex-direction: column;
}

/* Внутренний блок растягивается — кнопка встаёт на одну высоту
         в обеих карточках, независимо от длины вопроса */
.quiz,
.sort {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.demo-card:hover {
  box-shadow: 0 24px 55px rgba(0, 0, 0, 0.45);
  border-color: rgba(126, 168, 232, 0.5);
  transform: translateY(-2px);
}

.demo-head h3 {
  margin: 0 0 var(--rs-sp-1);
  color: var(--rs-paper-ink);
  /* Заголовок и его надпись-плашка — одна смысловая пара, поэтому
             минимальный зазор, 4px. */
  margin-bottom: var(--rs-sp-1);
  font-family: var(--rs-font-head);
  font-size: 1.2rem;
}

/* Оранжевая надпись-плашка как на макете */
.demo-tag {
  display: block;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #b45309;
  border: none;
  background: none;
  border-radius: 0;
  padding: 0;
  margin: 0 0 var(--rs-sp-2);
}

.quiz-progress {
  color: var(--rs-paper-muted);
  font-size: 0.85rem;
  min-height: 1.5em;
  /* Подпись «Вопрос 1 из 3» и точки под ней — одна пара, поэтому
             зазор между ними минимальный, 4px. */
  margin: 0 0 var(--rs-sp-1);
}

.quiz-question {
  color: var(--rs-paper-ink);
  font-size: 1.08rem;
  font-weight: 700;
  line-height: 1.45;
  font-family: var(--rs-font-body);
  /* Вопрос и варианты — одна смысловая пара внутри карточки:
             зазор 16px, ступень для внутренних блоков. */
  margin: 0 0 var(--rs-sp-4);
}

.quiz-options {
  display: grid;
  /* Варианты ответа идут списком, поэтому ступень 12px */
  gap: var(--rs-sp-3);
  margin: 0 0 var(--rs-sp-4);
}

/* Вариант ответа: белая карточка с номером в квадрате */
.quiz-option {
  display: flex;
  align-items: center;
  /* Номер и текст варианта — те же 12px, что между вариантами */
  gap: var(--rs-sp-3);
  text-align: left;
  background: #ffffff;
  border: 1px solid rgba(13, 58, 92, 0.12);
  color: var(--rs-paper-ink);
  border-radius: 14px;
  padding: var(--rs-sp-3) var(--rs-sp-4);
  font-size: 1rem;
  min-height: 60px;
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.2s ease, background-color 0.2s ease,
            box-shadow 0.2s ease, transform 0.2s ease;
}

.quiz-num {
  flex: none;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  /* Цифра — ровно посередине плашки.

     Почему нужен line-height: 1. Плашка это квадрат 34×34 с одной строкой
     внутри, а line-height наследовался от body — 1.6. У строки в 1,6 раза
     больше кегля появляется полуинтерлиньяж, базовая линия уезжает вниз от
     середины строки, и place-items: center центрирует строку целиком вместе
     с этой ошибкой. Замерено на рендере (красная рамка вокруг плашки, zoom 5):
     при line-height 1,6 краска цифры «1» лежала на 4,5px НИЖЕ середины
     плашки, при line-height 1 — на 0,4px выше, то есть в пределах
     полупикселя.

     Прежде здесь стояла другая правка — асимметричный padding-top: 0.066em.
     Она считалась от метрик гарнитуры в предположении, что смещение
     0,033em, и по замеру оказалась в 14 раз слабее нужного: цифра осталась
     смещённой вниз. Правильный инструмент — line-height, а не padding. */
  line-height: 1;
  border-radius: 10px;
  background: #dbeafe;
  color: #2563eb;
  font-family: var(--rs-font-head);
  font-size: 0.95rem;
  font-weight: 800;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.quiz-option:hover:not([disabled]) {
  border-color: #7ea8e8;
  box-shadow: 0 8px 20px rgba(11, 27, 51, 0.09);
  transform: translateY(-1px);
}

/* Выбранный, но ещё не проверенный вариант */
.quiz-option.is-selected {
  border-color: #2563eb;
  background: #dbeafe;
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.18);
}

.quiz-option.is-selected .quiz-num {
  background: #2563eb;
  color: #fff;
}

.quiz-option.is-right {
  animation: pop-in 0.3s cubic-bezier(0.2, 0.7, 0.3, 1.3);
  border-color: #00cf5f;
  background: rgba(0, 207, 95, 0.1);
}

.quiz-option.is-right .quiz-num {
  background: #00cf5f;
  color: #fff;
}

.quiz-option.is-wrong {
  animation: shake 0.3s cubic-bezier(0.2, 0.7, 0.3, 1.3);
  border-color: #ff7160;
  background: rgba(255, 113, 96, 0.1);
}

.quiz-option.is-wrong .quiz-num {
  background: #ff7160;
  color: #fff;
}

.quiz-feedback {
  min-height: 1.6em;
  font-family: var(--rs-font-body);
  color: var(--rs-paper-muted);
  /* Ответ и кнопки — пара внутри карточки: 16px */
  margin: 0 0 var(--rs-sp-4);
}

.quiz-feedback.good {
  color: #0a7a45;
}

.quiz-feedback.bad {
  color: #b3392a;
}

/* Строка кнопок квиза — прижата к низу карточки, как у сортировки */
.quiz-actions {
  display: flex;
  flex-wrap: wrap;
  /* Пара кнопок — 12px, как в .hero-actions и .hero-cta. Здесь стояло
             8px, и в одной карточке ряд кнопок был уже, чем точно такой же
             ряд в герое. */
  gap: var(--rs-sp-3);
  margin-top: auto;
  /* прижать к низу карточки */
  padding-top: var(--rs-sp-4);
}

/* Главные кнопки демо — оранжевый неон, как на сайте.
         Кнопка .btn-secondary без .btn-cta остаётся синей (как в hero). */
.demo-card .btn-cta {
  background-color: var(--rs-btn-orange-fill);
  color: #fff;
  border-color: var(--rs-btn-orange-stroke);
  box-shadow: 0 0 13px 3px var(--rs-btn-orange-drop),
            inset 0 0 10px 3px var(--rs-btn-orange-inner);
  text-shadow: var(--rs-btn-text-shadow);
}

.demo-card .btn-cta:hover {
  background-color: var(--rs-btn-orange-fill-hover);
  border-color: var(--rs-btn-orange-stroke);
  box-shadow: 0 0 20px 3px var(--rs-btn-orange-drop),
            inset 0 0 14px 3px var(--rs-btn-orange-inner);
}

/* Пока ничего не выбрано, «Проверить» неактивна: гасим неон,
         оставляя рамку, чтобы кнопка не выглядела пропавшей */
.demo-card .btn-cta:disabled,
.demo-card .btn-cta:disabled:hover {
  background-color: rgba(13, 58, 92, 0.05);
  color: #54718f;
  border-color: rgba(13, 58, 92, 0.22);
  box-shadow: none;
  /* text-shadow здесь не задаём: он и так none у всех кнопок
     (--rs-btn-text-shadow), правило было бы пустым */
  cursor: not-allowed;
  transform: none;
}

.sort-hint {
  color: var(--rs-paper-muted);
  font-size: 0.95rem;
}

.shelf ul,
.sort-tray {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  /* Чипы в лотке и в полке — это «список», ступень 12px */
  gap: var(--rs-sp-3);
  min-height: 58px;
}

.sort-tray {
  /* Подсказка про перетаскивание и лоток с чипами — блок и его
             содержимое, зазор 16px, как у вопроса и вариантов ответа. */
  margin: var(--rs-sp-4) 0 var(--rs-sp-4);
}

.chip {
  /* ui-monospace/Consolas/monospace — третий шрифт, которого нет в
       assets/fonts. На сайте только Harpseal и OpenRunde, поэтому чипы
       набираются основной гарнитурой. */
  font-family: var(--rs-font-body);
  font-size: 1rem;
  background: #ffffff;
  border: 1px solid rgba(13, 58, 92, 0.14);
  color: var(--rs-paper-ink);
  border-radius: 999px;
  padding: var(--rs-sp-3) var(--rs-sp-4);
  min-height: 48px;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.chip:active {
  cursor: grabbing;
}

.chip.is-selected {
  border-color: var(--rs-cta);
  background: rgba(255, 111, 59, 0.16);
}

.chip.is-right {
  border-color: #00cf5f;
}

.chip.is-wrong {
  border-color: #ff7160;
}

.chip.is-dragging {
  opacity: 0.35;
}

.chip.is-placed {
  animation: pop-in 0.25s cubic-bezier(0.2, 0.7, 0.3, 1.3);
}

.chip-drag-ghost {
  position: fixed;
  z-index: 300;
  pointer-events: none;
  margin: 0;
  transform: translate(-50%, -65%) rotate(-3deg);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.55);
}

.shelf.is-drop-target {
  border-color: var(--rs-cta);
  background: rgba(255, 111, 59, 0.1);
  animation: shelf-pulse 0.8s ease-in-out infinite;
}

.sort-shelves {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Две полки — две карточки, зазор как между карточками: 24px.
             Раньше было 14px, и полки читались слишком слитно. */
  gap: var(--rs-sp-5);
  /* Отступ до строки ответа под полками — 16px, тот же, что от вариантов
             ответа до строки ответа в карточке квиза (.quiz-options). Без него
             строка ответа в карточке сортировки примыкала к полкам впритык,
             хотя в квизе между теми же двумя блоками было 16px. */
  margin: 0 0 var(--rs-sp-4);
}

.shelf {
  border: 2px dashed rgba(13, 58, 92, 0.22);
  border-radius: 14px;
  /* Внутренние отступы полки — 16px: это блок внутри карточки,
             как заголовок и текст внутри .journey-step. */
  padding: var(--rs-sp-4);
  background: rgba(255, 255, 255, 0.55);
}

.shelf h4 {
  font-size: 1rem;
  color: var(--rs-paper-ink);
  margin: 0 0 var(--rs-sp-3);
  font-family: var(--rs-font-head);
}

.shelf .chip {
  font-size: 0.9rem;
  min-height: 44px;
  /* Уменьшенный чип внутри полки: 8/12 вместо 12/16 */
  padding: var(--rs-sp-2) var(--rs-sp-3);
}

.sort-actions {
  display: flex;
  flex-wrap: wrap;
  /* Пара кнопок — 12px, как в .quiz-actions, .hero-actions и .hero-cta */
  gap: var(--rs-sp-3);
  margin-top: auto;
  /* прижать к низу карточки */
  padding-top: var(--rs-sp-4);
}


/* ===================== Скриншоты: карусель и награды ===================== */

/* Кадры — почти на всю ширину окна (обычный .wrap ограничен 1180px) */
#shots .wrap {
  width: min(1560px, calc(100% - 32px));
}

/* Карточки наград оставляем на прежней ширине */
#shots .rewards {
  max-width: 1180px;
  margin-left: auto;
  margin-right: auto;
}

/* ---------- Рамка кадров ----------
         Синяя карточка с точечной сеткой и двойным светлым кантом, поверх неё
         оранжевая трапеция-вкладка слева и планета в правом верхнем углу — как
         на макете. Обёртка отдельная от .shots-slider: тот обрезает слайды по
         overflow:hidden и декор бы не вышел наружу. */
.shots-section {
  text-align: center;
  /* Ширина рамки. Запас справа/слева — под декор, который выходит за
             края: оранжевая вкладка на 35px, а угол повёрнутого ромба — на
             (60px × √2 − 60px) / 2 ≈ 12px плюс его правый отступ 12px, итого
             около 24px. По 40px с запасом на сторону, иначе появилась бы
             горизонтальная прокрутка. Ряду управления нужна та же ширина,
             поэтому живёт здесь, а не дублируется в двух правилах. */
  --shots-w: min(calc(100% - 80px), 1320px, 118vh);
}

.shots-frame {
  position: relative;
  width: 100%;
  max-width: var(--shots-w);
  /* Отступ от заголовка секции до первого блока — тот же, что в
             остальных секциях: 32px (--rs-sec-gap). Здесь стояло 48px — рамка
             «весит» больше карточек, но отступ от заголовка секции до её
             содержимого на сайте везде один, иначе #for (32) и #faq (32)
             выглядели бы тесно на фоне #shots. */
  margin: var(--rs-sec-gap) auto 0;
  /* Снизу 16px — столько же, сколько отступ у подписи (margin-top),
             поэтому текст стоит ровно посередине между картинкой и нижним
             краем рамки. Сверху и по бокам оставляем 24px: там нужен запас под
             точечную сетку (шаг 22px) и внутренний кант. */
  padding: var(--rs-sp-5) var(--rs-sp-5) var(--rs-sp-4);
  background:
            radial-gradient(circle, rgba(178, 226, 255, 0.38) 1.5px, transparent 2.1px) 0 0 / 22px 22px,
            linear-gradient(180deg, #1b74d8 0%, #0c50a0 100%);
  border-radius: 26px;
  /* внешний кант двойной линии: светлая обводка + мягкая тень */
  box-shadow:
            0 24px 48px rgba(8, 30, 70, 0.45),
            inset 0 0 0 2px rgba(206, 240, 255, 0.45);
}

/* Оранжевая вкладка сбоку — обычный прямоугольник, у которого clip-path
         срезает углы: слева остаётся ровный край, а сверху и снизу идут
         косые срезки, из-за чего вкладка выглядит трапецией. Чем больше
         срезка, тем тупее угол: 28px. Правый край (100% по X) уходит под
         синюю рамку — для этого z-index: -1, иначе оранжевое легло бы
         поверх рамки и её срезало. Высота задаётся top/bottom, поэтому
         вкладка тянется на любую высоту кадра. Градиент тот же, что у
         подложки планеты (.shots-planet::before), поэтому вкладка и ромб
         читаются как один материал. */
.shots-frame::before {
  content: "";
  position: absolute;
  top: 40px;
  /* отступ сверху */
  bottom: 40px;
  /* отступ снизу */
  left: -35px;
  /* выглядывает из-за рамки */
  width: 40px;
  /* видимая часть + запас под основной блок */
  z-index: -1;
  /* прячем под синюю рамку */
  background: linear-gradient(180deg, #ffb04a 0%, #f4620a 100%);
  /* срезаем углы сверху и снизу, из них же получается трапеция */
  clip-path: polygon(100% 0, 0 28px, 0 calc(100% - 28px), 100% 100%);
}

/* Иконка с планетой в правом верхнем углу. В planet-icon.svg только
         сама планета, поэтому оранжевую подложку рисуем сами: ромб —
         это квадрат со скруглением, повёрнутый на 45°. Рамка вокруг ромба
         сделана градиентом: внешний слой — переход от светлого к тёмному,
         внутренний — ровный оранжевый, отступ 2px даёт линию рамки. */
.shots-planet {
  position: absolute;
  top: -16px;
  right: -12px;
  z-index: 1;
  width: 60px;
  height: 60px;
  transform: rotate(45deg);
  border-radius: 13px;
  background: linear-gradient(135deg, #ffc46b 0%, #f4620a 100%);
  display: grid;
  place-items: center;
  pointer-events: none;
  box-shadow: 0 8px 20px rgba(180, 70, 8, 0.4);
}

/* Внутренняя плашка: отступ от внешнего слоя и есть рамка */
.shots-planet::before {
  content: "";
  position: absolute;
  inset: 2px;
  border-radius: 11px;
  background: linear-gradient(180deg, #ffb04a 0%, #f4620a 100%);
}

.shots-planet img {
  position: relative;
  width: 48px;
  height: 33px;
  transform: rotate(-45deg);
}

/* ---------- Кадры (смена только по прозрачности) ----------
         Размер кадра задаёт обёртка .shots-frame: картинка занимает её
         внутреннюю область, 100% — по ширине окна, 1320px — не растягиваем
         сверх натуральных 1382px, 118vh — по высоте окна, чтобы на больших
         мониторах блок не занимал весь экран. Обёртка .shots-slider и
         .shots-track нужны только для группировки: ничего не обрезают и
         ничего не двигают — кадры сменяет прозрачность (см. ниже). */
.shots-slider {
  position: relative;
  width: 100%;
}

/* Кадры наложены друг на друга: все слайды занимают одну ячейку сетки,
         поэтому трек не едет и не имеет ни ширины, ни перехода. Высота трека
         берётся у самого высокого слайда, так что рамка не скачет. */
.shots-track {
  display: grid;
}

.shot-slide {
  grid-area: 1 / 1;
  /* все слайды в одной ячейке — друг поверх друга */
  min-width: 0;
  margin: 0;
}

/* Фиксированная пропорция 16:10 — все слайды одной высоты, слайдер
         не скачет. object-fit: cover заполняет рамку целиком, поэтому
         по бокам не появляются тёмные полосы, как при contain.
         Чтобы обрезки не было вовсе, скриншоты надо снимать в 16:10. */
.shot-slide img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: #0b1b33;
  margin: 0 auto;
  border-radius: 18px;
  /* Ни обводки, ни тени: кадр лежит прямо на синей подложке. */
}

/* Подпись. Отступ сверху (16px) равен padding'у рамки снизу, а сам
         текст центрируется по высоте блока, поэтому он всегда стоит ровно
         посередине между картинкой и нижним краем рамки — и на одну, и на
         две строки. min-height резервирует одну строку, чтобы короткая
         подпись не сжимала рамку. */
.shot-slide figcaption {
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 600px;
  margin: var(--rs-sp-4) auto 0;
  min-height: 1.6em;
  /* Подпись лежит на синей рамке, и привычный приглушённый --rs-muted
             на ней читается как серый. Поэтому тут светлее --rs-ink, почти
             белый: на синем фоне он держит контраст, как в макете. */
  color: #eef6ff;
  font-size: 0.95rem;
  line-height: 1.6;
}

/* ---------- Проявление кадра по прозрачности ----------
         Гаснут и картинка, и подпись под ней: активному кадру JS вешает
         .is-active (shotPaint), остальные висят в opacity: 0. Прозрачность
         не влияет на высоту, поэтому рамка не скачет, пока кадр проявляется.
         Селекторы от .shots-frame: анимация не должна задеть такие же
         картинки в других блоках. */
.shots-frame .shot-slide figcaption,
.shots-frame .shot-slide img {
  opacity: 0;
  transition: opacity 0.4s ease;
}

.shots-frame .shot-slide.is-active figcaption,
.shots-frame .shot-slide.is-active img {
  opacity: 1;
}

/* ---------- Карточки наград ----------
   Три карточки повторяют материал миссии, и у каждой свой оттенок. Поэтому
   оболочка .reward задаёт только форму, раскладку и прозрачную обводку, а
   весь цвет — подложка, кант и свечения — живёт в модификаторах
   .reward--crystal / --code / --progress.

   Значения обводок и теней сняты с макета один в один, поэтому порядок
   теней в box-shadow значим: в CSS первая тень лежит выше остальных, как и
   в списке эффектов. Значение «внутрь, размытие N» из макета пишется
   как inset 0 0 N (размытие) идёт вторым числом, разброс — третьим;
   здесь разброс у всех нулевой. */
.rewards {
  display: grid;
  /* Порог 260px, а не 200px: пока карточка не стала этой шириной, три
     в ряд не держим и переходим на две попарно. На 200px карточка сужалась
     до 236px, и заголовок «Фрагменты кода» переносился на вторую строку —
     в две колонки он помещается целиком. */
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  /* Между карточками — ступень 24px, как у .demo-grid */
  gap: var(--rs-sp-5);
  margin-top: var(--rs-sp-6);
}

/* Слои заданы z-index, а не порядком в разметке, и стопка общая на весь
   ряд: подложки-планеты 1, элементы 2, текст 3.

   Именно общая стопка даёт эффект из макета: вынесенный за правый край
   элемент первой карточки перекрывает подложку второй, а текст второй
   остаётся поверх. Если бы у .reward стояла isolation:isolate, каждая
   карточка стала бы отдельной стопкой и перекрывала предыдущую целиком —
   нависания не было бы видно, элемент просто прятался бы за соседней.

   isolation здесь не нужен и потому, что подложка непрозрачна и занимает
   ровно свой прямоугольник: попасть под фон секции она не может — фон
   секции рисуется ниже любого позиционированного слоя.

   min-height намеренно не задан: высоту задаёт текст. Карточки от сдвига
   картинок не меняются — элемент стоит вне потока. */
.reward {
  position: relative;
  /* Обрезки здесь НЕТ: элемент награды вдвое крупнее прежнего и намеренно
     выходит за край карточки. Обрезку забрала на себя подложка
     (см. .reward-bg) — так скругление остаётся, а элемент свободен. */
  overflow: visible;
  display: flex;
  align-items: center;
  padding: var(--rs-sp-5);
  border-radius: 20px;
  /* Прозрачная обводка нужна, чтобы у всех карточек была одинаковая рамка
     по толщине: цвет подставляет модификатор, а размер — здесь. */
  border: 1px solid transparent;
  text-align: left;
  /* Доля ширины колонки, отданная картинке: остальное достаётся тексту
     (padding-right в .reward-body). Связана с выносом картинки внизу —
     чем правее картинка уехала, тем шире текст, — поэтому и живёт здесь,
     рядом с --reward-el-out, а не в самой колонке. */
  --reward-text-reserve: 56%;
  --reward-el-out: 16px;
}

/* Вынос картинки за правый край ограничен запасом по бокам от ряда. Пока ряд
   не упирается в предел 1180px, зазор равен отступу .wrap — 16px, и вынос
   больше дал бы горизонтальную прокрутку. На широком экране ряд центрирован
   и по бокам остаётся запас: 52px при зазоре 24px переносят рисунок через
   половину промежутка на соседнюю карточку, а запас по краю экрана на
   1290px равен 55px, так что прокрутки не возникает.

   Заодно растёт текст: уехавшая вправо картинка освобождает место, и колонка
   под неё уменьшается с 56% до 44% — описания перестают в четыре строки. */
@media (min-width: 1290px) {
  .reward {
    --reward-el-out: 52px;
    --reward-text-reserve: 44%;
  }
}

/* Текстовый блок. min-width:0 обязателен — иначе длинное слово в узкой
   колонке распирает карточку, а не переносится.

   padding-right в процентах резервирует место под элемент, который стоит
   поверх и выходит за правый край. Резервируется не вся ширина элемента, а
   только часть до его левого края: у рисунков по краям прозрачное поле
   (слева 7.6% у колбы, 8.7% у флага, 11% у кристалла), и на это поле текст
   может заходить, не наезжая на сам рисунок. */
.reward-body {
  position: relative;
  /* 3 — выше элемента: вынесенная вправо картинка соседней карточки не
     должна ложиться на текст. */
  z-index: 3;
  flex: 1 1 auto;
  min-width: 0;
  padding-right: calc(var(--reward-text-reserve) + var(--rs-sp-2));
}

.reward h3 {
  margin: 0 0 var(--rs-sp-3);
  font-family: var(--rs-font-head);
  /* 1.2rem, а не 1.4rem: на самой узкой карточке сетки (≈377px) заголовок
     «Фрагменты кода» на 1.4rem переносился на вторую строку, а в макете он
     стоит в одну. */
  font-size: 1.2rem;
  line-height: 1.15;
  color: #fff;
}

.reward p {
  margin: 0;
  /* На подложке-планете привычный --rs-muted (#a9c3d4) уходил в серый,
     поэтому описание белое, как заголовок. */
  color: #fff;
  font-size: 0.9rem;
  line-height: 1.5;
}

/* Элемент награды (кристалл, колба, звезда с флагом).

   Вдвое против прежних 30% / 120px. Стоит вне потока, иначе задавал бы
   высоту карточки сам и выйти за её край не смог бы; вынос за границу
   задан переменной --reward-el-out (16px по умолчанию, 52px на широком
   экране — см. @media выше).

   Пропорции исходника не меняются: элементы квадратные, и растягивать
   кристалл по вертикали значило бы рисовать его не таким, как нарисовали. */
.reward-el {
  position: absolute;
  /* 2 — выше подложек всех карточек (1), но ниже их текста (3). */
  z-index: 2;
  top: 50%;
  right: calc(-1 * var(--reward-el-out));
  transform: translateY(-50%);
  width: 60%;
  max-width: 240px;
  height: auto;
}

/* Подложка: планета в углу карточки. Обрезается по border-radius и
   растягивается по всей площади, поэтому пропорции исходника не важны.

   Обрезку держит сама подложка, а не карточка: карточке нужен видимый
   элемент, который выходит за её края. border-radius: inherit повторяет
   скругление карточки, overflow:hidden рубит по нему картинку. */
.reward-bg {
  position: absolute;
  inset: 0;
  /* 1 — самый нижний слой стопки ряда. */
  z-index: 1;
  display: block;
  border-radius: inherit;
  overflow: hidden;
}

.reward-bg img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Кристаллы — розово-пурпурная карточка */
.reward--crystal {
  border-color: #e988c5;
  box-shadow:
            0 0 10px 1px #f93e8e,
            inset 0 0 8px 0 #e771fc,
            inset 0 0 30px 0 rgba(236, 84, 253, 0.5);
}

/* Фрагменты кода — синяя карточка */
.reward--code {
  border-color: #95c6fd;
  box-shadow:
            0 0 10px 1px #2371cd,
            inset 0 0 8px 0 #48eeff,
            inset 0 0 30px 0 rgba(230, 93, 18, 0.5);
}

/* Прогресс — оранжевая карточка: оранжевое внешнее свечение и два
   внутренних — оранжевый контур и голубой разлив. */
.reward--progress {
  border-color: #ffb45f;
  box-shadow:
            0 0 10px 1px rgba(246, 62, 6, 0.7),
            inset 0 0 8px 0 #fec357,
            inset 0 0 30px 0 rgba(0, 202, 254, 0.8);
}

/* ---------- Управление каруселью ----------
         Раньше под картинкой шли три элемента управления подряд: точки,
         ряд вкладок, а стрелки висели поверх самой картинки. Три способа
         указать одно и то же на трёх слайдах — отсюда ощущение тесноты.
         Оставили один ряд: стрелка — вкладки — стрелка. Точки убрали,
         они дублировали вкладки. */
.shots-nav {
  position: relative;
  width: 100%;
  /* та же ширина, что и у картинки: рамка шире её на 2×26px,
            поэтому из ширины рамки вычитаем padding */
  max-width: calc(var(--shots-w) - 52px);
  margin: var(--rs-sp-5) auto 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  /* Ряд управления: стрелка, вкладки, стрелка. Между стрелками и
             вкладками — 16px, между самими вкладками — 12px: вкладки
             принадлежат одной группе, стрелки от неё отделены. */
  gap: var(--rs-sp-4);
}

.shots-tabs {
  display: flex;
  justify-content: center;
  gap: var(--rs-sp-3);
  flex: 0 1 auto;
  flex-wrap: wrap;
}

/* --- Переключатель скриншотов --- */
/* Layout only — neon skin lives in styles.css */
.shots-tab {
  background-color: rgba(var(--rs-neon-blue-glow), 0.05);
  border: 2px solid rgba(var(--rs-neon-blue-glow), 0.35);
  color: var(--rs-muted);
  box-shadow: 0 0 10px rgba(var(--rs-neon-blue-glow), 0.2),
      inset 0 0 8px rgba(var(--rs-neon-blue-glow), 0.12);
  /* Свечения букв нет — см. --rs-btn-text-shadow. У неактивной
     вкладки ореол убран вместе с активной, иначе они читались бы
     наоборот: подсвеченные невыбранные. */
  text-shadow: none;
  transition: background-color 0.3s ease, border-color 0.3s ease,
      box-shadow 0.3s ease, color 0.3s ease, text-shadow 0.3s ease;
  border-radius: 12px;
  /* Как у .audience-btn: та же плашка-переключатель */
  padding: var(--rs-sp-3) var(--rs-sp-5);
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
}

/* ---------- Стрелки слайдера ---------- */
.shots-arrow {
  flex: none;
  /* в ряду управления, а не поверх картинки */
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(0, 179, 255, 0.4);
  background: rgba(0, 18, 32, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 0 12px rgba(0, 179, 255, 0.35),
            inset 0 0 8px rgba(0, 179, 255, 0.2);
  transition: background-color 0.3s ease, border-color 0.3s ease,
            box-shadow 0.3s ease, color 0.3s ease, opacity 0.3s ease;
}

.shots-arrow svg {
  width: 22px;
  height: 22px;
}

.shots-arrow:hover:not([disabled]) {
  border-color: #00b3ff;
  background: rgba(0, 45, 72, 0.92);
  box-shadow: 0 0 22px rgba(0, 179, 255, 0.8),
            inset 0 0 12px rgba(0, 179, 255, 0.45);
}

.shots-arrow[disabled] {
  opacity: 0.3;
  cursor: default;
  box-shadow: none;
}

/* ---------- Пауза автопрокрутки ----------
         Кнопка вынесена из потока и прижата к правому краю ряда: иначе
         она стала бы четвёртым элементом и сдвинула вкладки с центра.
         Иконка показывает действие (пауза/пуск), aria-pressed — состояние,
         подпись — что это за контрол. */
.shots-play {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  flex: none;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(0, 179, 255, 0.3);
  background: rgba(0, 18, 32, 0.6);
  color: rgba(255, 255, 255, 0.8);
  cursor: pointer;
  transition: border-color 0.3s ease, color 0.3s ease,
            background-color 0.3s ease, box-shadow 0.3s ease;
}

.shots-play svg {
  grid-area: 1 / 1;
  width: 17px;
  height: 17px;
}

.shots-play-play {
  display: none;
}

.shots-play[aria-pressed="false"] .shots-play-pause {
  display: none;
}

.shots-play[aria-pressed="false"] .shots-play-play {
  display: block;
}

.shots-play:hover {
  border-color: #00b3ff;
  color: #fff;
  background: rgba(0, 45, 72, 0.85);
  box-shadow: 0 0 16px rgba(0, 179, 255, 0.45);
}

@media (max-width: 600px) {
  /* На телефоне пять элементов в ряд не помещаются — вкладки растягиваем
           на всю ширину, а стрелки убираем: листается свайпом, а вкладки
           дают прямой переход на любой кадр. Кнопка паузы при этом
           возвращается в поток и встаёт на собственную строку по центру. */
  .shots-nav {
    gap: var(--rs-sp-3);
  }

  .shots-arrow {
    display: none;
  }

  .shots-play {
    position: static;
    transform: none;
  }

  .shots-tabs {
    width: 100%;
    gap: var(--rs-sp-2);
  }

  .shots-tab {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    /* Три вкладки делят ширину экрана, поэтому боковые отступы
                 ужимаются до 8px */
    padding: var(--rs-sp-3) var(--rs-sp-2);
    font-size: 0.85rem;
  }

}

/* ===================== Секции: база, чек-лист, вкладки «ученик / родитель» ===================== */

/* ---------- Section Base ---------- */
.section {
  padding: var(--rs-sec-top) 0 var(--rs-sp-6);
}

.section-light {
  background: var(--rs-panel);
}

/* «Python — первая точка входа» — из блоков на растушёвке он единственный
   остался, и градиент ему не нужен: текста мало (заголовок, одна строка
   и плашки), и картинка на нём только мешает. Фон прозрачный, космос
   виден целиком. Тот же случай у #try, см. .final. */
#python {
  background: transparent;
}

/* ---------- Check List ---------- */
.check-list {
  list-style: none;
  /* Отступ сверху и снизу — как у .sec-head и .blist: 32px от
             соседнего блока. Раньше было 22px. */
  margin: var(--rs-sec-gap) 0;
  padding: 0;
  display: grid;
  gap: var(--rs-sp-3);
}

.check-list li {
  color: var(--rs-ink);
  font-size: 0.95rem;
  line-height: 1.5;
  position: relative;
  /* 24px — ширина кружка с галочкой, плюс 8px воздуха до текста */
  padding-left: var(--rs-sp-6);
}

.check-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--rs-dialog);
  color: #fff;
  font-size: 0.85rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ---------- Audience Window: окно-папка с выступом ---------- */
/* Раньше окно собиралось из двух блоков: полоса вкладок со своим фоном и
   карточка под ней со своим. На стыке фоны должны были совпадать до пикселя,
   и любая правка одного из них ломала шов. Теперь окно — один элемент
   .audience-window, а силуэт папки (тело плюс выступ-вкладка сверху слева)
   вырезан у него целиком через clip-path: shape().

   Почему shape(), а не SVG-маска: в SVG-маске координаты задаются либо в
   пикселях — тогда силуэт не тянется по ширине окна, — либо в
   clipPathUnits="objectBoundingBox", в долях от размера элемента, но тогда
   окружность радиуса r вырождается в эллипс: при окне 1180×485 угол 20px
   стал бы 20px по горизонтали и 8px по вертикали. В shape() координаты и
   радиусы дуг задаются в одних единицах (px, %, calc()), поэтому скругления
   остаются круглыми при любом размере окна.

   Медиазапрос на 640px ниже снимает clip-path: там вкладки растягиваются на
   всю ширину, выступа быть не может, и окно возвращается к обычной
   скруглённой карточке (её держат border-radius и overflow). */

.audience-window {
  /* Геометрия силуэта. Вынесена в переменные не ради красоты: те же числа
     нужны ряду вкладок, потому что выступ обязан совпасть с ним. Если
     выступ окажется уже полосы вкладок, вкладки вылезут за край окна и
     обрежутся — это уже проверено на глаз по замерам. */
  --rs-folder-r: 20px;      /* радиус внешних углов */
  --rs-folder-fillet: 16px; /* радиус вогнутого скругления на ступеньке */
  /* Ширина выступа: две вкладки по 168px, зазор 8px и поля 12px с боков. */
  --rs-folder-tab-w: 368px;
  /* Высота выступа = высота ряда вкладок: 12px поля сверху + 44px вкладка. */
  --rs-folder-tab-h: 56px;

  position: relative;
  /* Во всю ширину колонки: раньше окно было 880px, и на широком экране
     справа от него зияла пустая полоса фона. Ширина равна .wrap —
     блок встаёт в общую линию страницы. */
  max-width: 1180px;
  margin-top: var(--rs-sec-gap);
  /* Фон у окна, а не у полосы и карточки по отдельности: у папки один
     материал на выступ и тело. */
  background: var(--rs-tab-surface);
  /* Запасной вариант для браузера без shape(): объявление clip-path будет
     отброшено целиком, и окно останется обычной скруглённой карточкой.
     Там, где shape() поддержан, внешние углы силуэта совпадают с этими
     радиусами, поэтому border-radius ничего не портит. */
  border-radius: var(--rs-folder-r);
  /* Обрезает детей по контуру папки: блик панели, ореол активной вкладки и
     нижний край портрета не должны вылезать за силуэт. */
  overflow: hidden;
  /* Силуэт. Обход по часовой стрелке от левого верхнего угла выступа:
     вправо по верхнему краю → скругление → вниз по правому краю выступа →
     вогнутое скругление на ступеньке → вправо по верхнему краю тела →
     и дальше по трём внешним углам. Выпуклые углы идут cw, вогнутая
     ступенька — против часовой (ccw). */
  clip-path: shape(
    from var(--rs-folder-r) 0,
    line to calc(var(--rs-folder-tab-w) - var(--rs-folder-r)) 0,
    arc to var(--rs-folder-tab-w) var(--rs-folder-r)
      of var(--rs-folder-r) var(--rs-folder-r) cw,
    line to var(--rs-folder-tab-w) calc(var(--rs-folder-tab-h) - var(--rs-folder-fillet)),
    arc to calc(var(--rs-folder-tab-w) + var(--rs-folder-fillet)) var(--rs-folder-tab-h)
      of var(--rs-folder-fillet) var(--rs-folder-fillet) ccw,
    line to calc(100% - var(--rs-folder-r)) var(--rs-folder-tab-h),
    arc to 100% calc(var(--rs-folder-tab-h) + var(--rs-folder-r))
      of var(--rs-folder-r) var(--rs-folder-r) cw,
    line to 100% calc(100% - var(--rs-folder-r)),
    arc to calc(100% - var(--rs-folder-r)) 100%
      of var(--rs-folder-r) var(--rs-folder-r) cw,
    line to var(--rs-folder-r) 100%,
    arc to 0 calc(100% - var(--rs-folder-r))
      of var(--rs-folder-r) var(--rs-folder-r) cw,
    line to 0 var(--rs-folder-r),
    arc to var(--rs-folder-r) 0
      of var(--rs-folder-r) var(--rs-folder-r) cw,
    close
  );
}

/* Ряд вкладок — часть того же силуэта. Своего фона, рамки и радиуса у него
   больше нет: и выступ, и тело — один материал --rs-tab-surface, вырезанный
   в .audience-window. Раньше полоса затемнялась чёрным слоем, чтобы выделить
   выступ активной вкладки; с цельными силуэтом затемнение между вкладкой и
   телом сломало бы как раз то, что просили — «единый блок без разделения».

   Вкладки стоят на нижней кромке полосы (align-items: flex-end, снизу
   отступа нет), поэтому низ активной вкладки совпадает с верхним краем тела
   панели — ровно на линии ступеньки. */
.audience-switch {
  display: flex;
  align-items: flex-end;
  /* Вкладки одной группы стоят вплотную: зазор — ступень 8. Раньше был 4,
     и на полосе в 1180px вкладки сливались в одну бесформенную плашку. */
  gap: var(--rs-sp-2);
  /* 12px сверху и по бокам: первая вкладка стоит на равном удалении от
     верхнего и левого краёв выступа. Снизу отступа нет — по этому ряду
     считана высота выступа в --rs-folder-tab-h. */
  padding: var(--rs-sp-3) var(--rs-sp-3) 0;
}

/* --- Вкладки «Я ученик / Я родитель» --- */
/* Layout only — neon skin lives in styles.css */
.audience-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--rs-sp-2);
  /* У вкладок в браузере ширина близкая, дальше растёт уже текст. */
  min-width: 168px;
  min-height: 44px;
  padding: var(--rs-sp-2) var(--rs-sp-5);
  /* Скруглены только верхние углы: вкладка — выступ окна, её низ садится на
     верхнюю кромку карточки, и там радиус был бы виден зазором. */
  border: 0;
  border-radius: 14px 14px 0 0;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  /* Утопленная вкладка: полупрозрачная чёрнота поверх затемнённого таб-бара.
     Своего цвета у неё нет — так она остаётся частью того же окна, а не
     отдельной кнопкой над карточкой. */
  background-color: rgba(0, 0, 0, 0.26);
  color: var(--rs-muted);
  transition: background-color 0.3s ease, box-shadow 0.3s ease,
      color 0.3s ease, text-shadow 0.3s ease;
  font-family: var(--rs-font-body);
  font-size: 1rem;
  cursor: pointer;
}

/* Геометрия активной вкладки — рядом с базовой, а не в оформлении ниже:
   она держит стык с карточкой. Выше карточки по z-index, иначе панель,
   идущая следом по DOM, перекроет ореол вкладки и его нижнюю половину
   срежет ровно на стыке. */
.audience-btn.is-active {
  position: relative;
  z-index: 1;
}

@media (max-width: 640px) {
  /* Вкладки остаются в ряд — на узком экране в браузере они тоже в ряд, —
     но делят ширину пополам, чтобы подписи не сжимались в гармошку.
     Раньше переключатель переворачивался в колонку, для вкладок это
     выглядело бы двумя кнопками, а не вкладками.

     Правило стоит после базы .audience-btn, а не в общем списке медиазапросов
     выше: @media не добавляет специфичности, и на равных с базой
     специфичностях выигрывает правило, стоящее позже. */
  .audience-btn {
    flex: 1 1 0;
    min-width: 0;
    /* Горизонтальный отступ уже: на 320px подписи делят между собой по
       135px, и при полях в 16px «Я родитель» вставала впритык к краю. */
    padding: var(--rs-sp-3) var(--rs-sp-2);
  }

  /* Выступ папки здесь снимается. На узком экране вкладки растянуты на всю
     ширину окна (flex: 1 1 0 выше), значит выступ шириной 368px либо упрётся
     в правый край, либо окажется шире самого окна — и силуэт вывернется
     наизнанку. Окно возвращается к обычной скруглённой карточке: контур
     держат border-radius и overflow у .audience-window. */
  .audience-window {
    clip-path: none;
  }

}

/* ---------- Audience Panels ---------- */
.audience-panels {
  display: grid;
  /* Обе панели стоят в одной ячейке — ровно как кадры в .shots-track.
     Из этого следует всё нужное: высота блока постоянна (берётся от более
     высокой панели), поэтому переключение не сдвигает секцию, а сами
     панели проявляются прозрачностью друг в друга.

     Раньше панели стояли в разных строках, а переключались подменой
     display — блок дёргался дважды: текст прыгал мгновенно, и секция
     скакала по высоте (панель «родитель» выше панели «ученика» на 58px).
     Между панелями зазор был, но при наложении он не нужен. */
}

/* Панель — две колонки: крупная иконка слева, текст справа.
         На узких экранах (медиазапрос ниже) схлопывается в одну. */
.audience-panel {
  display: grid;
  /* Своego фона, рамки и тени у панели больше нет: фон и силуэт держит
     .audience-window, панель — только содержимое. Раньше панель была
     карточкой со своим фоном и рамкой, и её верхняя линия совпадала с низом
     полосы вкладок — тот самый шов, который убран вместе с разделением окна
     на вкладку и тело.

     position нужен блику ::before и портрету (z-index), overflow: hidden —
     чтобы портрет обрезался нижним краем панели, как и раньше. */
  position: relative;
  overflow: hidden;
  /* Отступы карточек на сайте: 24px. Здесь было 34px — панель самая
             широкая из карточек, но зазор внутри неё должен оставаться тем же,
             иначе текст внутри неё стоит ближе к краю, чем текст в .demo-card. */
  padding: var(--rs-sp-5);
  /* Обе панели в одной ячейке и обе остаются в разметке: иначе блок взял
     бы высоту только от активной и прыгал бы при переключении. */
  grid-area: 1 / 1;
  opacity: 0;
  /* visibility, а не только opacity: невидимая панель не должна оставаться
     в дереве доступности и ловить фокус. Меняется он с задержкой в 180мс,
     то есть к концу ухода: без задержки visibility переключился бы сразу
     и панель исчезла бы, не дорисовав перехода. */
  opacity: 0;
  /* Тайминг и кривая — ровно как у портретов Риты в #faq (.faq-visual-fit
     img): 0.6s на cubic-bezier(0.4, 0, 0.2, 1), растворение одновременное,
     без задержки и без сдвига. Переключение вкладки читается так же, как
     смена портрета в FAQ. */
  visibility: hidden;
  /* visibility с задержкой в 0.6s — до конца растворения. Это не часть
     анимации, а требование доступности: в неактивной панели есть кнопка
     «Открыть игру», и без visibility она осталась бы в дереве доступности
     и ловила бы фокус. У картинок Риты такой проблемы нет — они не
     фокусируются, поэтому у них visibility не нужен вовсе. */
  transition:
          opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
          visibility 0s linear 0.6s;
  /* Колонка портрета шире прежних 380px — на десктопе это 460px.
     Тексту остаётся 624px, а на такой ширине заголовок, пункты и кнопка
     укладываются в те же строки, что и раньше: зазор между колонками
     прежний, 48px. */
  grid-template-columns: 460px 1fr;
  /* Колонка космонавта и колонка текста — тот же разрыв, что
             у .python-layout: 48px. */
  gap: var(--rs-sp-7);
  align-items: start;
}

/* Мягкое свечение за иконкой — блок перестаёт быть плоской карточкой */
.audience-panel::before {
  content: "";
  position: absolute;
  /* Блик за портретом космонавта, а не над вкладками.
     Раньше пятно было 320×320 и висело над верхним краем панели
     (top: −70px), из-за чего подсветка попадала на полосу вкладок.
     Теперь оно крупнее портрета и смещено под него: центр по вертикали
     стоит чуть выше середины фигуры — так свет падает сверху, как на
     макете. */
  top: 50%;
  left: -70px;
  /* Блик держим чуть крупнее портрета (460px) — раньше пятно в 620px
     соотносилось с фигурой в 380px, и после её увеличения нагрев ушёл бы
     за силуэт. */
  width: 720px;
  height: 720px;
  transform: translateY(-42%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(77, 208, 225, 0.2), transparent 68%);
  pointer-events: none;
  z-index: 0;
}

.audience-panel[data-panel="parent"]::before {
  background: radial-gradient(circle, rgba(255, 176, 74, 0.2), transparent 68%);
}

.audience-panel.is-active {
  opacity: 1;
  /* Без задержки на вход — как у Риты в #faq. visibility при этом сразу:
     иначе проявление не началось бы. */
  visibility: visible;
  transition:
          opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
          visibility 0s;
}

/* Космонавт слева в панели. Раньше здесь стоял кружок-иконка 120px с
   ракетой или звездой; по макету нужен крупный портрет во всю высоту
   карточки, обрезанный её нижним краем (overflow: hidden у .audience-panel).

   Обе картинки лежат друг на друге, как четыре портрета Риты в #faq:
   скрипт переключает is-current, а переход идёт по прозрачности. */
.audience-figure {
  position: relative;
  /* Портрет перекрывает блик (z-index у ::before — 0), а не наоборот. */
  z-index: 1;
  /* 460px — на ступень больше прежних 380px. Высота 460px, а не 520px:
     картинка ученика вписывается в бокс 460×460 по ширине (масштаб 0.774) и
     рисуется ровно 460×450 — то есть 520-пиксельный бокс был на 70px выше
     самой картинки, и над головой космонавта зияла пустая полоса. Убраны
     ровно эти 70px: панель стала 484px вместо 545px, а портрет ученика
     выглядит ровно так же, как раньше. У портрета родителя высота
     вписывается по высоте, поэтому он стал чуть меньше (было 350px по
     ширине, стало 321px) — обратная сторона того же бокса.

     object-fit: contain вписывает картинку в эти боксы, а нижний край
     панели обрезает её по margin-bottom ниже. */
  width: 460px;
  min-height: 460px;
  align-self: stretch;
  /* Минус 24px: панель обрезает фигуру снизу по своей нижней границе,
     и космонавт должен доходить ровно до неё, а не висеть над ней. */
  margin-bottom: calc(-1 * var(--rs-sp-5));
  pointer-events: none;
}

.audience-figure-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  filter: drop-shadow(0 18px 36px rgba(3, 12, 34, 0.55));
  opacity: 0;
  /* Ровно как у портретов Риты в #faq: те же 600мс и та же кривая.
     Разница в полсекунды сама по себе ни на что не смотрелась бы, но рядом
     с соседним блоком переключение читалось заметно резче — глаз сравнивает
     соседние смены и разницу в скорости замечает. */
  transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.audience-figure-img.is-current {
  opacity: 1;
}

/* Текстовая колонка панели.

   align-self: center — колонка встаёт по центру строки, а не по верху.
   Раньше стоял align-items: start у самой панели, и текст (341px на вкладке
   «Я ученик») прижимался к верхнему краю, пока портрет рядом занимал все
   520px: две колонки начинались и заканчивались на разных высотах, и панель
   читалась как пустая карточка с текстом в углу и картинкой внизу. Теперь
   у обеих колонок одна вертикальная ось — блок читается цельно, и высота
   панели не меняется: её по-прежнему задаёт колонка с портретом.

   На вкладке «Я родитель» текст выше (470px против 341px), ось смещается
   всего на 25px — почти незаметно.

   В одну колонку (≤680px) правило ничего не делает: там высота строки равна
   высоте самой колонки, центрировать нечего, и портрет остаётся над текстом,
   как и задумано. */
.audience-body {
  position: relative;
  min-width: 0;
  align-self: center;
}

.audience-panel h3 {
  color: #fff;
  /* Заголовок внутри карточки отстоит от текста на ступень 16px —
             как заголовок шага в .journey-step. */
  margin: 0 0 var(--rs-sp-4);
  font-size: 1.3rem;
  line-height: 1.2;
}

/* Внутри карточки все блоки идут через одну ступень 16px. Списку
         нужны были 32px, когда он стоял прямо под заголовком секции, —
         здесь он часть панели, поэтому отступы как у соседних блоков. */
.audience-panel .check-list {
  margin: 0 0 var(--rs-sp-4);
}

.audience-panel p {
  color: var(--rs-muted);
  margin: 0 0 var(--rs-sp-4);
}

/* Отступ сверху не нужен: он не сложился бы с отступом абзаца
         (кнопка — строчный flex-элемент, её поля не схлопываются) и дал
         бы 28px вместо 16px. Нижний отступ абзаца уже отделяет её. */
.audience-panel .btn {
  margin-top: 0;
}

/* ---------- Fancy Heading ----------
         Класс остался от старой вёрстки, где у него были свои кегль и
         начертание (44px и 600 против 55px и 700 у .h2) — из-за этого три
         секции отличались от остальных. Теперь он ничего не меняет: размер,
         интерлиньяж и трекинг берутся из общего правила h2, здесь только
         гарнитура. */
.h-fancy {
  font-family: var(--rs-font-head);
}


/* ===================== Модули Python ===================== */

/* ---------- Python Section ----------
         Заголовок с подзаголовком слева, плашки справа.

         Форма — по присланному css: прямоугольник с вырезом сверху и
         зеркальным выступом снизу в одной полосе (18–45% ширины, глубина
         --py-cut). Выступ берёт то же значение глубины, поэтому зеркало
         получается само собой — подгонять его руками не нужно.

         Скругление углов — ключевое слово round внутри самого polygon: оно
         скругляет фигуру, а не бокс, поэтому работает вместе с clip-path.
         border-radius здесь не годится: он ложится под клип, и на углах
         выреза и выступа срезался бы вместо скругления.

         Рамка сделана двумя слоями, как в примере: .python-card::before — сплошной
         цвет рамки, обрезанный по --py-shape, а .python-card-inner лежит внутри
         на отступе --py-f со своим --py-shape-in. Псевдоэлемент здесь не
         украшение, а условие для свечения: filter строит тень по силуэту
         отрисованного, а clip-path применяется после filter и срезал бы тень,
         если бы форма задавалась на самой карточке. Собственный фон карточки
         поэтому прозрачный — иначе в ореол попал бы прямоугольник.

         Высота плашки задана явно: внутренний блок лежит абсолютно и в поток
         не входит, поэтому без неё карточка схлопнулась бы в рамку. */
#python {
  --py-f: 2px;
  /* толщина рамки */
  --py-r: 6px;
  /* радиус углов: вписан прямо в polygon */
  --py-n1: 27%;
  /* вырез: левый край полосы. Узкая полоса вместо прежней (18% → 45%,
                            то есть четверть ширины): на широкой плашке
                            вырез читался как длинная ступенька поперёк
                            верхней кромки и тянул взгляд сильнее, чем
                            содержимое. Сжат почти вдвое, до 13% ширины. */
  --py-n2: 31%;
  /* вырез: конец левого скоса */
  --py-n3: 37%;
  /* вырез: начало правого скоса */
  --py-n4: 41%;
  /* вырез: правый край полосы */
  --py-cut: 12%;
  /* глубина выреза; выступ снизу берёт то же значение,
                            поэтому он автоматически зеркало выреза */
  /* Высота плашки одинаковая у карточек и кнопки: --py-h это сама
             плашка без рамки. */
  --py-h: 116px;
  --py-card-pad: 18px 26px;
  /* внутренние отступы текста */
  --py-cta-pad: 12px 26px;
  /* Отступ кнопки до плашки: тот же зазор грида плюс две рамки (2px
             каждая), иначе кнопка отвалилась бы от стопки. Держим в одном
             ритме с gap: 12 + 4 = 16px чистого воздуха и там, и там. */
  --py-cta-gap: 16px;
  /* Форма рамки: прямоугольник с вырезом сверху и выступом снизу в
             одной полосе (18–45% ширины). Скругление — ключевое слово round
             в самом polygon: скругляет фигуру, а не бокс, поэтому работает
             вместе с clip-path и не нужен border-radius (он всё равно лёг бы
             под клип, а на углах выреза и выступа давал бы срезы). */
  --py-shape: polygon(
            round var(--py-r),
            0 0,
            var(--py-n1) 0,
            var(--py-n2) var(--py-cut),
            var(--py-n3) var(--py-cut),
            var(--py-n4) 0,
            100% 0,
            100% calc(100% - var(--py-cut)),
            var(--py-n4) calc(100% - var(--py-cut)),
            var(--py-n3) 100%,
            var(--py-n2) 100%,
            var(--py-n1) calc(100% - var(--py-cut)),
            0 calc(100% - var(--py-cut))
          );
  /* Та же форма у плашки. Точки не сдвинуты: их сдвигать нельзя, иначе
             скосы выреза и выступа разъедутся и рамка на них ляжет неровно —
             отступ на --py-f и так делает внутренний блок (он на --py-f уже и
             короче рамки с каждой стороны, поэтому доли в процентах уезжают
             меньше чем на пиксель).

             Радиус на толщину рамки меньше, и тогда центры дуг совпадают: у
             рамки центр на --py-r от угла, у плашки на --py-f от её угла плюс
             радиус --py-r минус --py-f, то есть там же. Скругление поэтому
             ровно такое же, как на прямых сторонах, а не тоньше. */
  --py-shape-in: polygon(
            round calc(var(--py-r) - var(--py-f)),
            0 0,
            var(--py-n1) 0,
            var(--py-n2) var(--py-cut),
            var(--py-n3) var(--py-cut),
            var(--py-n4) 0,
            100% 0,
            100% calc(100% - var(--py-cut)),
            var(--py-n4) calc(100% - var(--py-cut)),
            var(--py-n3) 100%,
            var(--py-n2) 100%,
            var(--py-n1) calc(100% - var(--py-cut)),
            0 calc(100% - var(--py-cut))
          );
}

.python-layout {
  display: grid;
  /* Колонки уравновешены (1fr / 1fr). Раньше текст с космонавтом получал
     0.85fr — около 481px на десктопе, и картинка упиралась в ширину
     колонки: её max-width в 620px не срабатывал никогда, лишний воздух
     справа просто не доставался до неё. Теперь колонка 566px, и космонавт
     занимает её целиком — фигура стала крупнее на 18%, а плашки справа
     всё ещё вмещают тег модуля, заголовок и описание. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  /* Две колонки: текст слева, стопка плашек справа. Разрыв 48px —
             та же ступень, что и между иконкой и текстом в .audience-panel. */
  gap: var(--rs-sp-7);
  align-items: start;
}

.python-grid {
  display: flex;
  flex-direction: column;
  /* Зазор считается между боксами, а плашки разведены ещё на две рамки
             (по 2px) с каждой стороны: 12px здесь дают 16px чистого воздуха
             между плашками — ступень шкалы, как и весь воздух между блоками
             на сайте. Раньше здесь стояло 10px, а с двумя рамками выходило
             14px — значение вне шкалы. Тот же воздух в 16px держит и отступ
             кнопки (--py-cta-gap), чтобы ритм не рвался на стыке. */
  gap: 12px;
  margin: 0;
}

.python-card {
  /* Карточка только позиционирует слои и светится. Свой фон у неё
             прозрачный, и это не украшение: filter строит тень по силуэту всего
             нарисованного, поэтому любой прямоугольный фон на самой карточке
             сделал бы ореол прямоугольным. Рамку рисует ::before, плашка —
             .python-card-inner. Высота задана явно: оба слоя лежат абсолютно и
             в поток не входят, иначе карточка схлопнулась бы в одну рамку. */
  --py-frame: #5fdcf5;
  /* сплошной цвет рамки */
  --py-fill: linear-gradient(102deg, #1b7ee0 0%, #2d53d3 100%);
  position: relative;
  min-height: calc(var(--py-h) + 2 * var(--py-f));
  /* свечение повторяет контур плашки, а не прямоугольник: filter
             применяется к результату отрисовки потомков, а они уже обрезаны
             по --py-shape. На самой карточке так не вышло бы — clip-path
             применяется после filter и срезал бы тень, как и box-shadow */
  filter: drop-shadow(0 0 10px rgba(95, 220, 245, 0.6));
  transition: filter 0.3s ease, transform 0.3s ease;
}

/* Рамка: сплошной цвет, обрезанный по контуру плашки. Отдельным
         слоем именно ради свечения (см. выше) — на псевдоэлементе
         --py-frame наследуется, поэтому смена цвета на hover работает. */
.python-card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--py-frame);
  clip-path: var(--py-shape);
  transition: background-color 0.3s ease;
}

.python-card:hover {
  /* Подъём — тот же, что у кнопок: -2px. Больше ни масштаба, ни отскока —
     карточка на наведении только слегка уходит вверх, размером не меняется. */
  transform: translateY(-2px);
  filter: drop-shadow(0 0 20px rgba(95, 220, 245, 0.8));
  --py-frame: #fff;
  /* рамка на hover становится ярше */
}

/* Наведение на карточку повторяет кнопку: подъём, усиленное свечение,
   рамка белеет — и плашка светлеет, как меняет заливку кнопка.

   Светлота задана фильтром, а не сменой --py-fill: заливка карточки —
   градиент, а градиенты не переходят между собой, переключение вышло бы
   рывком. Фильтр анимируется плавно, как background-color у кнопки. */
.python-card:hover .python-card-inner {
  filter: brightness(1.12);
}

.python-card-inner {
  transition: filter 0.3s ease;
  position: absolute;
  inset: var(--py-f);
  display: flex;
  align-items: center;
  /* Тег модуля и текст внутри плашки — как две колонки: 24px */
  gap: var(--rs-sp-5);
  padding: var(--py-card-pad);
  background: var(--py-fill);
  clip-path: var(--py-shape-in);
}

/* Номер модуля на левой полке карточки.

   Раньше здесь стояла подпись «Модуль N» мелким верхним регистром с
   разрядкой: служебная метка, которая читалась как приписка и спорила с
   заголовком плашки за внимание. Теперь это сам номер — часть композиции.

   С ведущим нулём, а не просто цифра: 01/02/03/04 выровнены по разрядам,
   и ряд читается как последовательность, где порядок виден сразу, а не
   вычисляется. Собственный шрифт не задан — тот же --rs-font-head, что у
   заголовков карточек, иначе номер читался бы как подпись чужеродной
   гарнитурой. Вес у .sr-only-подписи 700 обнулён: <b> внутри нужен только
   ради семантики выделения, а жирность задаёт сам .python-num.

   Кегль 2.5rem и прозрачность 1 — проверено и оставлено как есть. Проба
   приглушить номер до 1.35rem и пустить текст от левого края дала ряд,
   где цифры стали вторичнее заголовка; здесь номер намеренно крупный и
   это работает. */
.python-card .python-tag {
  flex: 0 0 30%;
  margin: 0;
  display: flex;
  align-items: center;
  /* Прижат влево, к внутреннему отступу плашки: по центру полки он вставал
     ровно против центра текста и тянул взгляд в середину плашки. */
  justify-content: flex-start;
  font-weight: 400;
}

.python-num {
  font-family: var(--rs-font-head);
  /* 2.5rem: в высоту не в упор — текстовый блок занимает около 69px,
     номер 40px, доступно около 80px. */
  font-size: 2.5rem;
  font-weight: 400;
  line-height: 1;
  color: #fff;
  /* Свечение того же оттенка, что рамка плашки (--py-frame на карточке),
     — номер и рамка читаются как один материал. */
  text-shadow: 0 0 20px rgba(95, 220, 245, 0.55);
}

.python-card-content {
  flex: 1 1 auto;
  min-width: 0;
  /* По центру колонки — к центру номера. */
  text-align: center;
}

.python-card h3 {
  /* Заголовок и описание внутри плашки — одна смысловая пара,
             поэтому зазор между ними минимальный, 4px: тот же, что между
             тегом модуля и заголовком. */
  margin: 0 0 var(--rs-sp-1);
  color: #fff;
  font-family: var(--rs-font-head);
  font-size: 1.15rem;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.python-card-content p {
  margin: 0;
  color: rgba(255, 255, 255, 0.86);
  font-size: 0.9rem;
  line-height: 1.5;
}

/* Кнопка собрана ровно как плашка и из тех же кирпичиков: рамку рисует
         .python-cta::before, плашку — .python-cta-plate, а сама ссылка только
         позиционирует их и светится. Форма у обоих слоёв одна и та же (те же
         --py-shape и --py-shape-in), поэтому border обычной кнопки не нужен:
         он был бы прямоугольным и срезался клипом.

         Оформление (цвета, шрифт, hover) остаётся от .btn-primary, но его
         заливка и box-shadow на ссылке отменяются: оба рисуют по скруглённому
         прямоугольнику .btn, и их было бы видно в вырезе и в рамке. Внешнее
         свечение переписано на filter — он строит тень по силуэту слоёв, то
         есть повторяет контур плашки, а не бокс. */
.python-cta {
  /* то же, что и у карточки: сама ссылка прозрачна и только светится,
             рамку рисует ::before, плашку — .python-cta-plate. Прозрачность
             здесь вынужденная: иначе свечение опять бы повторяло скруглённый
             прямоугольник .btn, а не контур плашки. */
  --py-frame: var(--rs-btn-orange-stroke);
  /* цвет рамки */
  --py-fill: var(--rs-btn-orange-fill);
  position: relative;
  display: block;
  width: 100%;
  margin-top: var(--py-cta-gap);
  min-height: calc(var(--py-h) + 2 * var(--py-f));
  padding: 0;
  border: 0;
  /* перебиваем оформление .btn-primary: его заливка и внешний ореол
             живут на самой ссылке, а не на плашке */
  background: transparent;
  box-shadow: none;
  /* drop-shadow() не знает spread (только смещение, размытие и цвет),
     поэтому ореол тут без него — в отличие от box-shadow у кнопок.
     Из-за неверного четвёртого аргумента фильтр целиком отбрасывался
     и свечение плашки просто исчезало. */
  filter: drop-shadow(0 0 13px var(--rs-btn-orange-drop));
  transition: filter 0.3s ease, transform 0.12s ease-out;
}

.python-cta::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--py-frame);
  clip-path: var(--py-shape);
  transition: background-color 0.3s ease;
}

.python-cta:hover {
  /* .btn-primary:hover перекрашивает саму ссылку — отменяем заливку и
             его box-shadow (он с ":hover" в селекторе, то есть перебивает
             наш box-shadow: none; его inset-подсветка обошла бы клип по
             скруглённому прямоугольнику и стала бы видна в вырезе и рамке).
             Свечение плашки задаёт правило для .python-cta-plate ниже. */
  background: transparent;
  box-shadow: none;
  --py-fill: var(--rs-btn-orange-fill-hover);
  filter: drop-shadow(0 0 20px var(--rs-btn-orange-drop));
}

.python-cta-plate {
  position: absolute;
  inset: var(--py-f);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--py-cta-pad);
  background: var(--py-fill);
  clip-path: var(--py-shape-in);
}

.python-cta:hover .python-cta-plate {
  /* заливку на hover задаёт --py-fill на самой ссылке, чтобы плашка
             менялась вместе с рамкой */
  box-shadow: inset 0 0 10px 3px var(--rs-btn-orange-inner);
}

.python-note {
  color: var(--rs-muted);
  font-size: 0.95rem;
  /* Подзаголовок секции (как .lead и .lead-sub в других секциях):
             24px от заголовка, 32px до плашек. Раньше было 20/20. */
  margin: var(--rs-head-gap) 0 0;
}

/* Космонавт с флагом на планете под текстом колонки — по макету он
   занимает всю ширину колонки и упирается в её нижний край.

   object-fit: contain, а не cover: картинка квадратная, и при cover
   планета обрезалась бы снизу ровно там, где нужен её силуэт.

   max-width поднят с 620 до 760px. На десктопе картинку по-прежнему
   держит колонка (566px), а вот на планшете и телефоне, где .python-layout
   складывается в одну колонку, колонка шире любого из этих значений: при
   620px справа от космонавта оставалось пустое поле, и фигура на узких
   экранах выглядела заметно мельче, чем та же картинка на десктопе.

   margin-inline: auto — пока колонка у́же потолка, правило не видно
   (ширина ровно 100%), а на широком планшете, где колонка перестаёт быть
   узкой и срабатывает max-width, картинка встаёт по центру, а не
   прижимается к левому краю с пустым полем справа.

   Отступ сверху убран совсем (было var(--rs-sec-gap), 32px). Подзаголовок
   колонки короткий, и 32px воздуха перед крупной иллюстрацией съедали
   высоту блока, которая здесь и так уходит плашкам справа: картинка
   начиналась ниже заголовка секции и тянула за собой пустой отступ. */
.python-astronaut {
  display: block;
  width: 100%;
  max-width: 760px;
  height: auto;
  margin: 0 auto;
  filter: drop-shadow(0 24px 48px rgba(3, 12, 34, 0.5));
}


/* ===================== FAQ ===================== */

/* ---------- FAQ Section ----------
         Вопросы — отдельные плашки с нумерацией и плюсом/минусом, как в
         макете. Номер и знак сделаны псевдоэлементами summary: ::before —
         номер (счётчик ::before не умеет, поэтому нумерация через
         counter-reset на списке), ::after — крестик из двух линий, у которого
         при открытии исчезает вертикальная, и он становится минусом. */
/* Отступ сверху не нужен: его даёт .faq-container (32px от заголовка),
         а лишний отступ сбивал список вопросов относительно плашки с Ритой —
         они должны начинаться на одной высоте. */
.faq-grid {
  display: grid;
  /* Вопросы идут списком, поэтому ступень 12px — как у .blist
             и .check-list. */
  gap: var(--rs-sp-3);
  /* align-content: start — иначе растянутые строки растянули бы сами
             пункты: плишка отдаёт контейнеру всю высоту, и лишнее ушло бы в
             зазоры между вопросами. */
  align-content: start;
  max-width: 820px;
  counter-reset: faq;
  /* нумерация с 01 */
}

.faq-item {
  counter-increment: faq;
  background: rgba(10, 22, 45, 0.72);
  border: 1px solid var(--rs-line);
  border-radius: 18px;
  overflow: hidden;
  padding: 0;
  transition: border-color 0.25s ease;
}

.faq-item:hover {
  border-color: rgba(77, 208, 225, 0.35);
}

.faq-item summary {
  /* Отступы внутри вопроса: 16px по вертикали и 24px по горизонтали */
  padding: var(--rs-sp-4) var(--rs-sp-5);
  cursor: pointer;
  color: #fff;
  font-family: var(--rs-font-head);
  font-size: 1.05rem;
  font-weight: 600;
  user-select: none;
  display: flex;
  align-items: center;
  /* Номер — текст вопроса — плюс: текст от номера отстоит на 16px,
             плюс прижат к правому краю, поэтому зазор до него не задан. */
  gap: var(--rs-sp-4);
  /* Одинаковая высота у всех закрытых вопросов: summary резервирует
             две строки, поэтому пункт с коротким вопросом не выглядит ниже
             пункта с длинным. Текст выровнен по центру, так что номер и плюс
             тоже стоят посередине. Ниже 600px кегль уменьшен, чтобы вопросы
             по-прежнему укладывались в эти две строки. */
  line-height: 1.3;
  min-height: 84px;
  transition: background 0.28s ease;
}

.faq-item summary:hover {
  background: rgba(77, 208, 225, 0.08);
}

/* Разделитель между вопросом и ответом — тенью внутрь, а не рамкой.
       Рамка добавляла бы вопросу высоту на 1px в момент открытия, и общая
       высота списка менялась бы на этот пиксель в зависимости от того,
       какой вопрос открыт: ровно то, что резервы выше убирают. */
.faq-item[open] summary {
  background: rgba(77, 208, 225, 0.12);
  box-shadow: inset 0 -1px 0 var(--rs-line);
}

/* Номер слева — узкой колонкой, чтобы текст всех вопросов начинался
         с одной вертикали, а ответ был выровнен по нему (см. .faq-item p) */
.faq-item summary::before {
  content: counter(faq, decimal-leading-zero);
  flex: 0 0 22px;
  font-family: var(--rs-font-body);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: rgba(169, 195, 212, 0.75);
}

/* Плюс: две линии крестиком. Обе — градиентом, иначе пришлось бы ещё
         один псевдоэлемент, а он занят номером. */
.faq-item summary::after {
  content: "";
  flex: 0 0 auto;
  margin-left: auto;
  /* прижимаем плюс к правому краю плашки */
  width: 14px;
  height: 14px;
  color: var(--rs-muted);
  background:
            linear-gradient(currentColor, currentColor) center / 14px 2px no-repeat,
            linear-gradient(currentColor, currentColor) center / 2px 14px no-repeat;
}

/* Открытый вопрос: остаётся только горизонтальная линия — минус */
.faq-item[open] summary::after {
  background: linear-gradient(currentColor, currentColor) center / 14px 2px no-repeat;
}

/* Ответ раскрывается через ::details-content — штатный механизм, который
         для этого и придуман. Ниже по порядку, почему не через сам ответ.

         Через .faq-answer переход невозможен физически: у закрытого
         <details> содержимое не отрисовывается (у ::details-content стоит
         content-visibility: hidden), и переходу не с чего начинаться.
         Проверено на кадре сразу после клика — не интерполируют ни
         max-height, ни opacity, ни transform.

         Через grid-template-rows: 0fr → 1fr дорожка не схлопывалась в ноль:
         у дорожки ненулевой автоматический минимум по краю элемента, и он
         считает padding <p> — получалось 40px вместо нуля, то есть 120px
         пустоты от трёх закрытых ответов.

         Переопределить content-visibility на закрытом вопросе нельзя: тогда
         свёрнутые ответы попадут в поиск по странице и в дерево доступности.

         Остаётся ::details-content: это тот самый слой, которым браузер
         управляет видимостью, и анимировать его можно, не ломая ничего.
         Нужен interpolate-size — без него переход между height: auto и
         height: 0 невозможен. Поддержка: Chrome/Edge 131+, Safari 18+.
         Где псевдоэлемент не поддерживается, правило не применится,
         <details> откроется штатно и без анимации, а min-height ниже всё
         равно держит блок постоянным.

         Кривая и 550мс — с запасом против прежних 300мс, чтобы раскрытие
         читалось как движение, а не как щелчок. Сумма высот старого и нового
         ответов постоянна (одна и та же кривая в обе стороны), поэтому блок
         не пульсирует — при условии, что оба перехода стартуют в одном
         кадре, ради чего закрытие делается в обработчике click, а не по
         событию toggle (см. script.js). Замерено: 603 → 601 → 602 → 603. */
.faq-answer {
  min-height: 0;
}

.faq-item::details-content {
  height: 0;
  overflow: hidden;
  opacity: 0;
  transition: height 0.55s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.45s ease,
              content-visibility 0.55s allow-discrete;
}

.faq-item[open]::details-content {
  height: auto;
  opacity: 1;
  content-visibility: visible;
}

/* Постоянная высота блока FAQ. Открыт всегда ровно один вопрос, так что
         высоту секции задаёт высота ОТКРЫТОГО ответа: у четырёх вопросов
         текст разной длины, и он переносится на разное число строк. Без
         резерва высота прыгала бы на 24–73px при каждом клике, а вместе с
         ней — плашка с Ритой, которая тянется по высоте списка
         (align-items: stretch у .faq-container).

         Задаётся одним только min-height, и обязательно в обоих состояниях,
         а не только у открытого. Иначе при закрытии min-height исчезает
         мгновенно, высота:auto у ::details-content тут же пересчитывается в
         естественную (136px вместо 188), и переход стартует не от 188, а от
         136: старый ответ сжимался бы быстрее, чем новый растёт, и блок
         проваливался на 50px. Сохранённый резерв даёт одинаковые 188 в обоих
         направлениях, кривая одна, и сумма постоянна.

         Схлопывание делает ::details-content, и его height: auto считается по
         содержимому, а содержимое не ниже min-height — значит auto равен
         резерву и у всех вопросов в полосе одинаков. Проверено при
         переключении: сумма высот 138 → 141 → 162 → 181 → 188, а блок
         603 → 553 → 603 — то есть ровно тот провал, о котором сказано выше.

         Внутри полосы значение одно, поэтому оно равно естественной высоте
         САМОГО ДЛИННОГО ответа («Как проходит обучение?») в худшей точке
         полосы, плюс 2px на дробную высоту строки: без этих двух пикселей
         высота плашки гуляла на 1px. Короткие ответы получают пустое место
         под текстом — обычно одну строку.

         Границы полос сняты свипом ширины от 769 до 1920 с шагом 4px, а не
         подобраны на глаз: естественная высота длинного ответа перескакивает
         ровно там, где текст влезает в лишнюю строку, то есть в местах
         795, 843, 903 и 1003.

         Правя текст ответов — перемерь: число считается от самого длинного
         ответа и изменится вместе с текстом.

         Уже 769px секция становится одноколоночной, и резервировать нечего:
         высота плашки с Ритой задана явно (height: 400px в
         @media (max-width: 768px)) и от высоты списка не зависит. */
@media (min-width: 1004px) {
  .faq-answer { min-height: 115px; }
}

@media (min-width: 904px) and (max-width: 1003px) {
  .faq-answer { min-height: 140px; }
}

@media (min-width: 844px) and (max-width: 903px) {
  .faq-answer { min-height: 164px; }
}

@media (min-width: 796px) and (max-width: 843px) {
  .faq-answer { min-height: 188px; }
}

@media (min-width: 769px) and (max-width: 795px) {
  .faq-answer { min-height: 213px; }
}

/* Ответ рамкой отделён от заголовка вопроса тем же зазором, что и .faq-item
         между соседними вопросами: 24px padding'а сверху плюс margin у p. */
.faq-item p {
  /* 24px padding'а слева + 22px колонка номера + 16px зазор — по левому
             краю текста вопроса (те же 24/16, что у summary) */
  margin: 0;
  padding: var(--rs-sp-4) var(--rs-sp-5) var(--rs-sp-5) 62px;
  color: var(--rs-muted);
  font-size: 0.95rem;
  line-height: 1.6;
}


/* ---------- Адаптив: секции, планшет ---------- */

/* Промежуточная ширина панели аудитории: 921–1180px.

   Правило стоит здесь, а не в одноимённом медиазапросе выше (в блоке шапки):
   базовые .audience-panel и .audience-figure объявлены ниже по файлу, а
   @media не добавляет специфичности — на равных специфичностях победило бы
   позднее правило, и ужимка просто не применилась бы.

   Сама ужимка: базовая колонка 460px рассчитана на десктоп. На 940px тексту
   оставалось 352px, список из шести пунктов расползался на восемь строк, и
   панель вырастала до 607px — выше, чем на широком экране (485px). То есть
   чем шире экран, тем ниже блок, что выглядит ровно наоборот ожидаемому. С
   колонкой 360px высота панели держится 425…516px на всём диапазоне и нигде
   не обгоняет десктопную. */
@media (min-width: 921px) and (max-width: 1180px) {
  .audience-panel {
    grid-template-columns: 360px 1fr;
  }

  .audience-figure {
    width: 360px;
    min-height: 360px;
  }
}

@media (max-width: 920px) {
  .demo-grid {
    grid-template-columns: 1fr;
  }

  .sort-shelves {
    grid-template-columns: 1fr;
  }

  /* Колонки складываются на том же breakpoint, что и .rita-grid.
             Раньше секция Python оставалась в две колонки до 680px, и при
             700px левая колонка сжималась до 258px: плашки с вырезом уже не
             помещали ни тег модуля, ни заголовок. */
  .python-layout {
    grid-template-columns: 1fr;
  }

  /* Иконка в панели аудитории уменьшается, но остаётся отдельной колонкой */
  .audience-panel {
    /* 320px вместо 270px: на планшете колонок две, и портрет с прежним
       размером занимал там меньше трети панели — при увеличенной десктопной
       версии разрыв стал бы заметнее. */
    grid-template-columns: 320px 1fr;
    /* На планшете разрыв и отступы плотнее, но на тех же ступенях */
    gap: var(--rs-sp-5);
    padding: var(--rs-sp-4);
  }

  /* Портрет космонавта на планшете — по колонке, а не во всю высоту */
  .audience-figure {
    width: 320px;
    /* Как и на десктопе, бокс подогнан под картинку ученика (в 320px она
       вписывается по ширине и рисуется 320×313), а не оставлен с запасом. */
    min-height: 320px;
  }

}
@media (max-width: 680px) {
  /* Одна колонка: портрет над текстом, а не рядом с ним. Правило — на всех
     панелях, а не только на активной: неактивная лежит в той же ячейке
     и влияет на высоту блока, и при старой колонке из двух карточки
     прыгали бы друг за другом. */
  .audience-panel {
    grid-template-columns: 1fr;
  }

  .audience-panel {
    max-width: 100%;
  }

  /* Портрет встаёт по центру колонки и обрезается по нижнему краю
     панели — как на планшете, только ниже. */
  .audience-figure {
    width: 290px;
    min-height: 290px;
    justify-self: center;
  }

  /* На телефоне левая полка карточки съела бы половину текста */
  .python-card .python-tag {
    flex: 0 0 26%;
  }

  /* Номер уменьшается вместе с плашкой, но остаётся читаемым: ниже
     1.8rem он в соседней с уменьшенными отступами (--py-card-pad сжат
     до 16px) начинает налезать на заголовок. */
  .python-num {
    font-size: 1.9rem;
  }

  .python-card-inner {
    padding: var(--rs-sp-4) var(--rs-sp-4);
    gap: var(--rs-sp-3);
  }

  /* Колонки уже сложились в 920px (см. выше); на телефоне у блока
             остаётся только свой зазор между заголовком и плашками */
  .python-layout {
    gap: var(--rs-sp-5);
  }

  .final-list {
    grid-template-columns: 1fr;
    gap: var(--rs-sp-2);
  }

  .final-list li {
    font-size: 0.82rem;
    padding: var(--rs-sp-2) var(--rs-sp-3);
  }

  /* FAQ на телефоне: кегль и отступы меньше, чтобы вопросы
             по-прежнему укладывались в две строки, которые резервирует
             summary, и все пункты оставались одной высоты. */
  .faq-item summary {
    font-size: 0.95rem;
    min-height: 76px;
    padding: var(--rs-sp-4);
    gap: var(--rs-sp-3);
  }

  /* 16px padding'а + 22px колонка номера + 12px зазор — по левому
             краю текста вопроса */
  .faq-item p {
    padding: var(--rs-sp-3) var(--rs-sp-4) var(--rs-sp-4) 50px;
  }

}

/* ===================== Финальный блок ===================== */

/* ---------- Final CTA ----------
         Вся панель — это карточка из макета: синий неон, светлая рамка,
         точечная сетка, оранжевая трапеция сверху и панель справа. Сетка
         на ::before (::after панели занят… точнее, ::after карточки свободен,
         но трапеция должна лежать ПОВЕРХ неё, а потомком с overflow:hidden
         это нельзя — поэтому трапеция вынесена в .final-tab-top, как и
         панель справа: обе лежат в .final-card. */
.final {
  /* Фона нет: карточка здесь одна и почти на всю ширину секции, своего
     мелкого текста блок не содержит, и сплошной --rs-panel вокруг неё
     только отрезал картинку по краям. Космос виден целиком, стык с
     футером сходит прозрачный к прозрачному. */
  background: transparent;
  position: relative;
  overflow: clip;
}

/* Свечения за карточкой больше нет: у неё своё неоновое свечение
         (inset + внешняя тень), а пятно позади секции только мешало. */
.final-card {
  position: relative;
  width: min(860px, 100%);
  margin: 0 auto;
}

.final-panel {
  position: relative;
  z-index: 2;
  /* карточка над боковой панелью */
  /* Самая крупная карточка на сайте — и отступы в ней тоже крупные,
             ступень 48px (две ступени sp-7). Раньше было 44/40px. */
  padding: var(--rs-sp-7);
  /* Цвета те же, что у .shots-frame. В макете стоял полупрозрачный
             синий (alpha .85/.9), но панель справа должна уходить ПОД
             карточку — сквозь альфу она просвечивала бы оранжевым. */
  background: linear-gradient(180deg, #1b74d8 0%, #0c50a0 100%);
  border: 4px solid #57c7ff;
  border-radius: 20px;
  /* многослойное неоновое свечение: внутреннее и внешнее */
  box-shadow:
            inset 0 0 15px rgba(87, 199, 255, 0.6),
            0 0 25px rgba(87, 199, 255, 0.4);
  overflow: hidden;
  /* чтобы сетка точек не вылезала за скругления */
}

/* Сетка точек: 1.5px с шагом 12px, к центру угасает маской — там
         текст, и точки в него не лезут. */
.final-panel::before {
  content: "";
  position: absolute;
  inset: 15px;
  background-image: radial-gradient(rgba(255, 255, 255, 0.15) 1.5px, transparent 1.5px);
  background-size: 12px 12px;
  -webkit-mask-image: radial-gradient(circle, transparent 30%, #000 100%);
  mask-image: radial-gradient(circle, transparent 30%, #000 100%);
  pointer-events: none;
}

/* Содержимое карточки — над сеткой точек */
.final-panel > * {
  position: relative;
  z-index: 1;
}

/* Верхняя оранжевая трапеция. Цвета — те же, что у панели справа
         (.final-tab-side::before), чтобы обе скобки были из одного
         материала. top: 0 — вплотную к верхнему краю и ВЫШЕ синей рамки
         (z-index 3 перекрывает border в 4px), а не под ней. */
.final-tab-top {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 3;
  transform: translateX(-50%);
  width: 200px;
  height: 28px;
  background: linear-gradient(180deg, #ff7c36 0%, #ff5107 100%);
  clip-path: polygon(0 0, 100% 0, 88% 100%, 12% 100%);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.4);
  pointer-events: none;
}

/* Правая панель: right: -36px — на 36px выходит за карточку, а
         оставшиеся 14px (50 − 36) уходят под неё. В макете ту же задачу
         решала обёртка шире карточки; у нас карточка занимает весь
         контейнер, поэтому свес задан отрицательным отступом. */
.final-tab-side {
  position: absolute;
  right: -36px;
  top: 50%;
  z-index: 1;
  /* под карточкой (у неё z-index: 2) */
  transform: translateY(-50%);
  width: 50px;
  height: 340px;
  background: #b63d0c;
  /* тёмная подложка — из неё получается контур */
  clip-path: polygon(0 0, 60% 12%, 100% 22%, 100% 78%, 60% 88%, 0 100%);
  pointer-events: none;
}

/* Внутренняя яркая часть панели — она и рисует рамку */
.final-tab-side::before {
  content: "";
  position: absolute;
  inset: 3px 0 3px 3px;
  background: linear-gradient(90deg, #ff5107 0%, #ff7c36 100%);
  clip-path: polygon(0 0, 60% 12%, 100% 22%, 100% 78%, 60% 88%, 0 100%);
}

/* Тёмно-синяя выемка. Наполовину спрятана за карточкой: карточка
         закрывает 14px панели слева, поэтому её середина (14px от левого
         края панели) делит выемку пополам. */
.final-tab-side::after {
  content: "";
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 90px;
  background: linear-gradient(90deg, #0b346b 0%, #154c94 100%);
  border: 2px solid #1c5cb0;
  border-radius: 6px;
  box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.5);
}

.final h2 {
  color: #fff;
  font-family: var(--rs-font-head);
  margin: 0 0 var(--rs-head-gap);
}

.final .lead {
  font-size: 1.1rem;
  color: #dceaff;
  /* на синей карточке приглушённый серый не читается */
  margin: 0 0 var(--rs-sec-gap);
}

.hero-cta {
  display: flex;
  gap: var(--rs-sp-3);
  flex-wrap: wrap;
}

/* Отступы кнопок идут по той же шкале: 12/24 у обычной, 16/32 у
       крупной (кнопка «Попробовать»), 8/16 у уменьшенной. Раньше здесь
       стояли 26px, 14/34px и 18px — значения вне шкалы, и крупная
       кнопка в финальном блоке была на 2px шире такой же в шапке. */
/* --- Крупные кнопки: пропорционально большее свечение --- */
.btn-big {
  min-height: 56px;
  /* Светлая заливка: .btn-big стоит только в финальном блоке, и там
     кнопка должна быть заметнее, чем в герое. Правило ниже .btn-big
     из раздела неона, поэтому значения повторяются здесь. */
  background-color: var(--rs-btn-orange-fill-light);
  box-shadow: 0 0 13px 3px var(--rs-btn-orange-drop),
      inset 0 0 10px 3px var(--rs-btn-orange-inner);
  padding: var(--rs-sp-4) var(--rs-sp-6);
  font-size: 1.05rem;
}

.btn-big:hover {
  background-color: var(--rs-btn-orange-fill-light-hover);
  box-shadow: 0 0 20px 3px var(--rs-btn-orange-drop),
      inset 0 0 14px 3px var(--rs-btn-orange-inner);
}

/* Header-specific button sizing */
.nav .btn {
  padding: var(--rs-sp-2) var(--rs-sp-4);
  min-height: 40px;
  border-radius: 12px;
}

/* Кегль h2 в финальной панели тоже общий (правило h2 выше), поэтому
         здесь только цвет текста-подзаголовка. */
.final-panel .lead {
  color: #dceaff;
  margin-bottom: var(--rs-sec-gap);
}

/* Три «чипа» с составом пробного урока — панель перестаёт быть
         пустым текстом с двумя кнопками. Сетка, а не flex-wrap:
         три чипа всегда встают в один ровный ряд, а третий не падает вниз. */
.final-list {
  list-style: none;
  margin: 0 0 var(--rs-sec-gap);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* Чипы — группа внутри панели, поэтому ступень 12px */
  gap: var(--rs-sp-3);
}

.final-list li {
  display: flex;
  align-items: flex-start;
  /* Галочка (19px) + 8px воздуха до текста — как у .check-list */
  gap: var(--rs-sp-2);
  padding: var(--rs-sp-3) var(--rs-sp-4);
  border-radius: 14px;
  /* циановская подложка на синем сливалась, берём белый полупрозрачный */
  border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.12);
  color: #f2f9ff;
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.35;
}

.final-list li::before {
  content: "✓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 19px;
  height: 19px;
  flex: 0 0 19px;
  border-radius: 50%;
  background: #fff;
  color: #0d4a9e;
  font-size: 0.7rem;
  font-weight: 800;
}

/* ---------- FAQ Container ---------- */
.faq-wrap {
  max-width: 100%;
}

/* Заголовок FAQ по центру — он один на всю секцию, список и картинка
         уходят в две колонки, а центр держит композицию. */
#faq-title {
  text-align: center;
}

.faq-container {
  display: grid;
  /* Вопросы уже, плашка с Ритой шире: картинка в 300px иначе
             ужималась. minmax(0, 1px) — чтобы длинный вопрос не распирал
             колонку. */
  grid-template-columns: minmax(0, 1fr) 360px;
  /* Разрыв между двумя колонками секции — 48px, как в .rita-grid,
             .python-layout и .audience-panel. Здесь стояло 32px, и FAQ был
             единственной двухколоночной секцией с более узким разрывом. */
  gap: var(--rs-sp-7);
  /* stretch, а не start: плишка с Ритой всегда ровно по высоте
             списка — не торчит, когда все вопросы закрыты, и не висит
             короткой полосой, когда раскрыты все. */
  align-items: stretch;
  margin-top: var(--rs-sec-gap);
}

/* Плашка с Ритой: та же тёмная карточка, что и вопросы, но крупнее
         и с более мягкой рамкой — иначе она спорит с самим заголовком. */
.faq-visual {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Плашка тянется по высоте списка (align-items: stretch у
             .faq-container), а фигура абсолютна и в высоту плишки не входит —
             иначе она задавала бы высоту первой, и растягивала список. */
  padding: var(--rs-sp-5) var(--rs-sp-5) 0;
  min-height: 340px;
  /* на совсем короткий список */
  border-radius: 24px;
  border: 1px solid rgba(124, 156, 255, 0.22);
  background: linear-gradient(180deg, rgba(16, 32, 58, 0.9), rgba(8, 18, 36, 0.75));
  box-shadow: 0 24px 50px rgba(3, 6, 18, 0.5);
}

/* Оранжевая вкладка сверху — та же, что у карточки «Пробный урок»,
         так что блоки читаются одним стилем. */
.faq-visual::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 50%;
  z-index: 1;
  transform: translateX(-50%);
  width: 120px;
  height: 24px;
  background: linear-gradient(180deg, #ff7c36 0%, #ff5107 100%);
  clip-path: polygon(0 0, 100% 0, 88% 100%, 12% 100%);
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.4);
  pointer-events: none;
}

/* Фигура вписывается в любую высоту плишки: обёртка абсолютна и
         растягивается по inset'ам, а картинки занимают её целиком и
         object-fit: contain вписывает рисунок, ничего не обрезая и не
         растягивая. Обёртка нужна ещё и потому, что <img> — заменяемый
         элемент: растянуть его по inset'ам нельзя, а object-fit работает
         только при точных ширине и высоте. */
.faq-visual-fit {
  position: absolute;
  top: 20px;
  right: 20px;
  bottom: 0;
  left: 20px;
  z-index: 1;
  /* над оранжевой вкладкой */
  display: block;
}

/* Четыре портрета лежат друг на друге. Смена вопроса не двигает ничего:
         скрипт только переключает is-current, а картинки меняют прозрачность.
         position: absolute у каждой — иначе они встали бы в столбик и
         растянули плишку. */
.faq-visual-fit img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center bottom;
  filter: drop-shadow(0 20px 40px rgba(14, 25, 55, 0.5));
  opacity: 0;
  transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Активный портрет. Прозрачность, а не visibility и не display: иначе
         переход был бы мгновенным скачком вместо проявления.

         600мс и мягкая кривая вместо 420мс на ease: на 420мс растворение
         читалось как резкая подмена, особенно на глазах — в середине
         перехода видно две полупрозрачные фигуры, и чем дольше это
         длится, тем спокойнее воспринимается. */
.faq-visual-fit img.is-current {
  opacity: 1;
}


/* ===================== Подвал ===================== */

/* ---------- Footer ---------- */
.site-footer {
  /* Верхней линии у футера больше нет: её роль теперь выполняет рамка
     карточки ниже. Линия на всю ширину экрана поверх общего фото читалась
     как чужеродная черта, не относящаяся ни к одному блоку. */
  border-top: none;
  /* Сверху 144px (три ступени), снизу 32px.

     Раньше сверху стояло 96px (две ступени), и вместе с 32px отступа
     #try снизу зазор до футера выходил 128px — ровно как между всеми
     остальными секциями. Но подвал — не секция, а завершение страницы:
     он должен отстоять от последнего блока сильнее, чем секция от соседней,
     иначе финальная карточка и подвал читаются как один длинный блок.
     Теперь 32 + 144 = 176px: подвал заметно отделён и уходит ниже. */
  padding: calc(var(--rs-sp-7) * 3) 0 var(--rs-sp-6);
}

/* Колонки подвала — карточка на общем фоне, как .audience-panel и
   .demo-card. Раньше текст лежал прямо на фотографии: в нижней части
   кадра там светлая туманность, и светло-серый --rs-muted на ней терялся.
   Поверх плашки мелкий текст читается, а стеклянный край, как у остальных
   карточек, держит блок в общей системе.

   Поверх задаётся токеном --rs-tab-surface: он кладёт rgba(10,22,45,.72)
   поверх --rs-panel, и поэтому совпадает с фоном вкладок и карточек. */
.footer-grid {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1fr;
  /* Три узких текстовых колонки, а не два крупных блока секции, поэтому
             зазор здесь 32px, а не 48px: колонки должны остаться широкими, иначе
             адрес и подписи рвутся на три строки. */
  gap: var(--rs-sp-7);
  /* Отступа снизу больше нет: копирайт переехал внутрь карточки, и под ней
     ничего не осталось — раньше здесь стоял --rs-sp-5, отодвигавший
     отдельную строку .footer-bottom. */
  margin-bottom: 0;
  background: var(--rs-tab-surface);
  border: 1px solid var(--rs-line);
  border-radius: 20px;
  padding: var(--rs-sp-6);
  box-shadow: 0 24px 46px rgba(3, 12, 34, 0.28);
}

.footer-brand p {
  margin: 0 0 var(--rs-sp-2);
  color: var(--rs-muted);
  font-size: 0.95rem;
  line-height: 1.6;
  /* Подпись логотипа ограничена по ширине: колонка шире текста, и строка
     растягивалась во всю её длину, обрываясь одинокой точкой. */
  max-width: 34ch;
}

.footer-brand p:first-child {
  color: #fff;
  font-weight: 600;
  font-size: 1.1rem;
  max-width: none;
}

.footer-logo {
  display: block;
  width: 76px;
  height: auto;
  margin-bottom: var(--rs-sp-3);
  filter: drop-shadow(0 8px 20px rgba(0,0,0,0.45));
}

/* Обнулять отступы у <p> внутри навигации футера было не нужно: такой
         селектор (0,1,1) перебивал .footer-heading (0,1,0) целиком, и
         отступ в 12px под заголовком колонки («Связь», «Разделы») пропадал.
         Заголовок прилипал к первой ссылке — отступ 4px от её padding'а.

         Подзаголовок колонки сделан капителью с акцентной чертой — так же,
         как подписаны блоки на странице. */
.footer-heading {
  font-family: var(--rs-font-body);
  color: #fff;
  margin: 0 0 var(--rs-sp-3);
  padding-bottom: var(--rs-sp-2);
  border-bottom: 1px solid var(--rs-line);
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.footer-nav a {
  display: block;
  color: var(--rs-muted);
  text-decoration: none;
  font-size: 0.95rem;
  /* 8px вместо 4px: между пунктами появился воздух, иначе список
     читался слитным. */
  padding: var(--rs-sp-2) 0;
  transition: color 0.25s ease, transform 0.25s ease;
}

.footer-nav a:hover {
  color: var(--rs-accent);
  /* Сдвиг вправо по 4px — тот же приём, что у пунктов меню. */
  transform: translateX(4px);
}

/* Копирайт — последняя строка карточки подвала, а не отдельная полоса под
   ней. Раньше он стоял в своём блоке .footer-bottom прямо на фотографии
   страницы: в нижней части кадра там светлая туманность, и светло-серый
   --rs-muted на ней почти не читался. Теперь строка лежит на подложке
   --rs-tab-surface, в той же рамке, что и колонки.

   grid-column: 1 / -1 — строка занимает всю ширину карточки, независимо
   от того, три там колонки или одна: без этого на десктопе копирайт встал бы
   в первую колонку рядом с логотипом. Верхняя черта отделяет его от
   колонок — та же --rs-line, что и у .footer-heading. */
.footer-copy {
  grid-column: 1 / -1;
  margin: 0;
  padding-top: var(--rs-sp-5);
  border-top: 1px solid var(--rs-line);
  color: var(--rs-muted);
  font-size: 0.9rem;
}

@media (max-width: 1000px) {
  /* Декор карточки ужимаем на узких экранах: справа от .wrap есть всего
           16px, и панель в 36px вылезла бы за экран. Заодно карточка
           становится плотнее по краям. */
  .final-panel {
    /* Отступы ужимаются на ступень, но не выходят из шкалы */
    padding: var(--rs-sp-6) var(--rs-sp-5);
  }

  .final-tab-side {
    right: -20px;
    width: 24px;
    height: 260px;
  }

  /* Выемка: панель уходит под карточку на 4px, поэтому её середина —
             2px от левого края панели, и половина (5px) торчит наружу */
  .final-tab-side::after {
    left: -3px;
    width: 10px;
    height: 70px;
  }

  .final-tab-top {
    width: 150px;
    height: 22px;
  }

}
@media (max-width: 768px) {
  .final-panel {
    padding: var(--rs-sp-5) var(--rs-sp-4);
  }

  .final-list {
    grid-template-columns: 1fr;
    /* три чипа в узкую колонку не влезут */
  }

  /* Под карточку уходит 6px → середина выемки в 3px от левого края */
  .final-tab-side {
    right: -12px;
    width: 18px;
    height: 200px;
  }

  .final-tab-side::after {
    left: -2px;
  }

  .final-tab-top {
    width: 130px;
    height: 20px;
  }

  .hero-cta {
    flex-direction: column;
  }

  .btn-big {
    width: 100%;
  }

  .faq-container {
    grid-template-columns: 1fr;
  }

  /* Плашка с Ритой на всю ширину превратилась бы в широкую
             полосу, поэтому ограничиваем и центрируем. */
  /* На телефоне высота плишки идёт от содержимого, а не от списка
             (одна колонка), поэтому задаём её явно, иначе фигура впишется в
             пустоту высотой min-height. */
  .faq-visual {
    order: -1;
    width: min(320px, 100%);
    margin: 0 auto var(--rs-sp-5);
    min-height: 0;
    height: 400px;
  }

  .footer-grid {
    grid-template-columns: 1fr;
    /* На телефоне колонки идут столбиком, и внутренние отступы карточки
       32px съедали бы заметную часть ширины — на 320px это треть экрана. */
    padding: var(--rs-sp-5);
    gap: var(--rs-sp-5);
  }

}
/* ============================== Анимации ============================== */

/* Ключевые кадры не зависят от позиции в файле — их можно держать в одном месте. */

@keyframes ripple-out { from { width: 12px; height: 12px; margin: -6px 0 0 -6px; opacity: 0.9; } to { width: 72px; height: 72px; margin: -36px 0 0 -36px; opacity: 0; } }

@keyframes spark-fly { to { transform: translate(var(--dx), var(--dy)) scale(0.2); opacity: 0; } }

@keyframes planet-spin {
      to { transform: rotate(360deg); }
    }

@keyframes twinkle {
      0%, 100% { opacity: .25; transform: scale(.78); }
      50% { opacity: 1; transform: scale(1.18); }
    }

@keyframes nav-drop {
      from {
        opacity: 0;
        transform: translateY(-8px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    /* Вход шапки при загрузке. Отдельный keyframe, а не переиспользованный
       nav-drop: у того сдвиг 8px (это про раскрытие меню), шапке нужно
       въехать целиком. */
    @keyframes nav-in {
      from {
        opacity: 0;
        transform: translateY(-100%);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

@keyframes bpop {
      from {
        opacity: 0;
        transform: translateY(12px) scale(.98);
      }
      to {
        opacity: 1;
        transform: translateY(0) scale(1);
      }
    }

@keyframes blink {
      0%, 80%, 100% { opacity: .2; transform: translateY(0); }
      40% { opacity: 1; transform: translateY(-2px); }
    }

@keyframes drip {
      to { top: 110%; }
    }

/* Медленное вращение кольца-орбиты вокруг иконки */
    @keyframes orbit-spin {
      to { transform: rotate(360deg); }
    }

@keyframes pop-in {
        0% { transform: scale(1); }
        40% { transform: scale(1.03); }
        100% { transform: scale(1); }
      }

@keyframes shake {
        0%, 100% { transform: translateX(0); }
        25% { transform: translateX(-5px); }
        75% { transform: translateX(5px); }
      }

@keyframes shelf-pulse {
        0%, 100% { box-shadow: 0 0 0 0 rgba(255, 111, 59, 0); }
        50% { box-shadow: 0 0 0 5px rgba(255, 111, 59, 0.25); }
      }

/* ===================== Кнопка «наверх» =====================
   Плавающий контрол в правом нижнем углу. Материал тот же, что у стрелок
   карусели кадров: та же круглая плашка, та же обводка и то же свечение —
   иначе на тёмном фоне страницы она читалась бы как чужеродная вставка.

   Прячется не через display, а через opacity + visibility + pointer-events:
   так её видно переходом, и при этом пока она скрыта, она не перехватывает
   клики по тому, что под ней. */
.to-top {
  position: fixed;
  right: var(--rs-sp-5);
  bottom: var(--rs-sp-5);
  /* Ниже шапки (z-index 80): у шапки своя подложка, и кнопка не должна
     перелезать на неё при наложении на самом верху. */
  z-index: 70;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(0, 179, 255, 0.4);
  background: rgba(0, 18, 32, 0.72);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: #fff;
  cursor: pointer;
  box-shadow: 0 0 12px rgba(0, 179, 255, 0.35),
            inset 0 0 8px rgba(0, 179, 255, 0.2);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(14px) scale(0.9);
  transition: opacity 0.3s ease, transform 0.3s ease,
      visibility 0.3s ease, border-color 0.3s ease,
      box-shadow 0.3s ease, background-color 0.3s ease, color 0.3s ease;
}

.to-top.is-shown {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
}

.to-top:hover {
  border-color: #00b3ff;
  background: rgba(0, 45, 72, 0.92);
  box-shadow: 0 0 22px rgba(0, 179, 255, 0.8),
            inset 0 0 12px rgba(0, 179, 255, 0.45);
}

.to-top:focus-visible {
  outline: 2px solid #7cd8ff;
  outline-offset: 3px;
}

.to-top svg {
  width: 22px;
  height: 22px;
}

/* ====================== Появление блоков при прокрутке ======================
   Блок въезжает снизу и одновременно проявляется. Обе величины идут через
   CSS-переход, поэтому скрипт только вешает класс is-in — один раз на
   элемент.

   Скрытое состояние спрятано за классом .js на <html>: его ставит строчка
   в <head> до отрисовки. Если скрипты выключены, правила не применяются и
   весь текст виден как есть — анимация не должна быть условием того, что
   контент вообще существует. */
.js .reveal {
  opacity: 0;
  transform: translateY(28px);
  transition:
          opacity var(--rs-t-reveal) var(--rs-ease),
          transform var(--rs-t-reveal) var(--rs-ease);
  /* Задержка всегда идёт через переменную, а не задаётся на месте. Иначе
     элемент вне группы нельзя поставить в очередь: правила групп пишут
     transition-delay напрямую, а отдельное значение молча перебивалось бы
     ими либо, наоборот, перебивало бы их. */
  transition-delay: var(--reveal-delay, 0ms);
}

.js .reveal.is-in {
  opacity: 1;
  /* Именно none, а не translateY(0): значение none снимает сам transform, а
     вместе с ним и контекст наложения, который transform создаёт. Это
     важно для карточек наград — их картинки намеренно перекрывают
     соседние, и transform на самой карточке сложил бы всё обратно. */
  transform: none;
}

/* Поочерёдное появление внутри группы: каждая следующая карточка сдвинута
   по времени относительно предыдущей. Номера до шести — столько нужно
   самой длинной сетке на странице (четыре шага «как это работает» и
   четыре карточки модулей). */
.js .reveal-group > .reveal:nth-child(1) { --reveal-delay: 0ms; }
.js .reveal-group > .reveal:nth-child(2) { --reveal-delay: var(--rs-reveal-step); }
.js .reveal-group > .reveal:nth-child(3) { --reveal-delay: calc(2 * var(--rs-reveal-step)); }
.js .reveal-group > .reveal:nth-child(4) { --reveal-delay: calc(3 * var(--rs-reveal-step)); }
.js .reveal-group > .reveal:nth-child(5) { --reveal-delay: calc(4 * var(--rs-reveal-step)); }
.js .reveal-group > .reveal:nth-child(6) { --reveal-delay: calc(5 * var(--rs-reveal-step)); }

/* Та же лестница, но со сдвигом на шаг: первый элемент ждёт его, а не
   начинает с нуля. Нужна там, где сам контейнер проявляется первым, а его
   содержимое — следом. Единственное место сейчас — плашка футера: сначала
   появляется карточка, и только потом логотип, колонки ссылок и копирайт.
   Без сдвига плашка и её первая колонка проявлялись бы одновременно, и
   карточка читалась бы полупустой. */
.js .reveal-group--shift > .reveal:nth-child(1) { --reveal-delay: var(--rs-reveal-step); }
.js .reveal-group--shift > .reveal:nth-child(2) { --reveal-delay: calc(2 * var(--rs-reveal-step)); }
.js .reveal-group--shift > .reveal:nth-child(3) { --reveal-delay: calc(3 * var(--rs-reveal-step)); }
.js .reveal-group--shift > .reveal:nth-child(4) { --reveal-delay: calc(4 * var(--rs-reveal-step)); }
.js .reveal-group--shift > .reveal:nth-child(5) { --reveal-delay: calc(5 * var(--rs-reveal-step)); }
.js .reveal-group--shift > .reveal:nth-child(6) { --reveal-delay: calc(6 * var(--rs-reveal-step)); }

/* Кнопка в блоке Python стоит ПОСЛЕ карточек-модулей, но вне их общей
   сетки, поэтому правила группы её не касаются и она проявлялась сразу —
   при быстром скролле кнопка вылезала раньше списка. Здесь она занимает
   следующую ступень той же очереди: карточки идут на 0/90/180/270мс,
   кнопка — на 360мс. */
.python-cta.reveal {
  --reveal-delay: 360ms;
}

/* Шапка появляется один раз при загрузке, а не по прокрутке: она и так над
   сгибом. Через общий механизм появления не вышло бы — скрытое состояние
   уводит шапку на translateY(-100%) за верхний край экрана, обозреватель
   перестаёт её видеть, и она осталась бы скрытой навсегда.

   Собственная анимация вместо класса .reveal. Fill-mode не задан, поэтому
   после конца шапка возвращается к обычным стилям, и .nav.scrolled (он
   меняет только отступы и цвет линии, transform не трогает) работает как
   прежде. */
.js .nav {
  animation: nav-in var(--rs-t-reveal) var(--rs-ease);
}

/* Прерывистая линия над карточками в блоке «Как это работает» — часть того
   же блока, поэтому появляется вместе с первой карточкой. Раньше она была
   видна сразу, и пока карточки ещё всплывали, линия была в блоке
   единственным, что видно: он читался пустым.

   Привязка через :has(). Там, где :has() не поддерживается, правило просто
   не применится и линия останется видимой сразу — то есть нынешним
   поведением, без поломок вёрстки. */
.js .journey-wrap::before {
  opacity: 0;
  transition: opacity var(--rs-t-reveal) var(--rs-ease);
}

.js .journey-wrap:has(.journey-step.is-in)::before {
  opacity: 1;
}

/* ====================== Отключение анимации (prefers-reduced-motion) ======================
   Собирается здесь специально: такие переопределения должны быть последними,
   иначе обычные правила ниже по каскаду снова включат анимацию. В старой
   вёрстке часть блоков стояла выше по файлу, чем правила, которые отключение
   должно было погасить, — из-за чего оно не срабатывало. */

@media (prefers-reduced-motion: reduce) {
  /* Смена вкладки «кто читает»: та же 0.6s, что у Риты в #faq, но
     растворение сокращено — полусекундное пересечение двух текстов
     и так долго, а тут анимация движением ничего не добавляет. */
  .audience-panel,
  .audience-panel.is-active {
    transition: opacity 0.15s linear, visibility 0s linear 0.15s;
  }

  /* Кнопка «наверх» остаётся на месте и просто включается-выключается. */
  .to-top {
    transform: none;
    transition: opacity 0.3s ease, visibility 0.3s ease;
  }

  /* Вход шапки при загрузке — тоже проявление, а не движение. */
  .js .nav {
    animation: none;
  }

  /* Появление при прокрутке отменяется целиком: блоки стоят на своих
     местах сразу, без сдвига и без задержек по очереди. */
  .js .reveal,
  .js .reveal.is-in {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .js .journey-wrap::before {
    opacity: 1;
    transition: none;
  }

  /* Сцена в герое крутится постоянно. Для тех, кто отключил анимацию,
        оставляем статичную картинку: планета, орбиты и звёзды на месте. */
  .hero-orbit,
  .hero-flight,
  .hero-planet,
  .hero-star,
  .hero-twinkle {
    animation: none;
  }

  .hero-star,
  .hero-twinkle {
    opacity: .85;
  }

  .audience-btn,
  .btn,
  .demo-card,
  .quiz-option,
  .replay,
  .shots-tab {
    transition: none;
  }

  .demo-card:hover {
    transform: none;
  }

  .btn-big:hover,
  .btn:hover {
    transform: none;
  }

  .replay:hover {
    transform: none;
  }

  /* Сдвиг пунктов подвала при наведении — тот же случай: переход
     отключаем, оставляем только смену цвета. */
  .footer-nav a {
    transition: none;
  }

  .footer-nav a:hover {
    transform: none;
  }

  .chip.is-placed,
  .quiz-option.is-right,
  .quiz-option.is-wrong,
  .shelf.is-drop-target {
    animation: none;
  }

  .shots-frame .shot-slide figcaption,
  .shots-frame .shot-slide img {
    transition: none;
  }

  .faq-answer {
    transition: none;
  }

  .faq-item::details-content {
    transition: none;
  }

  /* Всё, что ниже, блок выше не покрывал, а движение оставалось.

     Разделение принципиальное: под настройку попадает ДВИЖЕНИЕ, а не любой
     переход. Короткие переходы цвета, фона и рамки на 200–300мс укачиванию не
     подвержены — гладить их не нужно, иначе интерфейс станет «сломанным на вид».
     А вот всё, что двигает, увеличивает или вращает, отключаем полностью. */

  /* Курсор: всплеск разрастается с 12 до 72px, искры разлетаются. Из
     расширяющихся кругов под курсором у людей с вестибулярными расстройствами
     начинается тошнота — это самый заметный случай на странице. */
  .cursor-fx .ripple,
  .cursor-fx .spark {
    animation: none;
  }

  /* Меню выезжает сверху, реплика чата вырастает, стрелка «листайте» ползёт
     вниз без остановки. */
  .nav.is-open .nav-links,
  .msg,
  .scroll-hint i::after {
    animation: none;
  }

  /* Прыгающие и меняющие размер элементы. Переход тут снимаем, а у hover —
     сам сдвиг: без перехода он был бы мгновенным, то есть исчез бы совсем. */
  .brand img,
  .cursor-ring,
  .slot,
  .python-card,
  .audience-btn,
  .nav-burger,
  .nav-burger span {
    transition: none;
  }

  .brand:hover img,
  .python-card:hover {
    transform: none;
  }

  /* Плавная прокрутка: якорь под шапкой проезжает пол-экрана, и при
     вестибулярном расстройстве это само по себе неприятно. */
  html {
    scroll-behavior: auto;
  }

  /* Параллакс фона: слой замирает на стартовой позиции (верх картинки у
     верхней кромки окна). Дубль скрипта, который и так не запускается
     при reduce, — на случай, если язык заметят прямо во время прокрутки. */
  .bg-parallax {
    transform: none !important;
  }

}
