/*
 * Лендинг Colloq. Палитра и шкала взяты один в один из самого продукта
 * (web/src/index.css и web/tailwind.config.js), чтобы страница и приложение
 * не разъезжались: сайт — это тот же печатный объект, что и семинар внутри.
 */

/*
 * ------------------------------------------------------------ HSE Sans ---
 *
 * Корпоративный шрифт университета, подмножеством: кириллица, латиница,
 * типографские знаки. Четыре веса — те, что страница действительно набирает;
 * Thin и Italic не берутся, потому что на ней нет ни одного места, где они бы
 * включились, а каждый лишний файл это ещё один запрос.
 *
 * swap, а не block: текст обязан быть виден с первого кадра. Подмена
 * начертания на 15-килобайтном файле происходит быстрее, чем читатель
 * добирается до конца первой строки, и это дешевле, чем пустой экран.
 *
 * 500 в стеке нет намеренно: у HSE Sans нет Medium, и правило подбора CSS
 * само возьмёт ближайший — SemiBold. Объявлять 500 файлом от 600 значило бы
 * соврать браузеру о том, что у нас есть.
 */
@font-face {
  font-family: 'HSE Sans';
  src: url('fonts/hse-sans-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'HSE Sans';
  src: url('fonts/hse-sans-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'HSE Sans';
  src: url('fonts/hse-sans-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'HSE Sans';
  src: url('fonts/hse-sans-900.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

/*
 * -------------------------------------------------------- JetBrains Mono ---
 *
 * Моноширинный — метки разделов, команды, терминал — тоже приезжает со
 * страницей, а не с fonts.googleapis.com.
 *
 * Это была единственная внешняя зависимость лендинга, и держалась она на
 * доводе «шрифт не наш, чтобы его сабсетить», который просто неверен:
 * JetBrains Mono лежит под SIL OFL 1.1 (текст рядом, fonts/JetBrainsMono-OFL.txt),
 * и хостить и резать его можно. А страницу открывают ровно из тех сетей, где
 * Google блокируется: у университетского Wi-Fi без выхода наружу и из России,
 * где внешние CDN уже перекрывали. Там терминал в герое рисовался Menlo, и
 * ширины букв в нём другие — «make up» переставал попадать в свою строку.
 *
 * Один файл на подмножество, вариативный по начертанию: 400 и 500 берутся из
 * одного и того же woff2, потому что у него ось веса. Латиница
 * предзагружается разметкой — на ней набраны все команды; кириллица и
 * остальное подтянутся по unicode-range, только если такие буквы правда
 * рисуют.
 */
@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/jetbrains-mono-latin.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/jetbrains-mono-latin-ext.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/jetbrains-mono-cyrillic.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/jetbrains-mono-cyrillic-ext.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/*
 * Подменный моноширинный — тот, что стоит, пока настоящий в пути.
 *
 * `font-display: swap` меняет шрифт на лету, и без этой пары строки
 * подпрыгивали: у JetBrains Mono строка занимает 1.32em и знак 0.6em, у Menlo —
 * 1.164em и 0.602em, у Consolas — 0.55em. Правки метрик приводят системный
 * шрифт к нашему: строка встаёт на то же место, колонка команды — на ту же
 * ширину, и подмена перестаёт быть видимой. Те же цифры стоят в приложении
 * (web/index.html): шрифт и подмена у страницы и у тетради одни.
 *
 * Семейств два, и имена у них РАЗНЫЕ. Правка ширины у Consolas своя, одной
 * цифрой оба не накрыть, — а два правила под одним именем держались бы на том,
 * чего спецификация не обещает: что делает браузер, когда у выбранного лица не
 * нашлось ни одного local(), — переберёт ли остальные лица той же семьи или
 * бросит семью целиком — его дело. Проиграй эта лотерея на Windows, и подмены
 * там не было бы вовсе — ровно на той машине, ради которой писано первое
 * правило.
 *
 * Разные имена — обычный перебор семейств, который обещан: Consolas не нашёлся
 * (мак, Linux) — берём следующее; не нашлось ни одного — остаётся ровно то,
 * что было до этой правки. Оба имени стоят подряд в --mono ниже, между
 * настоящим шрифтом и системным хвостом; порядок между ними не решает ничего —
 * обе правки приводят свой шрифт к одним и тем же метрикам.
 *
 * `local()` берёт ЛИЦО, а не семью, и по имени лица — полному или
 * постскриптовому. Замерено в Chrome на маке (ширина строки из 80 «M»):
 * 'Menlo' не находится вообще — у семьи Menlo нет лица с таким именем, есть
 * «Menlo Regular» и «Menlo-Regular». Пока здесь стояло одно 'Menlo', на маке
 * подмены не было вовсе: семья оставалась пустой, стек проваливался в
 * неисправленный ui-monospace, и строка терминала в герое на 16px теряла 2px
 * против настоящего шрифта. Поэтому у каждого шрифта перечислены все
 * написания: лишнее local() ничего не стоит, ненайденное пропускается.
 */
@font-face {
  font-family: 'JetBrains Mono Fallback Consolas';
  src: local('Consolas'), local('Consolas Regular');
  size-adjust: 109.13%;
  ascent-override: 93.47%;
  descent-override: 27.49%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'JetBrains Mono Fallback Menlo';
  src:
    local('Menlo-Regular'), local('Menlo Regular'), local('Menlo'), local('DejaVu Sans Mono'),
    local('DejaVuSansMono'), local('DejaVu Sans Mono Book'), local('Liberation Mono'),
    local('LiberationMono'), local('Liberation Mono Regular');
  size-adjust: 99.66%;
  ascent-override: 102.35%;
  descent-override: 30.1%;
  line-gap-override: 0%;
}

:root {
  /* Синь ВШЭ — земля героя и подвала. Одинакова в обеих темах продукта. */
  --brand: #0f2d69;
  --brand-2: #374b9b;
  /* Единственный яркий цвет на всю страницу: голубая метка приводки. */
  --accent: #0fa0d7;
  --accent-soft: #4fc3ee;
  /* Та же метка как текст на белом: яркая не проходит по контрасту. */
  --accent-text: #0a6e96;

  --canvas: #ffffff;
  --surface: #f3f6fb;
  --raised: #e7eef9;
  --line: #dce3ef;
  --ink: #101a33;
  --muted: #5d6b8a;
  --faint: #9ba6be;

  /* Тёмная земля терминала — ровно та, на которой работает ночная тема. */
  --term-bg: #060c1c;
  --term-line: #16244b;
  --term-ink: #9ba6be;
  --term-faint: #5e6b85;
  --term-ok: #3ec9a7;

  /*
   * HSE Sans, и страница привозит его с собой.
   *
   * Раньше он просто стоял первым в стеке — и это работало ровно у тех, у кого
   * шрифт установлен, то есть у автора и у части ФКН. Все остальные видели
   * Inter, в котором те же слова шире на десятую, и заголовок, подогнанный под
   * метрики HSE Sans, ложился на три строки вместо двух. Хуже всего, что с
   * машины, где шрифт стоит, эту поломку нельзя увидеть в принципе.
   *
   * Теперь четыре начертания лежат в /fonts и грузятся страницей — 72 КБ на
   * все, потому что подмножество оставляет кириллицу, латиницу и типографику,
   * а больше здесь ничего и не набрано. Inter остался в стеке подстраховкой на
   * случай, если файлы не доедут.
   */
  --sans: 'HSE Sans', Inter, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:
    'JetBrains Mono', 'JetBrains Mono Fallback Consolas', 'JetBrains Mono Fallback Menlo',
    ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Поле страницы: 96px на макете, ужимается до 20px на телефоне. */
  --gutter: clamp(20px, 6.7vw, 96px);

  /*
   * Движение. До этой правки на всю страницу приходился один transition и ни
   * одной кривой. Обе кривые — усиленные варианты стандартных: встроенные
   * ease-* слишком вялые, на них движение читается как задержка, а не как
   * ответ. ease-in не заведён намеренно и не должен появиться: он тормозит в
   * первый момент — ровно тогда, когда за движением следят внимательнее всего.
   */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /*
   * Длительности одним словарём, чтобы страница говорила в одном темпе.
   * Всё, что отвечает руке, живёт под 300ms; машинный набор считается
   * посимвольно и в бюджет интерфейса не входит — это объяснение, не отклик.
   */
  --t-color: 120ms; /* смена цвета: столько уже живут ссылки шапки */
  --t-press: 140ms; /* отклик на нажатие: рука не должна ждать ответа */
  --t-swap: 200ms; /* подмена текста в переключателе кресел */
  --t-out: 260ms; /* появление вывода ячейки: это событие, а не перекраска */
  --t-type: 18ms; /* один символ машинного набора в терминале */
}

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

/*
 * Правило браузера `[hidden] { display: none }` живёт в его таблице и
 * проигрывает по весу любому классу с display. На двери прячутся именно такие
 * элементы — сетка меток (grid) и карточка (flex), — и без этой строки они
 * оставались бы на экране обоими состояниями сразу.
 */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

/*
 * Три якоря в шапке до этого телепортировали страницу: щелчок мгновенно
 * подменял весь экран, и связь между «где я был» и «куда попал» терялась.
 * scroll-margin здесь не нужен — липкой шапки на странице нет, а у всех трёх
 * целей уже есть padding-top до 112px, то есть воздуха над заголовком вдвое
 * больше любого разумного margin.
 */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 28px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

h1,
h2,
h3,
p,
ul {
  margin: 0;
}

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

/* ------------------------------------------------------------- голоса */

.label {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  line-height: 18px;
  color: var(--accent-text);
  text-transform: uppercase;
}

.label--on-brand {
  color: var(--accent);
}

.h2 {
  font-size: clamp(30px, 3.4vw, 48px);
  font-weight: 900;
  line-height: 1.16;
  letter-spacing: -0.03em;
}

.lead {
  font-size: clamp(17px, 1.6vw, 22px);
  line-height: 1.55;
}

.prose {
  color: var(--muted);
}

.on-brand .prose {
  color: rgba(255, 255, 255, 0.7);
}

/*
 * Скрыто от глаза, но не от клавиатуры и не от скринридера: legend и сами
 * радиокнопки переключателя обязаны остаться в дереве доступности.
 * display:none отобрал бы у переключателя фокус и стрелки.
 */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------- секции */

.section {
  padding: clamp(64px, 7.8vw, 112px) var(--gutter);
}

.section--brand {
  background: var(--brand);
  color: #fff;
}

.section--surface {
  background: var(--surface);
}

.inner {
  max-width: 1248px;
  margin: 0 auto;
}

/*
 * Полосы со снимками уходят за поле страницы: на макете рабочий экран
 * обрезан правым и нижним краем разворота, и это кадр, а не картинка в рамке.
 */
.bleed {
  padding-left: 0;
  padding-right: 0;
  padding-bottom: 0;
}

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

.nav {
  display: flex;
  align-items: center;
  gap: 24px;
  padding-bottom: clamp(56px, 10vw, 120px);
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: none;
}

/* Марка-ссылка ведёт на эту же страницу и подчёркиваться не должна. */
a.wordmark {
  color: inherit;
  text-decoration: none;
}

.wordmark span {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.18em;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.8vw, 40px);
  margin-left: auto;
  flex: none;
}

.nav-links a {
  font-size: 14px;
  color: rgba(255, 255, 255, 0.7);
  text-decoration: none;
  transition: color var(--t-color) ease;
}

.nav-links a:focus-visible {
  color: #fff;
}

/*
 * Тач выдаёт hover по тапу: без гейта нажатый якорь остаётся подсвеченным всю
 * плавную прокрутку и читается как «я всё ещё здесь». Гейт тот же, что у
 * .cell-run:hover ниже, — политика на странице одна.
 */
@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover {
    color: #fff;
  }
}

/* --------------------------------------------------------- снимки экрана */

.shot-head {
  display: flex;
  align-items: flex-end;
  gap: clamp(24px, 6vw, 96px);
  padding: 0 var(--gutter) clamp(40px, 4.5vw, 64px);
  max-width: calc(1248px + var(--gutter) * 2);
  margin: 0 auto;
}

.shot-head > div:first-child {
  display: flex;
  flex-direction: column;
  gap: 24px;
  max-width: 660px;
}

.shot-head p {
  max-width: 428px;
  font-size: 17px;
  line-height: 28px;
}

/* Preserve the screenshot's natural proportions at every viewport width. */
.shot-frame {
  width: calc(100% - 2 * var(--gutter));
  max-width: 1248px;
  margin: 0 auto;
  border: 1px solid var(--line);
}
.shot-frame img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  border: 0;
}

@keyframes mark-swap {
  from {
    opacity: 0;
    transform: scale(0.86);
  }
}

@keyframes grid-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

.shot-caption {
  font-family: var(--mono);
  font-size: 12px;
  line-height: 20px;
  color: var(--faint);
  padding: 18px var(--gutter) 0;
  max-width: calc(1248px + var(--gutter) * 2);
  margin: 0 auto;
}

/* ---------------------------------------------------------------- шаги */

.steps-head {
  display: flex;
  align-items: baseline;
  gap: 32px;
  padding-bottom: clamp(40px, 4.5vw, 64px);
}

.steps-head .rule {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

.steps-head .meta {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap;
  flex: none;
}

.steps {
  display: flex;
  gap: 56px;
}

.step {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.step-rule {
  display: flex;
  align-items: center;
  gap: 10px;
}

.step-rule i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

.step-rule b {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

.step .label {
  letter-spacing: 0.14em;
}

.step h3 {
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: -0.015em;
  /* Две строки заголовка держат прозу трёх колонок на одной линии. */
  min-height: 72px;
}

.step p {
  font-size: 17px;
  line-height: 28px;
  color: var(--muted);
}

/* ------------------------------------------------------------- свойства */

.feat-head {
  display: flex;
  align-items: flex-start;
  gap: clamp(24px, 6vw, 96px);
  padding-bottom: clamp(36px, 4vw, 56px);
}

.feat-head h2 {
  max-width: 660px;
}

.feat-head p {
  max-width: 428px;
  font-size: 17px;
  line-height: 28px;
  color: var(--muted);
  padding-top: 8px;
}

.feat-row {
  display: flex;
  gap: 56px;
  border-top: 1px solid var(--line);
}

.feat {
  flex: 1 1 0;
  min-width: 0;
  padding: 36px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.feat-title {
  display: flex;
  align-items: center;
  gap: 10px;
}

.feat-title svg {
  flex: none;
}

.feat-title h3 {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.feat p {
  font-size: 16px;
  line-height: 26px;
  color: var(--muted);
}

/* ---------------------------------------------------------- живая ячейка */

/*
 * Две ячейки одного документа и одно ядро на двоих. Единственное место на
 * странице, где продукт можно потрогать рукой, а не прочитать про него:
 * запустите свою ячейку первой — и получите NameError, потому что переменную
 * создаёт не тот, кто её читает. Объяснение здесь делает не движение, а
 * порядок нажатий; движение только не даёт выводу выскочить из ниоткуда.
 * Рамка без радиуса и без тени: на сером это документ, а не карточка.
 */
.kernel {
  margin-bottom: clamp(36px, 4vw, 56px);
  padding: 20px clamp(16px, 2vw, 24px) 18px;
  background: var(--canvas);
  border: 1px solid var(--line);
}

.kernel-head {
  display: flex;
  align-items: baseline;
  gap: 8px 20px;
  flex-wrap: wrap;
  padding-bottom: 14px;
}

.kernel-head .label {
  flex: none;
}

/*
 * Единственная фраза, объясняющая, что произошло. Две строки зарезервированы
 * заранее: пять реплик по 58–75 знаков пересекают границу «одна строка / две»
 * на планшетных ширинах, и без резерва шапка ядра толкала бы обе ячейки вниз
 * ровно тогда, когда читатель тянется ко второй, — тот же рывок, ради которого
 * этажом ниже стоит .cell-out { min-height: 36px }.
 * Подмена — та же идиома, что у .swhat: уход 120ms, приход 160ms с задержкой
 * в 100ms, чтобы глаз увидел чистое поле между репликами, а не две наложенные.
 */
.kernel-hint {
  font-size: 15px;
  line-height: 24px;
  color: var(--muted);
  flex: 1 1 260px;
  min-width: 0;
  min-height: 48px;
  transition: opacity 160ms var(--ease-out) 100ms;
}

.kernel-hint.is-out {
  opacity: 0;
  transition: opacity 120ms var(--ease-out);
}

.cell {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto;
  align-items: start;
  padding: 18px 0;
  border-top: 1px solid var(--line);
}

.cell-who {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
  padding-bottom: 10px;
}

/*
 * Промпт проходит In [ ] → In [*] → In [1]. Цвет меняется за те же 120ms,
 * что и единственная существующая на странице смена цвета — ссылки шапки;
 * второй идиомы для одного и того же события заводить незачем.
 */
.cell-prompt {
  grid-column: 1;
  grid-row: 2;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 26px;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
  transition: color var(--t-color) ease;
}

.cell[data-run='running'] .cell-prompt {
  color: var(--accent-text);
}

.cell-src {
  grid-column: 2;
  grid-row: 2;
  margin: 0;
  font-family: var(--mono);
  font-size: 14px;
  line-height: 26px;
  color: var(--ink);
  white-space: pre;
  overflow-x: auto;
}

.cell-run {
  grid-column: 3;
  grid-row: 1 / span 2;
  align-self: start;
  justify-self: end;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--accent-text);
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition:
    transform var(--t-press) var(--ease-out),
    border-color var(--t-color) ease;
}

/* Настоящая кнопка обязана отвечать на нажатие раньше, чем придёт результат. */
.cell-run:active {
  transform: scale(0.97);
}

/*
 * ...но только тогда, когда нажатие что-то делает. Для занятой и для уже
 * стоящей в очереди ячейки press() выходит вхолостую, и отклик обязан
 * замолчать вместе с ней: кнопка, которая ужимается и не делает ничего,
 * отчитывается за действие, которое было отброшено. Состояние уже размечено
 * атрибутом data-run, править скрипт не нужно.
 */
.cell[data-run='running'] .cell-run,
.cell[data-run='queued'] .cell-run {
  color: var(--muted);
}

.cell[data-run='running'] .cell-run:active,
.cell[data-run='queued'] .cell-run:active {
  transform: none;
}

/* На странице до сих пор не было ни одного видимого состояния фокуса —
   новому контролу оно обязательно. */
.cell-run:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
}

/* Тач по кнопке не должен оставлять её в «наведённом» состоянии. */
@media (hover: hover) and (pointer: fine) {
  .cell-run:hover {
    border-color: var(--accent-text);
  }
}

/*
 * Место под вывод занято всегда. Раскрытие высоты сдвинуло бы вторую ячейку —
 * ту самую, на которую читатель смотрит и куда сейчас потянется, — то есть
 * произвело бы ровно тот рывок, ради которого движение сюда и ставится.
 * Строка вывода не переносится, а прокручивается: так высота не зависит от
 * ширины экрана и не меняется в момент появления текста.
 */
.cell-out {
  grid-column: 2 / -1;
  grid-row: 3;
  min-height: 36px;
  padding-top: 10px;
  overflow-x: auto;
}

.cell-out p {
  font-family: var(--mono);
  font-size: 13px;
  line-height: 26px;
  color: var(--ink);
  white-space: pre;
  opacity: 0;
  transform: translateY(4px);
  /* transition, а не keyframes: при быстрых повторных нажатиях переход
     переприцеливается с текущей точки, кейфрейм начал бы с нуля.
     Базовая длительность — уход, и он короче прихода: приход вывода это
     событие (--t-out, 260ms), а уход — ответ системы, он обязан щёлкать.
     Скрипт стирает текст ровно через 160ms, то есть после того, как строка
     выцвела, а не посреди собственного фейда. */
  transition:
    opacity 160ms var(--ease-out),
    transform 160ms var(--ease-out);
}

.cell[data-run='done'] .cell-out p,
.cell[data-run='error'] .cell-out p,
.cell[data-run='queued'] .cell-out p {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--t-out) var(--ease-out),
    transform var(--t-out) var(--ease-out);
}

/* Ошибка и очередь — не результат: тот же моноширинный голос, но приглушённый. */
.cell[data-run='error'] .cell-out p,
.cell[data-run='queued'] .cell-out p {
  color: var(--muted);
}

/*
 * --muted, а не --faint: оговорка о том, что блок постановочный, не имеет
 * права быть слабейшим текстом на странице. #9ba6be на белом даёт 2.4:1 —
 * ниже порога AA; #5d6b8a даёт 5.4:1.
 */
.kernel-note {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 12px;
  line-height: 20px;
  color: var(--muted);
}

/* ---------------------------------------------------------------- финал */

.finale {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  text-align: center;
}

.finale h2 {
  font-size: clamp(32px, 4.6vw, 64px);
  font-weight: 900;
  line-height: 1.09;
  letter-spacing: -0.035em;
  max-width: 900px;
}

/* Кнопки и сноска под ними — одна связка: сноска объясняет, почему кнопки мертвы. */
.finale-call {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

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

.foot {
  display: flex;
  align-items: flex-start;
  gap: clamp(32px, 6vw, 96px);
  padding: 56px var(--gutter);
  background: var(--brand);
  color: #fff;
}

.foot-inner {
  max-width: 1248px;
  margin: 0 auto;
  width: 100%;
  display: flex;
  align-items: flex-start;
  gap: clamp(32px, 6vw, 96px);
  flex-wrap: wrap;
}

.foot-about {
  flex: 1 1 320px;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.foot-about p {
  font-size: 14px;
  line-height: 22px;
  color: rgba(255, 255, 255, 0.62);
}

.foot-col {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 180px;
}

.foot-col .label {
  font-size: 11px;
}

.foot-col span {
  font-size: 14px;
  color: rgba(255, 255, 255, 0.82);
}

.foot-col .dim {
  color: rgba(255, 255, 255, 0.5);
}

.foot-col .host {
  font-family: var(--mono);
  font-size: 13px;
  color: rgba(255, 255, 255, 0.62);
}

/* Единственная ссылка в подвале, по которой можно написать автору. Выглядит
   как соседние строки и подчёркивается только под курсором: подвал — это
   справка, а не набор кнопок. */
.foot-col a.host {
  text-decoration: none;
  transition: color var(--t-color) ease;
}

.foot-col a.host:hover {
  color: rgba(255, 255, 255, 0.95);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ------------------------------------------------------- узкие экраны */

/*
 * Дверь теряет афишу раньше остальной страницы — на 1024px, ровно там же, где
 * её теряет продукт (Poster объявлен как `hidden w-3/5 lg:flex`). Рубеж не
 * подобран под макет: ниже него сорок процентов ширины перестают вмещать
 * карточку метки одной строкой, и она разваливается на три этажа — аватар,
 * фраза, кнопка, — вместо того чтобы читаться одной. Форме нужна вся ширина
 * раньше, чем странице нужен телефонный режим.
 */

@media (max-width: 1100px) {
  .steps,
  .feat-row {
    flex-direction: column;
    gap: 0;
  }

  .step {
    padding: 28px 0;
    border-bottom: 1px solid var(--line);
  }

  .step h3 {
    min-height: 0;
  }

  .feat {
    padding: 28px 0;
    border-bottom: 1px solid var(--line);
  }

  .feat-row {
    border-top: none;
  }

  .feat-row:first-of-type {
    border-top: 1px solid var(--line);
  }

  .feat-head,
  .shot-head,
  .deploy {
    flex-direction: column;
    gap: 32px;
    align-items: flex-start;
  }

  /*
   * Ниже 1100px натуральный масштаб перестаёт быть кадром и становится
   * обрезком: при 900px в коробке 420px от снимка оставалось 58% ширины и
   * 47% высоты — четверть площади, — а панель оракула, названная в alt,
   * не попадала в кадр вовсе. Снимок показывается целиком.
   */
  .shot-frame {
    height: auto;
    padding-left: 0;
  }

  .shot-frame img {
    width: 100%;
    height: auto;
    border-left: none;
    border-right: none;
  }
}

@media (max-width: 700px) {
  body {
    font-size: 16px;
  }

  /* Линейка между заголовком и «≈ 40 секунд» схлопывается в ноль, и подпись
     повисает сбоку от двух строк. Проще положить её под заголовок. */
  .steps-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .steps-head .rule {
    display: none;
  }

  /* Кнопка уходит под ячейку и получает полноценную цель для пальца.
     58px — ширина «In [ ]» плюс воздух: при 48px промпт вставал вплотную
     к коду и читался как его часть. */
  .cell {
    grid-template-columns: 58px minmax(0, 1fr);
  }

  .cell-run {
    grid-column: 1 / -1;
    grid-row: 4;
    justify-self: stretch;
    margin-top: 14px;
    min-height: 44px;
  }
}

/*
 * Reduced motion — это «меньше и мягче», а не «ноль». Прежний блок глушил
 * подряд все transition на странице, вместе с подсветкой ссылок шапки: она
 * помогает понять состояние и ничего не двигает. Гребёнка ниже гасит только
 * то, что действительно ездит, — длительности анимаций, их повторы и плавную
 * прокрутку; всё остальное снимается точечно.
 *
 * Именно 1ms, а не animation:none: конечный кадр у набора, аватаров и ответа
 * терминала задан через forwards, и none оставил бы их на первом кадре —
 * то есть невидимыми навсегда.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }

  /* Всё, что ездит по экрану, снимается поимённо. */
  .cell-run:active {
    transform: none;
  }

  /* Нажатие всё равно обязано быть слышно: вместо масштаба отвечает рамка.
     И так же молчит там, где нажатие ничего не делает. */
  .cell-run:active {
    border-color: var(--accent-text);
  }

  .cell[data-run='running'] .cell-run:active,
  .cell[data-run='queued'] .cell-run:active {
    border-color: var(--line);
  }

  /* Один селектор на все состояния вывода — и результат, и ошибку, и очередь. */
  .cell-out p {
    transform: none !important;
    transition: opacity 120ms linear !important;
  }
}

/* ------------------------------------------------------------- лекция --- */

/*
 * Шапка секции: метка НАД заголовком, всё по одной левой кромке.
 *
 * Была колонкой слева, как в «Зачем», — но там под шапкой идут строки с
 * такой же колонкой номеров, а здесь под ней лид и карточки от края. Заголовок
 * оказывался сдвинут вправо один на всю секцию, и это читалось как ошибка
 * вёрстки, а не как сетка.
 */
.sec-head {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.sec-lead {
  max-width: 760px;
  padding-top: 20px;
}

/*
 * Три карточки без рамок: информация лежит прямо на поверхности, а линейка
 * сверху отбивает их друг от друга — тот же приём, что у «Что ломается».
 */
.lec-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 40px);
  padding-top: clamp(36px, 4vw, 56px);
}

.lec-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}

.lec-card p:last-child {
  font-size: 16px;
  line-height: 26px;
  color: var(--muted);
}

.lec-note {
  padding-top: clamp(28px, 3vw, 40px);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 22px;
  color: var(--faint);
}

@media (max-width: 900px) {
  .lec-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Landing, September 2026: three teaching modes, fewer repeated sections. */
.skip-link {
  position: fixed;
  left: 20px;
  top: -100px;
  z-index: 100;
  padding: 12px 20px;
  background: white;
  color: var(--brand);
}
.skip-link:focus {
  top: 12px;
}
a:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 5px;
}
.on-brand a:focus-visible {
  outline-color: white;
}
.hero h1 {
  font-weight: 900;
  letter-spacing: -0.04em;
}
.hero-head {
  display: flex;
  flex-direction: column;
}
.hero {
  padding-top: 32px;
  padding-bottom: 0;
}
.hero .nav {
  padding-bottom: 0;
  min-height: 48px;
}
.hero-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(40px, 6vw, 88px);
  padding: 88px 0 76px;
}
.hero-head {
  padding: 0;
  gap: 26px;
}
.hero h1 {
  max-width: none;
  font-size: clamp(44px, 5.3vw, 76px);
  line-height: 1.04;
}
.hero .lead {
  max-width: 580px;
  color: #d8e1f2;
  font-size: 21px;
  line-height: 1.5;
}
.label--on-brand {
  color: #80d6f5;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px 26px;
  padding-top: 6px;
}
.action-primary {
  display: inline-flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  min-height: 52px;
  padding: 13px 20px;
  background: white;
  color: var(--brand);
  font-size: 16px;
  line-height: 24px;
  font-weight: 600;
  text-decoration: none;
  transition: background 120ms;
}
.action-primary span {
  font-size: 23px;
  font-weight: 400;
}
.action-primary:hover {
  background: var(--raised);
}
.action-primary--dark {
  background: var(--brand);
  color: white;
}
.action-primary--dark:hover {
  background: var(--brand-2);
}
.action-text {
  display: inline-flex;
  gap: 14px;
  align-items: center;
  min-height: 44px;
  color: white;
  text-decoration: none;
  font-size: 15px;
}
.action-text:hover {
  text-decoration: underline;
  text-underline-offset: 5px;
}
.release-note {
  color: #b4c5e4;
  font-size: 14px;
  line-height: 22px;
}
.lesson-index {
  background: var(--canvas);
  color: var(--ink);
  align-self: center;
}
.lesson-index-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 24px 28px 18px;
  border-bottom: 1px solid var(--line);
}
.lesson-mark {
  font: 14px var(--mono);
  color: var(--muted);
}
.lesson-index > a {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) 20px;
  gap: 12px;
  align-items: start;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding: 24px 28px;
  transition: background 120ms;
}
.lesson-index > a:hover {
  background: var(--surface);
}
.lesson-number {
  font: 13px/28px var(--mono);
  color: var(--accent-text);
}
.lesson-index strong {
  display: block;
  font-size: 25px;
  line-height: 30px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.lesson-index small {
  display: block;
  margin-top: 6px;
  font-size: 15px;
  line-height: 22px;
  color: var(--muted);
}
.lesson-arrow {
  color: var(--brand);
  font-size: 23px;
}
.lesson-index-foot {
  padding: 20px 28px;
  font-size: 13px;
  line-height: 21px;
  color: var(--muted);
  background: var(--surface);
}
.hero-bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 28px;
  padding: 23px 0;
  border-top: 1px solid #385386;
  color: #d8e1f2;
  font-size: 14px;
}
.hero-bottom span::before {
  content: '+';
  color: #80d6f5;
  margin-right: 12px;
  font-family: var(--mono);
}
.nav-links a {
  color: #d8e1f2;
}
.seminar-section {
  padding-top: 88px;
  padding-bottom: 64px;
}
.seminar-section .shot-head {
  padding-bottom: 40px;
}

#lekciya {
  background: white;
}
#lekciya .sec-head {
  align-items: start;
}
#lekciya .sec-lead {
  max-width: 750px;
}
.lec-card {
  border-top-color: var(--line);
}
.lec-note {
  color: var(--muted);
}
.council-section {
  background: var(--surface);
}
.council-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 44px 64px;
  align-items: start;
}
.council-copy {
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.new-tag {
  margin-left: 8px;
  padding: 4px 7px;
  background: var(--brand);
  color: white;
  font-size: 10px;
  letter-spacing: 0.06em;
  vertical-align: middle;
}
.council-points {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.council-points li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 12px;
  font-size: 16px;
  line-height: 25px;
}
.council-points li > span {
  font: 12px/25px var(--mono);
  color: var(--accent-text);
}
.council-ai {
  font-size: 15px;
  line-height: 24px;
  color: var(--muted);
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.council-example {
  margin: 0;
  min-width: 0;
  background: white;
  border: 1px solid var(--line);
}
.council-example > figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 24px;
  border-bottom: 1px solid var(--line);
}
.council-example > figcaption .label {
  font-size: 10px;
  letter-spacing: 0.09em;
}
.example-dot {
  height: 7px;
  width: 7px;
  background: #0c7a64;
  border-radius: 50%;
  flex: none;
}
.council-task {
  padding: 28px 24px;
}
.council-task .label {
  font-size: 11px;
}
.council-task h3 {
  font-size: 24px;
  line-height: 30px;
  margin: 10px 0;
  letter-spacing: -0.02em;
}
.council-task p {
  color: var(--muted);
  font-size: 15px;
  line-height: 24px;
}
.council-example code {
  font-family: var(--mono);
  font-size: 0.85em;
}
.council-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 24px;
  padding: 16px 24px;
  background: var(--surface);
  border-block: 1px solid var(--line);
  font-size: 13px;
  color: var(--muted);
}
.council-stats b {
  font: 23px/30px var(--mono);
  color: var(--brand);
  margin-right: 4px;
}
.solution-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) 65px;
  gap: 10px;
  padding: 22px 24px;
  border-bottom: 1px solid var(--line);
  align-items: start;
}
.solution-count {
  font: 19px/26px var(--mono);
  color: var(--brand);
}
.solution-row strong {
  display: block;
  font-size: 15px;
  line-height: 26px;
  font-weight: 600;
}
.solution-row code {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  line-height: 20px;
  overflow-wrap: anywhere;
  color: var(--muted);
}
.solution-status {
  font-size: 11px;
  line-height: 26px;
  color: #0c7a64;
  text-align: right;
}
.solution-status--error {
  color: #a93f20;
}
.solution-detail {
  margin: 0 24px;
}
.solution-detail summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 0;
  cursor: pointer;
  color: var(--brand);
  font-size: 14px;
  line-height: 22px;
  list-style: none;
}
.solution-detail summary::-webkit-details-marker {
  display: none;
}
.solution-detail summary span {
  font: 22px var(--mono);
}
.solution-detail[open] summary span {
  transform: rotate(45deg);
}
.solution-detail > p {
  font-size: 15px;
  line-height: 24px;
  color: var(--muted);
  padding-bottom: 20px;
}
.example-note {
  padding: 14px 24px;
  background: var(--surface);
  color: var(--muted);
  font-size: 12px;
  line-height: 20px;
}
.council-kernel {
  grid-column: 1 / -1;
  max-width: 950px;
  padding-left: 20px;
  border-left: 2px solid var(--accent-text);
  font-size: 15px;
  line-height: 25px;
  color: var(--muted);
}
.council-kernel strong {
  color: var(--ink);
}
#kak {
  padding-bottom: 56px;
}
#kak .steps-head .meta {
  font-size: 12px;
}
#chto .feat-head h2 {
  max-width: 650px;
}
#chto .feat-row .feat p {
  font-size: 16px;
  line-height: 26px;
}
.faq-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: 64px;
}
.faq-layout .h2 {
  margin-top: 24px;
}
.faq-intro {
  margin-top: 24px;
  max-width: 310px;
}
.faq-list {
  border-top: 1px solid var(--line);
}
.faq-list details {
  border-bottom: 1px solid var(--line);
}
.faq-list summary {
  position: relative;
  padding: 23px 36px 23px 0;
  font-size: 19px;
  font-weight: 600;
  line-height: 28px;
  cursor: pointer;
  list-style: none;
}
.faq-list summary::-webkit-details-marker {
  display: none;
}
.faq-list summary::after {
  content: '+';
  position: absolute;
  right: 0;
  top: 23px;
  color: var(--accent-text);
  font: 23px/28px var(--mono);
}
.faq-list details[open] summary::after {
  content: '−';
}
.faq-list details > p {
  padding: 0 28px 22px 0;
  font-size: 16px;
  line-height: 27px;
  color: var(--muted);
}
.deploy {
  align-items: start;
}
.deploy .h2 {
  margin: 24px 0;
}
.deploy-release {
  margin-top: 28px;
  font-size: 15px;
  line-height: 25px;
  color: #b4c5e4;
}
.setup-sheet {
  border-top: 1px solid #385386;
  padding-top: 24px;
}
.setup-sheet ol {
  list-style: none;
  padding: 0;
  margin: 18px 0 0;
}
.setup-sheet li {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: 16px;
  padding: 22px 0;
  border-bottom: 1px solid #385386;
}
.setup-sheet li > span {
  font: 13px/26px var(--mono);
  color: #80d6f5;
}
.setup-sheet strong {
  font-size: 19px;
  font-weight: 600;
}
.setup-sheet p:not(.label) {
  font-size: 15px;
  color: #c5d3ed;
  margin-top: 5px;
  line-height: 24px;
}
.finale {
  flex-direction: row;
  text-align: left;
  align-items: start;
  gap: 64px;
}
.finale > div {
  flex: 1;
  min-width: 0;
}
.finale h2 {
  margin-top: 24px;
  font-size: clamp(32px, 3.6vw, 52px);
  line-height: 1.12;
}
.finale-call {
  padding-top: 42px;
  align-items: start;
  gap: 0;
}
.finale-call .action-primary {
  margin-top: 24px;
}

.foot-col a {
  color: #d8e1f2;
  text-decoration: none;
}
.foot-col a:hover {
  text-decoration: underline;
}
@media (max-width: 1100px) {
  .hero-layout {
    gap: 36px;
    padding: 64px 0;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  }
  .hero h1 {
    font-size: clamp(40px, 5.3vw, 64px);
  }
  .hero .lead {
    font-size: 18px;
  }
  .lesson-index > a,
  .lesson-index-head {
    padding-inline: 20px;
  }
  .lesson-index strong {
    font-size: 22px;
  }
  .council-layout {
    gap: 32px;
  }
  .solution-row {
    padding: 18px 16px;
    grid-template-columns: 26px minmax(0, 1fr);
  }
  .solution-status {
    grid-column: 2;
    text-align: left;
    line-height: 18px;
  }
  .faq-layout {
    gap: 40px;
  }
}
@media (max-width: 760px) {
  .hero-layout,
  .council-layout,
  .faq-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .hero-layout {
    padding-top: 52px;
    gap: 40px;
  }
  .hero h1 {
    font-size: clamp(40px, 8.5vw, 62px);
  }
  .hero-head {
    gap: 22px;
  }
  .hero .lead {
    max-width: 550px;
  }
  .hero .nav {
    flex-wrap: wrap;
    gap: 20px;
  }
  .hero .nav-links {
    display: flex;
    flex-wrap: wrap;
    flex: auto;
    width: 100%;
    margin: 0;
    gap: 8px 22px;
  }
  .hero .nav-links a {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    font-size: 13px;
  }
  .hero-bottom {
    display: grid;
    gap: 6px;
  }
  .lesson-index > a {
    padding-block: 20px;
  }
  .lesson-index small {
    margin-top: 3px;
  }
  .lesson-index-foot {
    padding: 16px 20px;
  }
  .hero-actions {
    gap: 8px 20px;
  }
  .action-primary {
    font-size: 14px;
    gap: 16px;
    padding-inline: 16px;
  }
  .seminar-section {
    padding-top: 64px;
    padding-bottom: 40px;
  }

  .council-copy h2 br:last-child {
    display: none;
  }
  .council-example {
    margin-top: 6px;
  }
  .solution-row {
    grid-template-columns: 26px minmax(0, 1fr) 62px;
  }
  .solution-status {
    grid-column: auto;
    text-align: right;
    line-height: 26px;
  }
  .solution-row code {
    font-size: 10px;
  }
  .council-task,
  .council-example > figcaption {
    padding-inline: 18px;
  }
  .council-stats {
    gap: 14px;
    padding-inline: 18px;
  }
  .council-stats b {
    font-size: 21px;
  }
  .faq-intro {
    max-width: 440px;
  }
  .faq-layout {
    gap: 32px;
  }
  .finale {
    flex-direction: column;
    gap: 24px;
  }
  .finale-call {
    padding-top: 0;
    max-width: none;
    width: 100%;
  }
  .finale h2 {
    max-width: none;
  }
  .setup-sheet {
    margin-top: 12px;
  }
}

@keyframes av-in {
  from {
    opacity: 0;
    transform: translateX(-10px) scale(0.94);
  }
}

/* Lecture: explanation beside a slide with ink annotations. */
.lecture-explain {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 56px;
  align-items: center;
  margin-top: 48px;
}
.lecture-explain .lec-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 24px;
  margin: 0;
}
.lecture-explain .lec-card {
  padding-top: 18px;
  gap: 10px;
}
.lecture-preview {
  margin: 0;
  min-width: 0;
}
.lecture-screen {
  background: #060c1c;
  padding: 24px;
}
.lecture-paper {
  position: relative;
  background: white;
  aspect-ratio: 16 / 10;
  padding: 28px;
  display: flex;
  flex-direction: column;
}
.lecture-paper > .label {
  font-size: 9px;
  letter-spacing: 0.1em;
}
.lecture-paper h3 {
  font-size: clamp(20px, 2.2vw, 30px);
  line-height: 1.2;
  margin-top: 12px;
  font-weight: 900;
}
.lecture-formula {
  font-family: var(--mono);
  font-size: clamp(18px, 2vw, 28px);
  color: var(--ink);
  margin-top: 36px;
  white-space: nowrap;
  letter-spacing: -0.05em;
}
.lecture-formula sub {
  font-size: 0.6em;
}
.lecture-formula > span {
  background: #fff0ad;
}
.lecture-annotation {
  width: 100%;
  height: auto;
  margin-top: -4px;
}
.lecture-slide-foot {
  display: flex;
  justify-content: space-between;
  margin-top: auto;
  padding-top: 12px;
  font: 10px/16px var(--mono);
  color: var(--muted);
}
.lecture-preview figcaption {
  font-size: 13px;
  line-height: 22px;
  color: var(--muted);
  padding-top: 14px;
}
.deploy {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 64px;
}
@media (max-width: 1100px) {
  .lecture-explain {
    gap: 32px;
  }
  .lecture-screen {
    padding: 16px;
  }
  .lecture-paper {
    padding: 20px;
  }
  .lecture-formula {
    margin-top: 24px;
  }
}
@media (max-width: 760px) {
  .lecture-explain,
  .deploy {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
  }
  .lecture-formula {
    font-size: clamp(16px, 4.5vw, 28px);
    margin-top: 24px;
  }
  .lecture-paper {
    padding: 18px;
  }
  .lecture-paper h3 {
    font-size: clamp(18px, 5vw, 28px);
  }
}

/* Captions and execution labels stay readable on white surfaces. */
.shot-caption,
.cell-who,
.cell-prompt {
  color: var(--muted);
}
.shot-caption {
  font-size: 14px;
  line-height: 24px;
  max-width: 950px;
}
.cell-who {
  font-size: 12px;
}

/* Restored collaborative cursors and animated room presence. */
.live {
  position: relative;
}

.cursors {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cur {
  position: absolute;
  inset: 0;
}

.cur-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 2px;
  background: var(--tint);
  transform: translate(-40px, -40px);
  opacity: 0;
  transition:
    transform 420ms var(--ease-out),
    opacity var(--t-out) var(--ease-out);
}

.cur.is-on .cur-bar {
  opacity: 1;
}

.cur-tag {
  position: absolute;
  left: -1px;
  bottom: 100%;
  margin-bottom: 5px;
  padding: 2px 6px;
  background: var(--tint);
  color: var(--cur-ink, #fff);
  font-family: var(--mono);
  font-size: 10px;
  line-height: 14px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: 2px;
  opacity: 0;
  transition: opacity var(--t-out) var(--ease-out);
}

.cur.is-say .cur-tag {
  opacity: 1;
}

.cur-sel u {
  position: absolute;
  background: var(--tint);
  opacity: 0.18;
  text-decoration: none;
  border-radius: 1px;
  animation: sel-in 200ms var(--ease-out) both;
}

@keyframes sel-in {
  from {
    opacity: 0;
  }
}

.room-line {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.avatars {
  display: flex;
  align-items: center;

  position: relative;
  flex: none;
}

.room-say {
  font-family: var(--mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

  min-width: 0;
  opacity: 0;
  transition: opacity var(--t-out) var(--ease-out);
}

.room-say.is-on {
  opacity: 1;
}

.room-say.is-gone {
  color: rgba(255, 255, 255, 0.5);
}

.avatars span {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid var(--brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  flex: none;
}

.avatars span + span {
  margin-left: -10px;
}

.avatars span {
  transition: transform var(--t-out) var(--ease-out);
}

.avatars span.is-out {
  animation: av-out var(--t-out) var(--ease-out) both;
  pointer-events: none;
}

@keyframes av-out {
  to {
    opacity: 0;
    transform: scale(0.72);
  }
}

.avatars span.is-new {
  animation: av-in 280ms var(--ease-out) both;
}

.avatars.is-in span {
  animation: av-in 280ms var(--ease-out) both;
}

.avatars.is-in span:nth-child(1) {
  animation-delay: 80ms;
}

.avatars.is-in span:nth-child(2) {
  animation-delay: 140ms;
}

.avatars.is-in span:nth-child(3) {
  animation-delay: 200ms;
}

.avatars.is-in span:nth-child(4) {
  animation-delay: 260ms;
}

.avatars.is-in span:nth-child(5) {
  animation-delay: 320ms;
}

.room-count {
  font-size: 15px;
  line-height: 24px;
  color: #d8e1f2;
  flex: none;
}
.room-line {
  flex-wrap: wrap;
  row-gap: 6px;
}
.room-say {
  min-width: 90px;
}
@media (max-width: 420px) {
  .room-count {
    font-size: 13px;
  }
  .room-say {
    flex-basis: 100%;
    height: 16px;
  }
  .avatars span {
    width: 32px;
    height: 32px;
    font-size: 10px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .avatars.is-in span {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/*
 * =========================================================== два языка ===
 *
 * Переключатель — тот же, что в документации (site/docs/docs.css): две
 * метки моноширинным, точка между ними, текущий язык подчёркнут. Отличие
 * одно и вынужденное: здесь он стоит на синем, поэтому цвета берутся из
 * пары ссылок шапки, а не из --muted, который на этой земле не читается.
 *
 * Текущий язык — не ссылка: вести со страницы на неё же незачем, а
 * скринридер получает aria-current и не предлагает переход.
 */
.lang-switch {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
  padding-left: clamp(4px, 1vw, 16px);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  line-height: 1;
}

.lang-option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 32px — не украшение: это минимальная мишень под палец, а метка
     шириной в две буквы сама по себе даёт около двадцати. */
  min-width: 32px;
  min-height: 32px;
  padding: 0 4px;
  color: rgba(255, 255, 255, 0.7);
  text-decoration: none;
  transition: color var(--t-color) ease;
}

.lang-option[aria-current] {
  color: #fff;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 6px;
}

.lang-option:focus-visible {
  color: #fff;
}

@media (hover: hover) and (pointer: fine) {
  a.lang-option:hover {
    color: #fff;
  }
}

.lang-sep {
  color: var(--brand-2);
}

/*
 * ========================================================== установка ===
 *
 * Блок сразу под героем: три команды и три ссылки. Терминал тёмный — та же
 * земля, на которой работает терминал продукта (--term-bg), потому что это
 * и есть терминал, а не картинка про него.
 */
.install-section {
  padding-top: clamp(56px, 6vw, 88px);
  padding-bottom: clamp(48px, 5vw, 72px);
}

.install-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

.install-copy {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.install-copy .prose {
  font-size: 17px;
  line-height: 28px;
  color: var(--muted);
  max-width: 480px;
}

.install-term {
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 1.6vw, 22px);
  min-width: 0;
  padding: clamp(22px, 2.8vw, 36px) clamp(18px, 2.8vw, 40px);
  background: var(--term-bg);
}

/*
 * Строка команды целиком выделяется мышью и копируется как есть: приглашение
 * «$» лежит в ::before, а не в тексте, — иначе в буфер уезжает доллар, и
 * первая же вставка в чужой терминал ломается.
 */
.install-term code {
  display: block;
  font-family: var(--mono);
  font-size: clamp(13px, 1.1vw, 16px);
  line-height: 26px;
  color: #fff;
  overflow-x: auto;
  white-space: nowrap;
}

.install-term code::before {
  content: '$ ';
  color: var(--term-ok);
}

.install-term p {
  padding-left: 18px;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 20px;
  color: var(--term-faint);
}

.install-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding-top: clamp(28px, 3.4vw, 44px);
}

.action-ghost {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  min-height: 52px;
  padding: 13px 20px;
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 16px;
  line-height: 24px;
  font-weight: 600;
  text-decoration: none;
  transition:
    border-color 120ms,
    background 120ms;
}

.action-ghost span {
  color: var(--faint);
}

@media (hover: hover) and (pointer: fine) {
  .action-ghost:hover {
    border-color: var(--accent-text);
    background: var(--surface);
  }
}

/* Требования уезжают к правому полю и отбиваются линейкой — тот же приём,
   что у шапки шагов (.steps-head). */
.install-req {
  display: flex;
  align-items: center;
  gap: 24px;
  flex: 1 1 260px;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 22px;
  color: var(--faint);
}

.install-req::before {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}

/*
 * ============================================================= сцены ===
 *
 * Пять анимированных SVG вместо снимков экрана. Каждый лежит на белой
 * плите с рамкой: собственная подложка сцены — это --surface, и на
 * секции того же цвета она растворяется без рамки.
 *
 * Ширина картинки ограничена 1040px при колонке в 1248: на всю колонку
 * сцена шириной 880 растягивается в полтора раза, и подписи внутри неё
 * становятся крупнее прозы самой страницы — то есть страница начинает
 * кричать собственной иллюстрацией.
 */
.scene-band {
  margin: 0;
  padding-top: clamp(36px, 4.5vw, 64px);
}

.scene-plate {
  width: 100%;
  max-width: 1248px;
  margin: 0 auto;
  padding: clamp(14px, 2.4vw, 32px) clamp(12px, 5vw, 104px);
  background: var(--canvas);
  border: 1px solid var(--line);
}

/* В полосе, вынесенной за поле страницы (.bleed), поля берёт на себя сама
   плита: у секции их нет. */
.bleed .scene-plate {
  width: calc(100% - 2 * var(--gutter));
}

.scene-plate img {
  display: block;
  width: 100%;
  max-width: 1040px;
  height: auto;
  margin: 0 auto;
}

/* Подсказка про боковую прокрутку нужна только там, где прокрутка есть.
   Коробку она берёт ту же, что плита: в полосе за полем страницы (.bleed)
   у секции полей нет, и подпись иначе прижимается к самому краю экрана. */
.scene-hint {
  display: none;
  width: 100%;
  max-width: 1248px;
  margin: 0 auto;
  padding-top: 12px;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 20px;
  color: var(--faint);
}

.bleed .scene-hint {
  width: calc(100% - 2 * var(--gutter));
}

/* Под лекцией три карточки объясняют ровно те три экрана, что нарисованы
   в сцене, — поэтому она идёт сразу под ними, а не сбоку. */
.lecture-cards {
  padding-top: clamp(32px, 4vw, 56px);
}

@media (max-width: 760px) {
  /*
   * Переключатель уходит на первую строку к марке: на этой ширине .nav
   * переносится, и .nav-links занимает вторую строку целиком — без order
   * языки оказались бы на третьей, ниже навигации.
   */
  .hero .lang-switch {
    order: 0;
    margin-left: auto;
    padding-left: 0;
  }
  .hero .nav-links {
    order: 1;
  }

  .install-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Кнопки переносятся по две в ряд, требования уезжают на свою строку — и
     линейка перед ними схлопывается в огрызок длиной в палец. Убираем. */
  .install-req::before {
    display: none;
  }

  /*
   * Сцена шириной 880 в колонку 350 сжимает подписи до пяти пикселей —
   * это уже не рисунок, а текстура. Поэтому на телефоне плита становится
   * лентой: картинка держит 760px и листается вбок.
   */
  .scene-plate {
    padding: 10px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .scene-plate img {
    width: 760px;
    max-width: none;
  }
  .scene-hint {
    display: block;
  }
}

/* Команда внутри прозы — моноширинным, но в цвет окружающего текста:
   это имя команды, а не выделенный кусок кода. */
.release-note code,
.setup-sheet code {
  font-family: var(--mono);
  font-size: 0.92em;
  color: inherit;
}

/* Заметка про общее ядро переехала из сетки под сцену — сетка больше не
   отбивает её от соседа сверху, и отступ нужен свой. */
.council-section .scene-band + .inner .council-kernel {
  margin-top: clamp(28px, 3vw, 40px);
}
