/* V1 — Кинетическая сборка. Гамма, сетка, плиты.
   Токены: см. variants/v1/README.md. Основной hue 250. */

:root {
  /* ══ ПАЛИТРА (25.10.2026, рекомендации для клиента) ═════════════════════
     Вместо пастели Oura и синего: белый фон, светлый тёплый серый для
     отдельных разделов, графитовые заголовки, тёмно-серый текст, тёплый
     оранжевый для главных кнопок и акцентов, светлый персиковый — для одного
     важного блока (запись на консультацию). Прежние гаммы — в истории git.

     Как распределять: большая часть страницы белая, заголовки графитовые;
     оранжевым — основные кнопки, отдельные цифры и мелкие детали; целые абзацы
     оранжевым не красим. Литералов цвета за пределами этого блока нет. */
  --graphite:     #252E33;  /* заголовки; фон тёмного футера. 13.84 к белому */
  --graphite-raised:#2E383E;/* приподнятая поверхность на тёмном */
  --text:         #535D63;  /* основной текст: 6.74 на белом, 6.13 на сером */
  --text-dim:     #646E75;  /* второстепенный текст: 5.5 на белом, 4.9 на сером */
  --orange:       #E8750A;  /* главные кнопки и акценты */
  --orange-deep:  #C9620A;  /* hover / pressed */
  --orange-ink:   #A9520B;  /* оранжевый БУКВАМИ на светлом: 4.9 на сером, 5.4 на белом.
                               Сам #E8750A как мелкий текст порог 4.5 не берёт (3.0) */
  --orange-soft:  #F29A4E;  /* оранжевый буквами на графите: 6.27 */
  --peach:        #FFF0E2;  /* светлый персиковый: один важный блок */
  --white:        #FFFFFF;
  --warm:         #F5F4F1;  /* светлый тёплый серый: фон отдельных разделов */
  /* Золото эксклюзива (26.10.2026): приглушённое, «шампань», без блеска и
     градиентов — светлая заливка, золотая рамка, буквы тёмным золотом. */
  --gold:         #B8955A;  /* рамка: 2.8 к белому, декоративная — смысл несёт текст */
  --gold-soft:    #F4ECDC;  /* заливка */
  --gold-ink:     #7A5A1E;  /* буквы: 5.4 на заливке */

  /* Совместимость: эти имена использует вёрстка (подписи на фото, интро). */
  --ink:          var(--graphite);
  --ink-raised:   var(--graphite-raised);
  --bone:         var(--warm);
  --surface:      var(--white);
  --surface-raised: var(--white);

  --danger-on-ink:     #F0476B;  /* 4.6 на графите */
  --danger-on-surface: #B3261E;  /* 6.5 на белом */

  /* Сетка — посадочные места, а не колонки. */
  --mod: 96px;
  --gut: 8px;
  --pad: 16px;

  /* Один ease на всё направление: быстрый ход, жёсткая посадка, овершута нет. */
  --snap: cubic-bezier(.2, .9, .1, 1);

  /* Шрифт — Manrope (SIL OFL 1.1, Fontsource), 400 / 600 / 700 / 800, тонких
     начертаний нет намеренно. Арабские гарнитуры стоят вторыми: арабских букв
     у Manrope нет, и браузер берёт их из следующего семейства. */
  --font-display: 'Manrope', 'Noto Kufi Arabic', system-ui, sans-serif;
  --font-body: 'Manrope', 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Типографика (компьютер / телефон), плавно между 375 и 1440 px:
     главный заголовок 72 / 38, заголовки разделов 44 / 29, карточки 22 / 20,
     текст 18 / 16, кнопки и меню 16, ключевые цифры 48 / 34. */
  --fs-h1:   clamp(2.25rem, 1.6rem + 3.3vw, 4.5rem);
  --fs-h2:   clamp(1.75rem, 1.35rem + 1.9vw, 2.75rem);
  --fs-h3:   clamp(1.25rem, 1.18rem + .25vw, 1.375rem);
  --fs-body: clamp(1rem, .93rem + .35vw, 1.125rem);
  --fs-ui:   1rem;
  --fs-num:  clamp(2.125rem, 1.75rem + 1.6vw, 3rem);

  /* Направление письма числом: 1 — слева направо, −1 — справа налево (арабский). */
  --dir: 1;
}
[dir='rtl'] { --dir: -1; }

/* ══ ПОВЕРХНОСТЬ ══════════════════════════════════════════════════════════
   Один набор имён, два значения — выбор делает data-theme на секции.
   :root несёт ТЁМНЫЙ набор: он совпадает с последней секцией страницы
   (графитовый футер) и обслуживает body и оверскролл. */
:root,
[data-theme='dark'] {
  --bg:         var(--graphite);
  --bg-raised:  var(--graphite-raised);
  --fg:         var(--warm);                                          /* 12.58 */
  --fg-strong:  var(--white);
  --fg-dim:     color-mix(in srgb, var(--warm) 68%, var(--graphite));
  --line:       color-mix(in srgb, var(--warm) 40%, var(--graphite));
  --line-soft:  color-mix(in srgb, var(--warm) 18%, var(--graphite));

  --action:       var(--orange);
  --action-hover: var(--orange-deep);
  --action-edge:  var(--orange);
  --action-text:  var(--orange-soft);
  --on-action:    var(--white);

  --accent-rare:      var(--warm);
  --accent-rare-text: var(--warm);
  --on-accent-rare:   var(--graphite);

  --focus-dark:  var(--orange-soft);
  --focus-light: var(--orange-ink);
  --focus:       var(--focus-dark);
  --danger: var(--danger-on-ink);

  --shadow: none;
  --shadow-lift: none;
}

/* ── СВЕТЛАЯ ПОВЕРХНОСТЬ ────────────────────────────────────────────────── */
[data-theme='light'] {
  --bg:        var(--surface);
  --bg-raised: var(--surface-raised);
  --fg:        var(--text);
  --fg-strong: var(--graphite);
  --fg-dim:    var(--text-dim);
  --line:      color-mix(in srgb, var(--graphite) 45%, var(--surface));
  --line-soft: color-mix(in srgb, var(--graphite) 13%, var(--surface));
  --action-edge: var(--orange);
  --action-text: var(--orange-ink);
  --accent-rare:      var(--graphite);
  --accent-rare-text: var(--graphite);
  --on-accent-rare:   var(--white);
  --focus:     var(--focus-light);
  --danger:    var(--danger-on-surface);
  --shadow:      0 1px 0 color-mix(in srgb, var(--graphite) 4%, transparent),
                 0 10px 28px -20px color-mix(in srgb, var(--graphite) 40%, transparent);
  --shadow-lift: 0 2px 6px -2px color-mix(in srgb, var(--graphite) 35%, transparent),
                 0 18px 32px -22px color-mix(in srgb, var(--graphite) 50%, transparent);
}

/* ── ФОН РАЗДЕЛОВ ─────────────────────────────────────────────────────────
   Без data-tint секция белая. warm — светлый тёплый серый (через раз),
   peach — светлый персиковый, только у записи на консультацию. Карточки на
   сером и персиковом — белые. Старые имена оттенков оставлены как синонимы. */
[data-tint='warm'], [data-tint='beige'], [data-tint='grey'],
[data-tint='grey-light'], [data-tint='sage'] { --surface: var(--warm); }
[data-tint='peach'] { --surface: var(--peach); }

[data-theme] {
  background: var(--bg);
  color: var(--fg);
}


@media (min-width: 720px) { :root { --pad: 24px; } }
@media (min-width: 1100px) { :root { --pad: 40px; } }

/* Шрифт — Manrope (SIL OFL 1.1, из Fontsource / Google Fonts), субсеты cyrillic + latin,
   вендорено локально: assets/fonts/manrope-<вес>-<субсет>.woff2. Браузер тянет только
   нужный диапазон и только те веса, что встретились на странице. */

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

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-400-latin.woff2') format('woff2');
  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: 'Manrope';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-600-latin.woff2') format('woff2');
  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: 'Manrope';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-700-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-700-latin.woff2') format('woff2');
  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: 'Manrope';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-800-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../../../assets/fonts/manrope-800-latin.woff2') format('woff2');
  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;
}

/* ── Арабский (14.10.2026) ─────────────────────────────────────────────────
   Noto Kufi Arabic 700 — под заголовки: широкий геометрический куфи, ближайший
   по характеру к Unbounded. IBM Plex Sans Arabic 400/600 — под текст, пара к Golos.
   Обе — SIL OFL 1.1, взяты из Fontsource (Google Fonts) и урезаны pyftsubset до
   блока Arabic U+0600–06FF плюс ZWNJ/ZWJ/метки направления; OpenType-функции
   (формы букв в начале, середине и конце слова) сохранены целиком. Латиница и
   цифры на арабской странице идут из Unbounded и Golos, как и везде. */
@font-face {
  font-family: 'Noto Kufi Arabic';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../../assets/fonts/noto-kufi-arabic-700-arabic.woff2') format('woff2');
  unicode-range: U+0600-06FF, U+200C-200F, U+2010-2011, U+FD3E-FD3F;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../../../assets/fonts/ibm-plex-sans-arabic-400-arabic.woff2') format('woff2');
  unicode-range: U+0600-06FF, U+200C-200F, U+2010-2011, U+FD3E-FD3F;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../../../assets/fonts/ibm-plex-sans-arabic-600-arabic.woff2') format('woff2');
  unicode-range: U+0600-06FF, U+200C-200F, U+2010-2011, U+FD3E-FD3F;
}

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

/* Скроллом при перерисовке каталога управляем мы: якорь считается в catalog.js.
   Браузерный scroll anchoring делает то же самое независимо и асинхронно — и правки
   складываются, унося страницу на сотни пикселей. Отключаем его на документе. */
body { overflow-anchor: none; }
#cards-mount, #cost-mount, .cards, .plot { overflow-anchor: none; }

/* Фон body обязан совпадать с ПОСЛЕДНЕЙ секцией страницы — сейчас это тёмный
   футер, поэтому здесь тёмный набор с :root и подпорок не нужно. Значение
   продублировано в <meta name="theme-color">: разъедутся — на iOS при оттягивании
   страницы снизу вылезет чужой цвет, а сверху перекрасится строка состояния.
   Меняешь тему футера — меняй и meta. */
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 var(--fs-body)/1.55 var(--font-body);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.015em; margin: 0; color: var(--fg-strong); }
/* Жирным — заголовки, цифры и короткие ключевые фразы: они графитовые, как заголовки. */
b, strong { font-weight: 700; color: var(--fg-strong); }
/* Переносы: заголовки выравниваются по строкам, у абзацев последняя строка не
   остаётся из одного слова. Там, где браузер этого не умеет, просто обычный перенос. */
h1, h2, h3, .section__note, .about__h3, .meets__title { text-wrap: balance; }
p, li, figcaption, blockquote { text-wrap: pretty; }
h3 { font-size: var(--fs-h3); line-height: 1.2; }
p, ul, ol { margin: 0; }
ul { list-style: none; padding: 0; }

/* Фокус берёт --focus, а тот переключается вместе с поверхностью: на тёмном
   оранжевый (6.90 к фону), на светлом --orange-deep (3.68). Одним цветом обе
   поверхности не закрыть — --orange на светлом даёт 2.52 при пороге 3:1.

   Зазор в 3 px обязателен и держится смещением, а не тенью. Оранжевое кольцо
   вокруг оранжевой кнопки без зазора слилось бы с заливкой; смещение показывает
   в просвете фон родителя и разводит их. Тенью это делать нельзя: box-shadow
   у нас уже занят — им нарисован inset-индикатор раскрытой строки графика,
   а .row это кнопка, и фокус затёр бы её состояние. */
:where(a, button, input, textarea, select, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ── Плита ────────────────────────────────────────────────────────────────
   Структуру держат заливки и воздух, а не линейки. Радиус намеренно ненулевой.

   Глубина на тёмном — это сдвиг фона на --bg-raised плюс линия в 1px, а не тень:
   тень на чёрном не читается вовсе, а --bg-raised к --ink это всего 1.08, то есть
   сам по себе он поверхностью не выглядит. Линию несёт border, тень включается
   только в светлых секциях — там --shadow перестаёт быть none. */
.plate {
  background: var(--bg-raised);
  border: 1px solid var(--line-soft);
  border-radius: 2px;
  box-shadow: var(--shadow);
}

.label {
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.3;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--fg-dim);
}

/* Логические inset/padding/margin в этом файле — ради арабской версии: справа
   налево они зеркалятся сами, а слева направо значат ровно то же, что left/right.
   Увод за край — тоже в сторону начала строки: в RTL отрицательный left дал бы
   горизонтальную прокрутку, а уход вправо прокрутки не создаёт. */
.skip {
  position: absolute; inset-inline-start: -9999px; top: 0;
  background: var(--action); color: var(--on-action); padding: 12px 16px; z-index: 10;
}
.skip:focus { inset-inline-start: 0; }

/* ── Первый экран ─────────────────────────────────────────────────────────
   Поле сборки во весь вьюпорт: не «текст слева, медиа справа». */
.hero {
  position: relative;
  min-height: 100svh;
  padding: var(--pad);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: calc(var(--gut) * 3);
  overflow: clip;
}

.hero > * { position: relative; z-index: 2; min-width: 0; }

.hero__top { display: flex; justify-content: space-between; align-items: start; gap: var(--gut); flex-wrap: wrap; }
/* Вордмарк в позиции шапки. Он же цель FLIP из интро, поэтому золото здесь
   не украшение, а продолжение: интро сажает на это место золотую «Selena».
   Это единственная доля золота на первом экране — больше на нём её нет. */
.hero__mark {
  font-family: var(--font-display); font-size: .8125rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent-rare-text);
}
.hero__mid { align-self: center; display: grid; gap: calc(var(--gut) * 3); }
/* Логотип: на телефоне — над заголовком у правого края, на широком экране —
   отдельная колонка справа от заголовка и буллетов, по центру по вертикали. */
.hero__logo { display: block; justify-self: end; width: clamp(128px, 36vw, 170px); container-type: inline-size; }
/* На телефоне крупного знака нет: он стоит маленькой иконкой в верхней панели,
   рядом с языками (.topbar__logo), иначе на первом экране много пустого места. */
@media (max-width: 899px) { .hero__logo { display: none; } }
.hero__logo img { display: block; width: 100%; height: auto; }
/* Надпись под шапкой. Кисточка висит справа ниже полей шапки, поэтому надпись
   поднята под поля (отрицательный отступ, в долях ширины знака) и сдвинута
   влево от кисточки. Кегли — от ширины знака (cqi): знак масштабируется целиком. */
.logo__word {
  display: grid; justify-items: center;
  margin-top: -19%; padding-inline-end: 17%;
  font-family: var(--font-display); font-weight: 800; line-height: 1; letter-spacing: -0.03em;
}
.logo__selena { font-size: 21cqi; color: var(--orange); }
.logo__educates { margin-top: 1.5cqi; font-size: 10.5cqi; font-weight: 700; letter-spacing: -0.01em; color: var(--graphite); }
@media (min-width: 900px) {
  .hero__mid { grid-template-columns: minmax(0, 1fr) auto; column-gap: calc(var(--gut) * 6); align-items: center; }
  .hero__mid > :not(.hero__logo) { grid-column: 1; }
  .hero__logo { grid-column: 2; grid-row: 1 / span 2; width: clamp(240px, 24vw, 380px); }
}

h1 {
  /* Unbounded заметно шире системного гротеска: и кегль, и мера подобраны под него. */
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.1;
  text-transform: uppercase;
  max-width: 17ch;
  /* Страховка: если в фазе 3 придёт слово длиннее «сопровождением», оно
     перенесётся, а не раздует грид-трек и не уедет под overflow: clip. */
  overflow-wrap: break-word;
}
h1 .w { display: inline-block; }

.bullets { display: grid; gap: 6px; max-width: 52ch; color: var(--fg); font-size: var(--fs-body); line-height: 1.5; }
.bullets li { padding-inline-start: 18px; position: relative; }
.bullets li::before {
  content: ''; position: absolute; inset-inline-start: 0; top: .55em;
  width: 8px; height: 8px; background: var(--action); border-radius: 1px;
}

.hero__bottom { display: flex; justify-content: space-between; align-items: end; gap: calc(var(--gut) * 2); flex-wrap: wrap; }

.cta {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--action); color: var(--on-action); text-decoration: none;
  font-weight: 600; font-size: var(--fs-ui);
  padding: 18px 24px; border-radius: 2px; cursor: pointer;
  font-family: var(--font-body);
  /* Контур обязателен: на светлой секции сама заливка --orange даёт к фону 2.52
     и порог 3:1 для границ компонентов не проходит. На тёмном --action-edge
     совпадает с заливкой и рамки не видно — правило одно на обе поверхности. */
  border: 1px solid var(--action-edge);
}
.cta:hover { background: var(--action-hover); border-color: var(--action-hover); }
.cta svg { flex: none; }

.stats { display: flex; gap: var(--gut); flex-wrap: wrap; }
.stat { padding: 14px 18px; min-width: 128px; }
.stat b { display: block; font-family: var(--font-display); font-weight: 800; font-size: var(--fs-num); line-height: 1.05; letter-spacing: -0.02em; color: var(--orange); font-variant-numeric: tabular-nums; }
.stat span { display: block; margin-top: 6px; font-size: .875rem; line-height: 1.4; color: var(--fg); max-width: 22ch; }

/* ── Секции ───────────────────────────────────────────────────────────────── */
.section { padding: calc(var(--gut) * 8) var(--pad); }
.section__head { display: grid; gap: 8px; margin-bottom: calc(var(--gut) * 3); max-width: 62ch; }
/* Маркер — float, а не inline-block. Кинетика режет заголовок SplitText'ом
   на строки-блоки, и inline-маркер оставался один в собственной строке над
   заголовком: квадрат сверху, текст ниже. Float обтекается первой строкой
   в обоих случаях — и разрезанной, и цельной (без JS, reduced-motion), —
   так что заголовок выглядит одинаково. Высота float меньше строки, поэтому
   вторую строку он не задевает. */
.section__head h2::before {
  content: ''; float: inline-start;
  width: .38em; height: .38em; margin: .3em 0 0; margin-inline-end: .34em;
  background: var(--action-text); border-radius: 1px;
  transition: opacity .35s var(--snap), transform .35s var(--snap);
}
/* До входа заголовка (класс ставит scroll.js) маркер спрятан и чуть сжат,
   проявляется вместе с первой строкой. */
.section__head h2.is-pending::before { opacity: 0; transform: scale(.4); }
h2 { font-size: var(--fs-h2); line-height: 1.15; }
.section__note { color: var(--fg); font-size: var(--fs-body); line-height: 1.55; }

/* ── Маршрут ──────────────────────────────────────────────────────────────
   Второй экран тёмного блока (D2): стоит сразу за #hero тем же тёмным фоном,
   первый экран не тронут. Класс свой, не .section — см. комментарий в index.html.
   Отступ сверху меньше, чем у секции: это продолжение первого экрана, а не новая
   глава. От статов его отделяет волосяная линия на той же левой кромке.

   Линия маршрута — золотая волосяная, та же, что прочерчивается в интро. На этом
   экране золота больше нет: вордмарк первого экрана к этому месту уже ушёл вверх.
   Узел шага — оранжевый квадрат, идиома маркеров .bullets и .dirs, и номер.
   Линия собрана из отрезков .route__seg, по одному на шаг: так её можно
   прочерчивать по шагам. Раскладка:
     ≥1100 px — четыре шага в ряд, линия сквозь все четыре;
     720–1099 — 2 × 2, линия по верху каждой строки;
     <720     — вертикаль: линия слева, узлы на ней, итоговая строка — последняя точка.
   Начальных скрытых состояний здесь нет: их ставит только кинетика (scroll.js),
   поэтому без неё и при reduced-motion маршрут сразу в финальном кадре. */
.route { --route-gap: calc(var(--gut) * 3); padding: calc(var(--gut) * 5) var(--pad) calc(var(--gut) * 8); }
.route::before {
  content: ''; display: block; height: 1px;
  margin-bottom: calc(var(--gut) * 5);
  background: var(--line-soft);
}

/* «ОБРАЗОВАТЕЛЬНОГО» — шестнадцать букв одним словом, капсом в Unbounded. Замер:
   13.53 em с трекингом h2. В общем кегле h2 на 360 px это 325 px в строке 328 —
   формально влезает, но запас 3 px, а Safari рисует текст на пару пикселей шире.
   Поэтому кегль именно этого заголовка ограничен шириной строки, делённой на
   ширину слова с запасом ~5% (14.2): на 360 px это ~23 px и слово в 312 px,
   на 320 px — ~20 px. Слово встаёт целиком, переносов внутри слова нет.
   С ~373 px ограничение больше общего кегля и не действует, дальше — общий clamp. */


/* ol, а не ul: общий сброс списков в начале файла касается только ul, отсюда
   свой — иначе браузер оставляет ol отступ 40 px. */
.route__steps { display: grid; gap: var(--route-gap); padding: 0; list-style: none; }
.route__step { position: relative; display: grid; gap: 12px; align-content: start; }

.route__node {
  position: relative; display: flex; align-items: center; height: 12px;
  transform-origin: 6px 50%;
}
[dir='rtl'] .route__node { transform-origin: calc(100% - 6px) 50%; }
.route__dot {
  flex: none; width: 12px; height: 12px;
  background: var(--action); border-radius: 1px;
}
/* Номер стоит на линии: фон секции под ним прячет линию, и «01» читается узлом. */
.route__num {
  padding-block: 0; padding-inline: 16px 8px;
  font-family: var(--font-display); font-size: .8125rem; line-height: 1;
  color: var(--fg); background: var(--bg);
}
.route__seg { position: absolute; background: var(--accent-rare); }

.route__body { display: grid; gap: 6px; }
.route__title { font-size: var(--fs-h3); line-height: 1.2; letter-spacing: -0.01em; }
.route__text { color: var(--fg); font-size: 1rem; line-height: 1.55; max-width: 46ch; }

.route__finale { position: relative; margin-top: var(--route-gap); font-size: var(--fs-body); line-height: 1.55; color: var(--fg); }
.route__finale b { color: var(--fg); font-weight: 600; }
.route__finale .route__dot { position: absolute; inset-inline-start: 0; top: calc(.75em - 6px); }

/* Вертикаль: линия идёт от центра своего узла к центру следующего, у последнего
   шага — к точке итоговой строки. */
@media (max-width: 719px) {
  .route__body { padding-inline-start: 28px; }
  .route__seg {
    inset-inline-start: 5.5px; top: 6px; width: 1px;
    height: calc(100% + var(--route-gap));
    transform-origin: 50% 0;
  }
  .route__step:last-child .route__seg { height: calc(100% + var(--route-gap) + .703125rem - 6px); }
  .route__finale { padding-inline-start: 28px; }
}

/* Горизонталь: отрезок от узла до следующего узла той же строки, через зазор колонки. */
@media (min-width: 720px) {
  .route__steps { grid-template-columns: repeat(2, 1fr); }
  .route__seg { inset-inline-start: 0; top: 5.5px; height: 1px; width: 100%; transform-origin: 0 50%; }
  /* Линия прочерчивается от начала строки: в арабской версии — справа налево. */
  [dir='rtl'] .route__seg { transform-origin: 100% 50%; }
  .route__step:nth-child(odd) .route__seg { width: calc(100% + var(--route-gap)); }
  .route__finale {
    padding-block: 14px; padding-inline: 40px 18px;
    background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px;
  }
  .route__finale .route__dot { inset-inline-start: 18px; top: calc(14px + .75em - 6px); }
}
@media (min-width: 1100px) {
  .route__steps { grid-template-columns: repeat(4, 1fr); }
  .route__step .route__seg,
  .route__step:nth-child(odd) .route__seg { width: calc(100% + var(--route-gap)); }
  .route__step:last-child .route__seg { width: 100%; }
}

/* ── Значки ───────────────────────────────────────────────────────────────
   Линейный значок в круге — по референсу клиента (14.10.2026). Рисунки и имена —
   js/icons.js, какой значок где — данные. Три вида:
     solid  — тёмный круг, значок рабочим акцентом. На тёмной секции это
              приподнятая плита с золотой кромкой: кромка продолжает золотую линию
              маршрута, и новой доли золота на экране не появляется. На светлой —
              чернильный островок, как плита верхней панели;
     accent — залитый оранжевым, значок тёмный. Ровно один на блок: финиш маршрута,
              плитка «Особые условия»;
     soft   — тонированный и мельче, для списков: семь чёрных кругов подряд
              перетянули бы на себя весь блок «О нас».
   Оранжевый значок на --ink — 6.90, тёмный на --orange — 6.90: оба выше 3:1,
   которых требует графика. */
.ico {
  --ico: 44px;
  flex: none;
  display: inline-grid; place-items: center;
  width: var(--ico); height: var(--ico);
  border-radius: 50%;
  border: 1px solid transparent;
}
.ico svg { display: block; width: 48%; height: 48%; }
/* Самолёт и бумажный самолётик летят в сторону чтения. */
[dir='rtl'] .ico--flip svg { transform: scaleX(-1); }

.ico--solid { background: var(--bg-raised); border-color: var(--accent-rare); color: var(--action-text); }
[data-theme='light'] .ico--solid { background: var(--bg-raised); border-color: var(--line-soft); color: var(--accent-rare-text); }
.ico--accent { background: var(--action); border-color: var(--action-edge); color: var(--on-action); }
.ico--soft {
  --ico: 36px;
  background: color-mix(in srgb, var(--action) 12%, var(--bg-raised));
  border-color: color-mix(in srgb, var(--action) 30%, var(--bg-raised));
  color: var(--action-text);
}
/* В маленьком круге значок крупнее по доле: иначе штрих 1.75 сливается в точку. */
.ico--soft svg { width: 52%; height: 52%; }

/* ── Маршрут со значками ──────────────────────────────────────────────────
   Класс .route--ico ставит page.js, когда значок есть у каждого шага. Узел —
   круг 44 px вместо квадрата 12 px, и все отступы линии считаются от половины
   узла: линия проходит через центры кругов. Круг непрозрачный и лежит над
   линией (z-index узла), поэтому линия в него входит и из него выходит, а не
   перечёркивает значок. Кинетика масштабирует узел от центра круга. */
.route { --node: 12px; }
.route--ico { --node: 44px; }
.route--ico .route__node { height: var(--node); transform-origin: calc(var(--node) / 2) 50%; z-index: 1; }
[dir='rtl'] .route--ico .route__node { transform-origin: calc(100% - var(--node) / 2) 50%; }
.route--ico .route__finale .route__ico { position: absolute; inset-inline-start: 0; top: 0; }

@media (max-width: 719px) {
  .route--ico .route__body { padding-inline-start: calc(var(--node) + 16px); }
  .route--ico .route__seg { inset-inline-start: calc(var(--node) / 2 - .5px); top: calc(var(--node) / 2); }
  /* Финиш стоит на той же вертикали: последний отрезок доходит до центра его круга. */
  .route--ico .route__step:last-child .route__seg { height: calc(100% + var(--route-gap)); }
  .route--ico .route__finale {
    min-height: var(--node);
    padding-inline-start: calc(var(--node) + 16px);
    padding-top: calc((var(--node) - 1.5em) / 2);
  }
}
@media (min-width: 720px) {
  .route--ico .route__seg { top: calc(var(--node) / 2 - .5px); }
  /* В плите финиша круг поменьше и по центру высоты. */
  .route--ico .route__finale { padding-inline-start: calc(18px + 36px + 14px); }
  .route--ico .route__finale .route__ico { --ico: 36px; inset-inline-start: 18px; top: 50%; transform: translateY(-50%); }
}

/* ── О нас ────────────────────────────────────────────────────────────────
   Первая светлая секция за тёмным блоком первого экрана. Новых красок здесь
   нет ни одной — всё собрано на производных от поверхности и на --action,
   который и так рабочий акцент.

   Порядок внутри (раунд 2, от клиента): лид (он в .section__note) → основной
   текст → направления → страны → факты → закрывающий абзац → слоган.
   Акцентная плитка — «Особые условия»: она объясняет скидки, и читатель
   уходит с неё в блок цен. Какая плитка акцентная, решают данные. */
.about { display: grid; gap: calc(var(--gut) * 4); }
.about__block { display: grid; gap: 10px; }
.about__note { color: var(--fg-dim); font-size: .875rem; }
.about__closing { max-width: 68ch; color: var(--fg); font-size: var(--fs-body); }

/* Лид здесь — утверждение, а не пояснение к заголовку, как у других секций:
   за ним идут четыре абзаца основного текста, и без подъёма он читался бы
   пятым. Поэтому --fg и кегль крупнее; основной текст — ступенью тише. */
#about .section__note { color: var(--fg); font-size: 1.125rem; line-height: 1.4; }
.about__body { display: grid; gap: 12px; max-width: 62ch; }
.about__body p { color: var(--fg); font-size: var(--fs-body); line-height: 1.6; }

/* Слоган — последняя строка секции. Отдельно от абзаца над ним: гарнитура
   заголовков и волосяная линия сверху, секция им подписана. Регистр — как
   у клиента: капс оставлен заголовкам. */
.about__tagline {
  padding-top: calc(var(--gut) * 3);
  border-top: 1px solid var(--line-soft);
  font-family: var(--font-display); font-size: clamp(1.125rem, 2.4vw, 1.5rem); line-height: 1.2;
  color: var(--fg);
  overflow-wrap: anywhere;
}

/* Семь направлений. Маркер — тот же оранжевый квадрат, что у .bullets:
   идиома на странице уже есть, заводить под список вторую незачем.

   Семь не делится ни на 2, ни на 3, и в гриде по строкам седьмой пункт
   уезжал бы сиротой в отдельную строку. Поэтому грид заполняется по колонкам:
   число строк (--rows) ставит page.js, половина пунктов с округлением вверх,
   и семь ложатся 4 + 3.

   Не CSS columns. Колонки текста дают тот же 4 + 3, но в Safari правая колонка
   начиналась ниже левой: WebKit не обрезает отступ пункта на разрыве колонки
   и переносит его наверх следующей. У грида строки общие на обе колонки —
   верх выровнен в любом движке. Три колонки не берём: пункты длинные,
   «Визовое, жилищное и постзачислительное сопровождение» в трети строки
   ломается на три. */
.dirs { display: grid; gap: 8px 32px; }
@media (min-width: 720px) {
  .dirs { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(var(--rows, 4), auto); grid-auto-flow: column; }
}
.dirs li { position: relative; padding-inline-start: 18px; font-size: 1rem; }
.dirs li::before {
  content: ''; position: absolute; inset-inline-start: 0; top: .55em;
  width: 8px; height: 8px; background: var(--action); border-radius: 1px;
}
/* Пункты со значками: круг вместо квадрата-маркера. */
.dirs--ico li { display: flex; align-items: center; gap: 12px; padding-inline-start: 0; }
.dirs--ico li::before { content: none; }

/* Десять стран. Кнопка — это .chip из фильтра каталога: тот же компонент,
   те же состояния наведения и фокуса, ноль новой краски. Отличие одно —
   крупнее площадь нажатия: здесь чип не фильтр, а основное действие блока.
   aria-pressed не ставится: клик по стране — действие, а не переключатель. */
.geo { display: flex; gap: 6px; flex-wrap: wrap; }
.geo .chip {
  font-size: .875rem;
  padding: 12px 16px;
  /* Граница поднята с --line-soft до --line. У фильтра чип живёт в подписанной
     группе, рядом со счётчиками, и опознаётся окружением; здесь он сам себе
     блок и единственное действие — значит, край обязан проходить 3:1.
     --line-soft на --bg-raised это 1.65, --line — 3.12. */
  border-color: var(--line);
}
/* :not([disabled]) здесь не про disabled — его у стран не бывает. Он добивает
   специфичность: без него правило (0,3,0) сходится вничью с .chip:hover:not([disabled])
   из фильтра, а тот объявлен ниже по файлу и молча выигрывает по порядку. */
.geo .chip:hover:not([disabled]) { border-color: var(--action-edge); }

/* Факты. Плита, а не карточка: наводить не на что, подъёма нет.
   Оранжевый ровно у одной плитки — «Особые условия»; какая именно,
   решают данные (about.facts[].accent), а не порядок в разметке.

   Плиток три, четвёртая («ОАЭ и Ближний Восток») выключена в данных и может
   вернуться. Сетка обязана держать оба случая, поэтому 3 и 4 разложены числом,
   по data-facts, а не auto-fit: тот даёт 2 + 1 и 3 + 1, и последняя плитка
   читается как лишняя.
     3 плитки: столбик → три в ряд с 720 px;
     4 плитки: столбик → 2 × 2 с 560 px → четыре в ряд с 1100 px.
   Любое другое число — прежний auto-fit. */
.facts {
  display: grid; gap: var(--gut);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 232px), 1fr));
}
.facts[data-facts='3'], .facts[data-facts='4'] { grid-template-columns: 1fr; }
@media (min-width: 560px)  { .facts[data-facts='4'] { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 720px)  { .facts[data-facts='3'] { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) { .facts[data-facts='4'] { grid-template-columns: repeat(4, 1fr); } }
.fact { padding: 16px 18px; display: grid; gap: 6px; align-content: start; }
.fact b {
  font-family: var(--font-display); font-size: 1.125rem; line-height: 1.15;
  /* Длинное значение в Unbounded («Международные партнёрства») шире колонки
     на узком экране: пусть переносится, а не раздувает грид-трек. */
  overflow-wrap: anywhere;
}
.fact span { color: var(--fg-dim); font-size: .8125rem; }
.fact--accent b { color: var(--action-text); }
/* Плитка со значком: круг слева от значения и подписи, как карточки в референсе. */
.fact--ico { grid-template-columns: auto minmax(0, 1fr); column-gap: 14px; align-items: start; }
.fact--ico > .ico { grid-column: 1; grid-row: 1 / span 2; }
.fact--ico > :not(.ico) { grid-column: 2; }

/* ── О Selena Educates: миссия, встречи, основатель, кнопка (23.10.2026) ──
   Новой краски нет: производные поверхности, --accent-rare на линиях и
   --action на кнопке. */
.about__mission {
  display: grid; gap: 10px; max-width: 62ch;
  padding-inline-start: calc(var(--gut) * 2);
  border-inline-start: 2px solid var(--accent-rare);
}
.about__mission p {
  font-family: var(--font-display); font-size: clamp(1.125rem, 2.4vw, 1.5rem); line-height: 1.25;
  color: var(--fg); overflow-wrap: anywhere;
}
.about__h3 {
  font-family: var(--font-display); font-size: var(--fs-h3); line-height: 1.2;
  max-width: 34ch;
}
.unis { gap: calc(var(--gut) * 2); }

/* Коллаж встреч. Широкие кадры — на всю ширину, два узких — парой с 720 px.
   Ширина ограничена: снимки пришли из коллажа шириной 756 px и увеличены
   вдвое, крупнее 960 px они мылятся. */
.meets { display: grid; gap: calc(var(--gut) * 2); max-width: 960px; margin-top: var(--gut); }
.meets__title {
  font-family: var(--font-display); font-size: clamp(1.125rem, 2.2vw, 1.5rem); line-height: 1.2;
  text-align: center;
}
.meets__grid { display: grid; gap: calc(var(--gut) * 2); }
@media (min-width: 720px) {
  .meets__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .meet--wide { grid-column: 1 / -1; }
}
.meet { margin: 0; display: grid; gap: var(--gut); align-content: start; }
.meet__name {
  background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px;
  padding: 10px 14px; text-align: center; font-weight: 600; font-size: .9375rem;
}
.meet__photo {
  position: relative; overflow: hidden; border-radius: 2px;
  container-type: inline-size;
  background: var(--line-soft);
}
.meet__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Подпись на снимке. Цвета свои, не темы: плашка лежит на фотографии, а не на
   секции, и в тёмной теме не должна темнеть. Кегль — от ширины кадра (cqi),
   чтобы плашка и буквы росли вместе со снимком, как в коллаже клиента. */
.meet__tag {
  position: absolute; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: .25em .6em;
  background: var(--bone); color: var(--ink);
  font-size: clamp(11px, 2cqi, 17px); line-height: 1.25;
}
.meet:not(.meet--wide) .meet__tag { font-size: clamp(11px, 4cqi, 17px); }
.meet__cap, .meets__closing { color: var(--fg-dim); font-size: .9375rem; text-align: center; }
.meets__closing { padding-top: calc(var(--gut) * 2); border-top: 1px solid var(--line-soft); }

/* Основатель. Фото пока нет — плита держится на тексте. */
.founder { padding: calc(var(--gut) * 3); display: grid; gap: calc(var(--gut) * 2); max-width: 820px; }
.founder__head { display: grid; gap: 6px; }
.founder__name {
  font-family: var(--font-display); font-size: clamp(1.375rem, 1.2rem + .8vw, 1.75rem); line-height: 1.2;
}
.founder__bio { display: grid; gap: 10px; max-width: 62ch; }
.founder__bio p { color: var(--fg-dim); line-height: 1.6; }
.founder__quote {
  margin: 0; max-width: 62ch;
  padding-inline-start: calc(var(--gut) * 2);
  border-inline-start: 2px solid var(--accent-rare);
}
.founder__quote p { font-family: var(--font-display); font-size: clamp(1rem, 2vw, 1.25rem); line-height: 1.35; color: var(--fg); }

/* Кнопка на встречу — блёкло-зелёная плита посреди кремовой секции (data-tint на блоке). */
.about__cta {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: calc(var(--gut) * 3);
  padding: calc(var(--gut) * 4) calc(var(--gut) * 3);
  border-radius: 2px;
}
.about__cta-text { display: grid; gap: 8px; max-width: 46ch; }
.about__cta h3 {
  font-family: var(--font-display); font-size: clamp(1.375rem, 1.2rem + .8vw, 1.75rem); line-height: 1.2;
}
.about__cta p { color: var(--fg-dim); }
:root[lang='ar'] :is(.about__mission p, .founder__quote p, .founder__bio p, .about__cta h3) { line-height: 1.7; }


/* ── Галерея кампусов ─────────────────────────────────────────────────────
   Сцена задаёт высоту через aspect-ratio, слайды лежат в ней абсолютом.
   Отсюда CLS = 0: коробка под картинку посчитана до того, как картинка приехала,
   и её появление ничего не двигает.

   3D сдержанный: соседи отходят по X, слегка поворачиваются и гаснут. Разворотов
   на 45° и «карусели-книжки» здесь нет намеренно — клиент просил без перегибов,
   и на тёмном фоне сильный поворот превращает ряд в мешанину полупрозрачных пятен. */
.gal { display: grid; gap: calc(var(--gut) * 2); }

.gal__stage {
  position: relative;
  /* Подобрано под слайд, а не «на глаз»: слайд занимает 62% ширины при пропорции 3/2,
     то есть 0.41 ширины сцены по высоте, плюс строка подписи. При 16/9 сверху и снизу
     оставалось по полосе пустоты в четверть экрана. */
  aspect-ratio: 2 / 1;
  max-height: 56svh;
  /* Перспектива на сцене, а не на слайде: иначе у каждого своя точка схода
     и ряд разъезжается. */
  perspective: 1400px;
  perspective-origin: 50% 50%;
  overflow: hidden;
  border-radius: 2px;
}
.gal__stage:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

.gal__track { position: absolute; inset: 0; margin: 0; list-style: none; }

.gal__slide {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(62%, 640px);
  /* Перемножаем сдвиг соседа на его номер: --d приходит из JS числом. */
  /* --dir разворачивает ряд в арабской версии: следующий слайд встаёт слева. */
  transform:
    translate(-50%, -50%)
    translateX(calc(var(--d) * var(--dir) * 46%))
    translateZ(calc(var(--d) * var(--d) * -90px))
    rotateY(calc(var(--d) * var(--dir) * -9deg))
    scale(calc(1 - 0.06 * max(var(--d), var(--d) * -1)));
  transition: transform .5s var(--snap), opacity .5s var(--snap);
  opacity: .32;
  z-index: 0;
}
.gal__slide.is-current { opacity: 1; z-index: 2; }
/* Дальние не прячем display: none — они должны доезжать плавно, а не возникать. */
.gal__slide.is-far { opacity: 0; pointer-events: none; }

.gal__slide figure { margin: 0; display: grid; gap: 8px; }
.gal__slide img {
  display: block;
  width: 100%; height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  background: var(--bg-raised);
  border: 1px solid var(--line-soft);
  border-radius: 2px;
}
.gal__slide.is-current img { border-color: var(--line); }

.gal__slide figcaption { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; font-size: .8125rem; }
/* Подпись показывает только текущий слайд. Соседи стоят под разным углом и в разном
   масштабе, их подписи садились на разную высоту и налезали друг на друга — на широком
   экране получалась каша из четырёх «фото уточняется» поверх одной картинки.
   visibility, а не display: место под строку остаётся занятым, и смена слайда
   не двигает раскладку. */
.gal__slide:not(.is-current) figcaption { visibility: hidden; }
.gal__slide figcaption b { font-family: var(--font-display); font-size: .9375rem; }
.gal__credit { color: var(--fg-dim); }

.gal__go {
  font: inherit; font-size: .8125rem;
  background: 0; border: 0; padding: 0;
  color: var(--action-text); text-decoration: underline; cursor: pointer;
  margin-inline-start: auto;
}
/* Кнопка внутри некущего слайда недостижима табом (tabIndex ставит JS), но и
   мышью по ней бить незачем: слайд полупрозрачный, попадание случайно. */
.gal__slide:not(.is-current) .gal__go { pointer-events: none; }

.gal__ctl { display: flex; align-items: center; gap: var(--gut); flex-wrap: wrap; }
.gal__btn {
  font: inherit; font-size: .875rem;
  padding: 10px 16px; min-width: 48px;
  background: var(--bg-raised); color: var(--fg);
  border: 1px solid var(--line); border-radius: 2px; cursor: pointer;
}
.gal__btn:hover { border-color: var(--action-edge); }
/* Кнопка паузы шире остальных: подпись в ней меняется, и прыгать она не должна. */
.gal__btn--play { min-width: 108px; }
.gal__pos { color: var(--fg-dim); font-size: .8125rem; margin-inline-start: auto; }

@media (max-width: 719px) {
  /* На узком соседи почти не видны и только съедают ширину: оставляем один слайд
     во всю сцену, листание остаётся свайпом и кнопками. */
  /* На узком соседи почти не видны и только съедают ширину: оставляем один слайд
     во всю сцену, листание остаётся свайпом и кнопками. */
  .gal__stage { aspect-ratio: 4 / 3; max-height: none; }
  .gal__slide { width: 92%; }
  .gal__pos { margin-inline-start: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  /* Ни поворота, ни отъезда: слайды просто сменяются. Автолистание выключено
     в самом модуле, здесь снимается только движение. */
  .gal__slide {
    transition: opacity .2s linear;
    transform: translate(-50%, -50%) translateX(calc(var(--d) * var(--dir) * 46%));
  }
}

/* Заголовок секции графика пинится — строки уходят под него, а не сквозь. */
/* Запиненный заголовок: непрозрачная подложка и свой слой, иначе в щель под ним
   просвечивает следующая секция. Тень того же цвета закрывает шов от subpixel. */
/* Запиненный заголовок остаётся ПОД контентом: строки графика проходят поверх него,
   а сам он гаснет по мере прокрутки. Перекрывать контент заголовок не должен,
   поэтому ни щита-подложки, ни тени-заглушки здесь больше нет — щели неоткуда взяться,
   когда сверху всегда лежит непрозрачная плита строки. */
#cost .section__head {
  position: relative;
  z-index: 0;
  padding: 14px 0 16px;
  margin-bottom: 0;
}
/* Непрозрачная подложка контента: строки идут с зазором в 2 px, и без неё сквозь
   эти просветы просматривался бы запиненный заголовок. Цвет тот же, что у страницы,
   поэтому визуально ничего не меняется — меняется только перекрытие. */
#cost-mount { position: relative; z-index: 2; background: var(--bg); }

/* ── Виджет: график стоимости (дамбелл) ───────────────────────────────────── */
.plot { display: grid; gap: 2px; }
.plot__axis { display: flex; justify-content: space-between; color: var(--fg-dim); font-size: .75rem; padding: 0 14px 6px; }

.row {
  display: grid; gap: 6px;
  width: 100%; text-align: start;
  padding: 12px 14px;
  background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px;
  font: inherit; color: inherit; cursor: pointer;
}
/* Наведение — не заливка посветлее (на тёмном её попросту не видно), а линия:
   строка поднимает свою границу с --line-soft до --line. */
.row:hover { border-color: var(--line); }
.row[aria-expanded='true'] { box-shadow: inset calc(3px * var(--dir)) 0 0 var(--action-edge); }
.row__head { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.row__name { font-weight: 600; }
.row__prog { color: var(--fg-dim); font-weight: 400; font-size: .8125rem; }
/* Неразрывна каждая сумма, а не пара целиком. В дирхамах пара «153 000 AED
   от 107 100 AED» — 229 px, и в одну строку она распирала строку графика на 360 px
   шире экрана. Теперь на узком итоговая цена переносится под зачёркнутую.
   Перенос даёт flex-wrap, а не white-space: между <s> и суммой нет пробела,
   и строке текста рваться там негде. */
.row__price {
  display: flex; flex-wrap: wrap; justify-content: flex-end; column-gap: 8px;
  font-weight: 600; color: var(--action-text);
}
.row__price s, .row__net { white-space: nowrap; }
.row__price s { color: var(--fg-dim); font-weight: 400; }

/* Отрезок: полная цена → цена со скидкой. Длина отрезка и есть скидка. */
/* Дорожка — это шкала от $0 до максимума оси, отрезок — полная цена вуза.
   Разные заливки: иначе длина отрезка не читается вовсе. */
.bar { position: relative; height: 10px; background: var(--line-soft); border-radius: 1px; }
.bar__full { position: absolute; inset-block: 0; inset-inline-start: 0; width: var(--full); background: var(--line); border-radius: 1px; }
/* Зона экономии. Прежде она была второй краской — маджентой против ультрамарина;
   новая гамма второй краски не даёт, и раздваивать её золотом нельзя: золото
   работает линиями и метками, а не штриховкой в половину виджета. Поэтому
   экономия и цена теперь обе оранжевые, а различает их форма — штриховка
   против сплошного узла, — и это честнее: обе величины про одни и те же деньги. */
.bar__cut {
  position: absolute; top: 0; bottom: 0; inset-inline-start: var(--netw); width: calc(var(--full) - var(--netw));
  background: repeating-linear-gradient(90deg, var(--action) 0 2px, transparent 2px 5px);
  opacity: .85;
}
.bar__node {
  position: absolute; top: -3px; inset-inline-start: var(--netw);
  width: 16px; height: 16px; margin-inline-start: -8px;
  background: var(--action); border: 1px solid var(--action-edge); border-radius: 2px;
}
.bar__node--flat { background: var(--fg); border-color: var(--fg); }
.row__meta { display: flex; gap: 10px; flex-wrap: wrap; color: var(--fg-dim); font-size: .75rem; }

/* Плашка по умолчанию — контурная: на тёмном заливка «чуть светлее фона» не видна. */
.tag { border: 1px solid var(--line-soft); padding: 2px 8px; border-radius: 2px; }

/* Заливка акцентом. Подпись на ней всегда --on-action, то есть тёмная:
   белым по оранжевому нельзя — 2.87. */
.tag--save { background: var(--action); border-color: var(--action-edge); color: var(--on-action); }

/* Оранжевый контур: «сильная скидка» в каталоге. Это featured, а не exclusive —
   роли разведены, и золота здесь нет. */
.tag--featured { border-color: var(--action-text); color: var(--action-text); }

/* СОСТОЯНИЕ вместо значения: «всё включено, без скидки», «условия уточняются».
   Это не предложение и не характеристика вуза, а сообщение о том, что сравнивать
   нечего или пока нечем. Поэтому граница поднята до --line — плашку видно, —
   а подпись приглушена: заметнее обычной меты, тише любой заливки. */
.tag--state { border-color: var(--line); color: var(--fg-dim); }

/* ЗОЛОТО. Ровно две плашки на весь сайт, обе — редкий акцент по правилу гаммы:
   настоящий эксклюзив и бесплатное обучение. Заливка, а не контур: на светлой
   секции золото даёт к фону 1.98 и контуром не читается, поэтому там --accent-rare
   переключается на --gold-deep (3.62) и держит границу сам.
   Подпись тёмная на обоих: --ink на --gold 8.80, на --gold-deep 4.80.

   .tag--free заведена заранее — «Бесплатное обучение» придёт с контентными
   правками клиента (Al Qasimia), в данных этого поля пока нет. */
/* «Эксклюзив Selena» и «Бесплатное обучение» — золотистая плашка (26.10.2026):
   шампань-заливка и тонкая золотая рамка — в каталоге, графике и сравнении. */
.tag--excl, .tag--free, .cmp__excl {
  background: var(--gold-soft); border: 1px solid var(--gold); color: var(--gold-ink);
  font-weight: 600; letter-spacing: .01em;
}

/* Кто не попал в график и почему. Строка обязана быть: вуз есть в каталоге,
   а в графике его нет — без объяснения это выглядит как потеря данных. */
.plot__excluded {
  margin-top: calc(var(--gut) * 2);
  max-width: 68ch; color: var(--fg-dim); font-size: .8125rem;
}

.row__details { display: grid; gap: 8px; padding: 12px 14px 16px; background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px; }
.row__details ul { display: grid; gap: 4px; color: var(--fg-dim); font-size: .875rem; }
.row__details li::before { content: '— '; }

/* Фолбэк до загрузки виджета — таблица, не спиннер. */
.fallback { width: 100%; border-collapse: collapse; background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px; font-size: .875rem; }
.fallback caption { text-align: start; color: var(--fg-dim); font-size: .75rem; padding: 0 0 8px; }
.fallback th, .fallback td { padding: 8px 12px; text-align: start; }
.fallback th { font-size: .75rem; text-transform: uppercase; letter-spacing: .08em; color: var(--fg-dim); font-weight: 600; }
.fallback tr + tr td { border-top: 1px solid var(--line-soft); }

/* ── Карта кампусов ───────────────────────────────────────────────────────── */
.map {
  position: relative;
  min-height: 340px;
  aspect-ratio: 16 / 9;
  max-height: 70svh;
  background: var(--bg-raised);
  /* Карта на тёмной странице оправляется линией, а не тенью: тень на чёрном
     не читается, а --bg-raised к --ink это 1.08 и краем сам не работает. */
  border: 1px solid var(--line);
  border-radius: 2px;
  overflow: hidden;
  overflow-anchor: none;
}
@media (max-width: 719px) { .map { aspect-ratio: 4 / 5; max-height: none; } }

/* Специфичность здесь не украшательство, а необходимость: MapLibre вешает на этот же
   узел свой класс .maplibregl-map с position: relative, а его таблица стилей
   подключается позже нашей. При равной специфичности выигрывает она, inset перестаёт
   работать, и контейнер схлопывается в нулевую высоту — карта строится и молчит.
   Селектор из двух классов выигрывает независимо от порядка подключения. */
.map > .map__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Контролы MapLibre раскладываются физически (масштаб справа сверху, копирайт
     справа снизу), и переключатель области ниже стоит слева от них. В арабской
     версии карту не зеркалим: это карта, а не текст. */
  direction: ltr;
}

/* Состояние до загрузки: не дыра, а читаемый блок.
   Лежит абсолютом поверх канваса — и обязан уходить из потока целиком, а не просто
   прятаться. Наш `display: flex` перебивал браузерное `[hidden] { display: none }`
   (авторский стиль всегда сильнее пользовательского агента), поэтому спрятанный
   плейсхолдер оставался на месте и перехватывал все указательные события: карта
   не тянулась, маркеры не кликались, zoomend до карты не доходил. */
.map__fallback {
  position: absolute; inset: 0;
  z-index: 1;
  display: flex; flex-direction: column; justify-content: center; gap: 20px;
  padding: 28px;
}
.map__fallback[hidden] { display: none; }
.map__stats { display: flex; gap: var(--gut); flex-wrap: wrap; }
.map__stats li { display: flex; gap: 10px; align-items: baseline; }
.map__stats b {
  font-family: var(--font-display); font-size: 1.75rem; line-height: 1;
  color: var(--action-text); font-variant-numeric: tabular-nums;
}
.map__stats span { font-size: .875rem; color: var(--fg-dim); max-width: 14ch; }
.map__note { max-width: 46ch; color: var(--fg); font-size: 1rem; }

/* Переключатель области карты. Лежит поверх канваса, но НИЖЕ плейсхолдера
   по порядку в DOM — пока карта не поднялась, кнопка не нужна и не должна
   перехватывать нажатия. Слева внизу: справа сверху стоит NavigationControl,
   справа внизу — копирайт тайлов. */
.map__scope {
  position: absolute;
  left: 12px; bottom: 12px;
  z-index: 2;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  max-width: calc(100% - 24px);
}
.map__scope-btn {
  font: inherit; font-size: .8125rem;
  padding: 10px 14px;
  background: var(--bg-raised); color: var(--fg);
  border: 1px solid var(--line); border-radius: 2px; cursor: pointer;
}
.map__scope-btn:hover { border-color: var(--action-edge); }
/* Узкий экран: справа внизу живёт кнопка копирайта «i» (24 px плюс отступ),
   и контрол обязан кончаться до неё — иначе счётчик ложится поверх. Не влезли
   в строку — счётчик переносится под кнопку, а не под «i». */
@media (max-width: 719px) {
  .map__scope { left: 10px; bottom: 10px; max-width: calc(100% - 64px); gap: 6px; }
  .map__scope-btn { min-height: 44px; }
}
/* Счётчик — подпись при кнопке, а не живая область: обновляется на каждый moveend,
   и объявлять это вслух при каждой прокрутке колесом было бы издевательством.
   Плашка под ним нужна: цифра лежит поверх карты, а не поверх фона страницы. */
.map__scope-count {
  font-size: .75rem; color: var(--fg-dim);
  background: var(--bg);
  padding: 4px 8px; border-radius: 2px;
}

/* Точка вуза. Кнопка, а не декорация: доступна табом, Enter работает как клик. */
.pin {
  width: 16px; height: 16px; padding: 0;
  /* Кольцо цветом фона страницы: точка вырезается из карты, а не лежит на ней. */
  border: 2px solid var(--bg); border-radius: 2px;
  background: var(--action);
  cursor: pointer;
  box-shadow: var(--shadow-lift);
}
.pin:hover { transform: scale(1.15); }
.pin:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; box-shadow: 0 0 0 2px var(--bg); }

/* precision: 'cluster' — известен район, а не здание. Тихое отличие, без легенды:
   мягкий контур вместо плотной заливки, у точки нет чёткого центра. */
.pin--cluster {
  background: color-mix(in srgb, var(--action) 30%, var(--bg));
  border-color: color-mix(in srgb, var(--action) 55%, var(--bg));
  border-radius: 50%;
  width: 18px; height: 18px;
}

/* Групповой маркер: четыре вуза Knowledge Park на обзорном зуме — одна точка с числом. */
.pin--group {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--bg-raised); color: var(--fg);
  border: 2px solid var(--action-edge);
  font: 600 .8125rem/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  display: grid; place-items: center;
}
.pin--group:hover { transform: scale(1.08); }

/* Карточка, к которой привела карта. */
.card--target { box-shadow: 0 0 0 2px var(--action-edge), var(--shadow-lift); }

@media (prefers-reduced-motion: reduce) {
  .pin:hover, .pin--group:hover { transform: none; }
}

/* ── Каталог и фильтр ─────────────────────────────────────────────────────── */
.filter { display: grid; gap: 12px; margin-bottom: calc(var(--gut) * 3); }
.filter__group { display: grid; gap: 8px; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  font: inherit; font-size: .8125rem;
  padding: 8px 12px; border: 1px solid var(--line-soft); border-radius: 2px; cursor: pointer;
  background: var(--bg-raised); color: var(--fg);
}
.chip:hover:not([disabled]) { border-color: var(--line); }
/* Нажатое состояние несут заливка И граница: на тёмном одна заливка читается хуже. */
.chip[aria-pressed='true'] { background: var(--action); border-color: var(--action-edge); color: var(--on-action); }
.chip[disabled] { opacity: .4; cursor: default; }
.chip i { font-style: normal; color: var(--fg-dim); margin-inline-start: 6px; }
/* Счётчик внутри нажатого чипа: та же тёмная краска, что подпись, но приглушённая
   к заливке. Прежде здесь было полупрозрачное белое — на оранжевом оно нечитаемо. */
.chip[aria-pressed='true'] i { color: color-mix(in srgb, var(--on-action) 72%, var(--action)); }
.filter__foot { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; color: var(--fg-dim); font-size: .8125rem; }
.reset { font: inherit; font-size: .8125rem; background: 0; border: 0; color: var(--action-text); cursor: pointer; padding: 4px 0; text-decoration: underline; }

.cards { display: grid; gap: var(--gut); grid-template-columns: repeat(auto-fill, minmax(min(100%, 272px), 1fr)); }
.card {
  padding: 16px; display: grid; gap: 10px; align-content: start;
  transition: transform .25s var(--snap), box-shadow .25s var(--snap), border-color .25s var(--snap);
}
/* Наведение на тёмном: подъём плюс оранжевая обводка. Ореола вокруг карточки нет
   и не будет — свечение оранжевым по чёрному это ровно тот шаблон, которого
   гамма требует избегать. Вторым слоем идёт --shadow-lift, а он none на тёмном
   и включается только в светлых секциях. */
/* hover — только там, где он есть. На тачскрине :hover залипает после тапа:
   карточка оставалась приподнятой и в оранжевой рамке, пока не ткнёшь в другое место. */
@media (hover: hover) {
  .card:hover {
    transform: translateY(-4px);
    border-color: var(--action-edge);
    box-shadow: 0 0 0 1px var(--action-edge), var(--shadow-lift);
  }
  .card:hover .card__price { color: var(--action-text); }
}
.card:focus-within {
  transform: translateY(-4px);
  border-color: var(--action-edge);
  box-shadow: 0 0 0 1px var(--action-edge), var(--shadow-lift);
}
.card:focus-within .card__price { color: var(--action-text); }
.card__top { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.card h3 { font-size: var(--fs-h3); line-height: 1.2; text-transform: none; letter-spacing: -0.01em; }
.card__sum { color: var(--fg); font-size: .9375rem; line-height: 1.5; }
.card__price { font-weight: 600; transition: color .25s var(--snap); }
/* Именованный класс, а не «любой span внутри цены».
   Прежнее правило .card__price span (0,1,1) перебивало по специфичности краску
   плашек, которые лежат в той же строке: золотая «Бесплатное обучение» получала
   --fg-dim вместо --on-action и падала с 8.80 до 1.31. Ловится это только замером:
   плашка остаётся золотой, нечитаемой становится подпись на ней. */
.card__unit { color: var(--fg-dim); font-weight: 400; font-size: .8125rem; }
/* Плашка в строке цены наследует 1rem от .card__price — возвращаем размер меты. */
.card__price .tag { font-size: .75rem; font-weight: 400; }
/* Плашка в строке цены («Всё включено, без скидки» у EFTA) не рвётся пополам:
   на 390 px её рамка ломалась на две строки. Целиком переезжает под цену. */
.card__price .tag { display: inline-block; white-space: nowrap; line-height: 1.5; }
.card__meta { display: flex; gap: 6px; flex-wrap: wrap; font-size: .75rem; color: var(--fg-dim); }
.card .cta { padding: 12px 16px; font-size: .9375rem; }

.empty { padding: 24px; color: var(--fg-dim); }

/* ── Сравнение двух вузов ─────────────────────────────────────────────────── */
.cmp { display: grid; gap: var(--gut); }

/* Три колонки на десктопе, две на узком: подпись уезжает над парой значений,
   и горизонтальной прокрутки не возникает ни на одном экране. */
.cmp__head,
.cmp__names,
.cmp__row {
  display: grid;
  grid-template-columns: minmax(150px, 1fr) 1fr 1fr;
  gap: var(--gut);
  align-items: start;
}

.cmp__pick { display: grid; gap: 6px; }
.cmp__select {
  font: inherit; font-size: .9375rem;
  padding: 12px 14px;
  background: var(--bg-raised); color: var(--fg);
  border: 1px solid var(--line); border-radius: 2px;
  width: 100%;
}
/* Те же боковые отступы, что у строк таблицы, иначе имена не встают над колонками. */
.cmp__names { align-items: end; padding: 0 14px; }
.cmp__name {
  font-family: var(--font-display); font-weight: 700; font-size: 1rem; line-height: 1.25;
  overflow-wrap: anywhere;
}

.cmp__table { display: grid; gap: 2px; margin: 0; }

.cmp__row { background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px; padding: 12px 14px; }
.cmp__label { color: var(--fg-dim); font-size: .875rem; }
.cmp__cell { margin: 0; }

/* Совпадение — спокойно и тихо. */
.cmp__value { color: var(--fg); font-weight: 400; font-size: 1rem; display: block; }

/* Расхождение — тем же набором средств: вес, цвет, тонкая линия слева. Без плашек. */
.cmp__row.is-diff { box-shadow: inset calc(2px * var(--dir)) 0 0 var(--action-edge); }
.cmp__row.is-diff .cmp__value { color: var(--fg); font-weight: 600; }

/* Скидка. Доля показывается полосой своей длины, фиксированная сумма — плашкой
   без полосы. Есть полоса — процент; нет полосы — сумма. Разная форма, а не подпись. */
.cmp__num { display: block; font-variant-numeric: tabular-nums; }
.cmp__share {
  display: block; height: 3px; margin-top: 6px;
  width: var(--доля); min-width: 3px; max-width: 100%;
  background: var(--action); border-radius: 1px;
}
/* Сумма — заливка, цена-нетто — контур. Форма различает их, а не краска:
   второй краски новая гамма не даёт, и обе метки про одни и те же деньги. */
.cmp__sum {
  display: inline-block;
  background: var(--action); border: 1px solid var(--action-edge);
  color: var(--on-action);
  padding: 4px 10px; border-radius: 2px;
  font-variant-numeric: tabular-nums;
}
/* Цена уже со скидкой: ни доли, ни суммы — своя форма, контур вместо заливки. */
.cmp__net {
  display: inline-block;
  border: 1px solid var(--action-text);
  color: var(--action-text);
  padding: 4px 10px; border-radius: 2px;
}
/* Единственная доля золота в этой секции — настоящий эксклюзив. Флаг читается
   из данных (discounts[].exclusive), списка вузов в коде нет и не будет:
   состав эксклюзивных партнёров у клиента ещё не закрыт. */
.cmp__excl { display: inline-block; margin-top: 8px; padding: 2px 8px; border-radius: 2px; font-size: .8125rem; }

/* Оговорка под значением: «зависит от профиля», «условия уточняются».
   Та же форма, что у эксклюзива, но приглушённая — это ограничение, не награда. */
.cmp__state { display: block; margin-top: 6px; color: var(--fg-dim); font-size: .8125rem; }


@media (max-width: 719px) {
  /* Селекты во всю ширину и друг под другом: на 360 px в колонку 160 px
     «University of Wollongong in Dubai» не помещается и обрезается. */
  .cmp__head { grid-template-columns: 1fr; }
  .cmp__names { grid-template-columns: 1fr 1fr; }
  .cmp__corner { display: none; }
  .cmp__row { grid-template-columns: 1fr 1fr; }
  /* Подпись встаёт над парой и занимает обе колонки. */
  .cmp__label { grid-column: 1 / -1; margin-bottom: 6px; }
  /* 16 px, а не 15: iOS Safari приближает страницу при фокусе на поле
     мельче 16 px и обратно сам не отдаляет. */
  .cmp__select { font-size: 1rem; }
  /* Таблица на телефоне — восемь строк в два экрана, и к «Наборам» уже не
     помнишь, какая колонка чья. Имена вузов прилипают к верху экрана. */
  .cmp__names {
    position: sticky; top: 0; z-index: 2;
    margin-inline: -1px; padding-block: 10px;
    background: var(--bg);
    border-bottom: 1px solid var(--line-soft);
  }
}

/* ── Отзывы ───────────────────────────────────────────────────────────────
   Светлая секция, и вместе с #lead под ней — один светлый блок (тот же приём,
   что у #route с первым экраном): чередование ниже не сдвигается, а отзывы
   стоят вплотную к форме. Новой краски нет: плита, --action, --fg/--fg-dim.

   Отзыв — письмо, а не карточка-тизер. Поэтому полный текст набран основным
   шрифтом с нормальным интерлиньяжем, а «крупное» — это одна фраза из того же
   письма, вынесенная гарнитурой заголовков. В тексте она подсвечена маркером:
   видно, что выноска взята оттуда, а не придумана.

   Два списка (их собирает page.js):
     .reviews__list--lead — первый отзыв, во всю ширину; с 900 px две колонки:
       слева кавычка, выноска и подпись, справа письмо и метки;
     .reviews__list--rest — остальные: сеткой на широком (auto-fit — две карточки
       делят ширину пополам, а не оставляют пустую третью колонку), лентой со
       свайпом на узком (data-reviews — их число).
   Карточки в ряду одной высоты, подпись и метки прижаты к низу: у соседних
   отзывов они стоят на одной линии, сколько бы ни было текста. */
.reviews { display: grid; gap: var(--gut); }
.reviews__list { display: grid; gap: var(--gut); padding: 0; }
@media (min-width: 720px) {
  .reviews__list--rest { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); }
}

.review { padding: 20px; display: flex; }
.review__fig {
  flex: 1; min-width: 0;
  margin: 0;
  display: grid; gap: 18px;
  grid-template-areas: 'aside' 'text' 'by' 'meta';
  grid-template-rows: auto 1fr auto auto;
}
.review__aside { grid-area: aside; display: grid; gap: 10px; align-content: start; }
.review__text  { grid-area: text; margin: 0; display: grid; gap: 12px; align-content: start; max-width: 64ch; }
.review__by    { grid-area: by; }
.review__meta  { grid-area: meta; }

/* Кавычка — декор, а не текст: заливка --action без порога 4.5, как у маркеров
   списков. Рисунок с точной коробкой, а не глиф — см. page.js. */
.review__mark { display: block; width: 2.5rem; color: var(--action); }
.review__mark svg { display: block; width: 100%; height: auto; }

.review__highlight {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.25rem, 2.6vw, 2rem); line-height: 1.18; letter-spacing: -0.01em;
  color: var(--fg);
  text-wrap: balance;
  overflow-wrap: break-word;
}

.review__text p { color: var(--fg); font-size: var(--fs-body); line-height: 1.6; }
.review__text p:first-child { color: var(--fg); }

/* Маркер — подложка нижней половиной строки, а не заливка целиком: текст
   остаётся на своей поверхности и не теряет контраст. */
.review__hl {
  background: none; color: var(--fg);
  box-shadow: inset 0 -.42em 0 color-mix(in srgb, var(--action) 24%, transparent);
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

/* Несколько сообщений одного чата: реплика с инициалом, как аватар в мессенджере.
   Склеивать их в один абзац нельзя — это разные люди. */
.review__thread { gap: 16px; }
.review__msg { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; align-items: start; }
.review__msg blockquote { margin: 0; display: grid; gap: 8px; }
.review__thread p, .review__thread p:first-child { color: var(--fg); font-size: 1rem; }
.review__from {
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 50%;
  background: color-mix(in srgb, var(--action) 16%, var(--bg-raised));
  border: 1px solid var(--line-soft);
  font-size: .8125rem; font-weight: 600; color: var(--fg);
}

.review__by { display: grid; gap: 2px; padding-top: 14px; border-top: 1px solid var(--line-soft); }
.review__by b { font-weight: 600; }
.review__by span { color: var(--fg-dim); font-size: .875rem; }

.review__meta { display: flex; gap: 12px 16px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.review__topics { display: flex; gap: 6px; flex-wrap: wrap; font-size: .75rem; color: var(--fg-dim); }

.review__orig {
  display: inline-flex; align-items: center; gap: 8px;
  font: inherit; font-size: .8125rem; font-weight: 600;
  padding: 10px 14px; min-height: 44px;
  background: transparent; color: var(--fg);
  border: 1px solid var(--line); border-radius: 2px; cursor: pointer;
}
.review__orig:hover { border-color: var(--action-edge); color: var(--action-text); }
.review__orig-icon { display: inline-flex; color: var(--action-text); }

/* Выноска работает, только когда стоит РЯДОМ с письмом. В одну колонку она
   оказывалась тремя строками выше той же фразы в тексте и читалась как повтор.
   Там её роль берёт маркер в тексте, а первый абзац поднят на ступень. */
.review__highlight { display: none; }
.review__text p:first-child { font-size: 1.0625rem; }
@media (min-width: 900px) {
  .review--lead .review__highlight { display: block; }
  .review--lead .review__text p:first-child { font-size: 1rem; }
}

@media (min-width: 900px) {
  .review--lead { padding: 32px 36px; }
  .review--lead .review__fig {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    grid-template-areas: 'aside text' 'by meta';
    grid-template-rows: 1fr auto;
    gap: 24px 56px;
  }
  .review--lead .review__aside { align-self: start; position: sticky; top: 24px; }
  .review--lead .review__mark { width: 3.5rem; margin-bottom: 8px; }
  .review--lead .review__by { align-self: end; }
  .review--lead .review__meta { padding-top: 14px; border-top: 1px solid var(--line-soft); }
}

/* Узкий экран, отзывов больше одного: лента со свайпом. Карточка — 86% ширины,
   чтобы край следующей торчал и было видно, что лента листается. */
@media (max-width: 719px) {
  .review { padding: 18px 16px; }
  .reviews__list--rest:not([data-reviews='1']) {
    display: flex; gap: var(--gut);
    margin-inline: calc(var(--pad) * -1); padding: 2px var(--pad) 12px;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; scroll-padding-inline: var(--pad);
    scrollbar-width: none;
  }
  .reviews__list--rest:not([data-reviews='1'])::-webkit-scrollbar { display: none; }
  .reviews__list--rest:not([data-reviews='1']) > .review { flex: 0 0 86%; scroll-snap-align: start; }
}


/* Диалог со скриншотом. Тёмный в любой секции: снимок — светлый скрин
   мессенджера, на тёмной подложке он читается как документ, а не как дыра. */
.shot {
  width: min(92vw, 560px); max-height: 92svh;
  padding: 0; border: 1px solid var(--line); border-radius: 2px;
  background: var(--bg); color: var(--fg);
  overflow: hidden;
}
.shot::backdrop { background: color-mix(in srgb, var(--ink) 78%, transparent); }
.shot[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
.shot__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-block: 8px; padding-inline: 16px 8px; border-bottom: 1px solid var(--line-soft);
}
.shot__title { font-size: .8125rem; color: var(--fg-dim); }
.shot__close {
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  background: transparent; color: var(--fg);
  border: 1px solid var(--line-soft); border-radius: 2px; cursor: pointer;
}
.shot__close:hover { border-color: var(--action-edge); }
.shot__pic { display: block; min-height: 0; overflow: auto; }
.shot__img { display: block; width: 100%; height: auto; }
html:has(.shot[open]) { overflow: hidden; }

/* ── Форма ──────────────────────────────────────────────────────────────────
   Секция заявки светлая. Прежде здесь была сплошная заливка ультрамарином во всю
   ширину; в новой гамме её эквивалент — сплошной оранжевый, а это самая большая
   доля акцента на сайте, и он перевесил бы всё остальное. Светлое работает тем же
   способом — контрастом к чёрной странице, — но акцент оставляет кнопке. */
.form { display: grid; gap: 12px; max-width: 520px; padding: 20px; }
.field { display: grid; gap: 6px; }
.field label { font-size: .8125rem; font-weight: 600; color: var(--fg); }
.field input, .field textarea {
  font: inherit; padding: 12px; border: 1px solid var(--line); border-radius: 2px;
  background: var(--bg-raised); color: var(--fg);
}
.field input:hover, .field textarea:hover { border-color: var(--fg-dim); }

/* Плейсхолдер задаётся явно. Умолчание браузера — примерно 54% серого от цвета
   текста, и на светлом поле это около 3.5:1: типовое место провала по контрасту.
   --fg-dim держит 5.4 на светлом и 6.7 на тёмном. */
.field input::placeholder, .field textarea::placeholder { color: var(--fg-dim); opacity: 1; }

/* ОШИБКА. Состояние несут значок и текст, цвет только поддерживает — и это не
   осторожность, а арифметика: ни один красный не даёт 3:1 против --orange.
   Любой достаточно светлый для чтения на --ink сидит на той же светлоте, лучший
   из оранжево-красных — 1.53. На форме оранжевая кнопка и красное поле стоят
   в одном экране, и различить их одним цветом нельзя. Поэтому:
     — поле в ошибке получает границу в 2 px, то есть меняет форму, а не только цвет;
     — сообщение открывается значком «!», собранным из currentColor, без картинки;
     — сам красный взят с максимальным отрывом по тону (347°/342° против 22°). */
.field input[aria-invalid='true'],
.field textarea[aria-invalid='true'] { border: 2px solid var(--danger); }

.field .err {
  color: var(--danger); font-size: .8125rem;
  display: flex; align-items: baseline; gap: .45em;
}
/* Обязательная пара к строке выше. Правило [hidden] { display: none } живёт
   в таблице пользовательского агента с весом (0,1,0), а «.field .err» — это
   (0,2,0), и авторский display: flex его перебивает. Без этой строки пустое
   сообщение об ошибке остаётся в потоке и показывает свой значок под каждым
   полем. Ровно та же ловушка описана в «Страховке» в конце файла. */
.field .err[hidden] { display: none; }
.field .err::before {
  content: '!';
  flex: none;
  display: inline-grid; place-items: center;
  inline-size: 1.15em; block-size: 1.15em;
  border: 1px solid currentColor; border-radius: 50%;
  font-weight: 700; font-size: .85em; line-height: 1;
  transform: translateY(.1em);
}

/* Что уже подставлено в заявку: страна из блока «Страны обучения».
   Скрытое поле пользователю не видно, и без этой строки клик по стране выглядел
   бы как несработавшая кнопка. Акцент несёт левая грань, а не заливка: это
   пометка о состоянии, а не действие, и перетягивать кнопку она не должна. */
.form__pick {
  font-size: .8125rem;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--action-edge);
  border-radius: 2px;
}


/* Ловушка для ботов: вне экрана, но не display: none — часть ботов такие поля
   пропускает. Человек её не видит, скринридер не слышит (aria-hidden), таб
   до неё не доходит (tabindex=-1). */
.hp { position: absolute; inset-inline-start: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }

.cta[disabled] { opacity: .65; cursor: progress; }

/* Отправка не прошла. Та же левая грань, что у .form__pick, но цвета ошибки:
   это сообщение о сбое, и рядом с ним — выход, кнопка в WhatsApp. */
.form__fail {
  display: grid; gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--danger);
  border-radius: 2px;
  font-size: .875rem;
}
.form__fail[hidden] { display: none; }
.form__fail .cta { justify-content: center; }

/* ── Футер ────────────────────────────────────────────────────────────────── */
.footer { background: var(--bg); color: var(--fg); padding: calc(var(--gut) * 6) var(--pad) calc(var(--gut) * 4); }
.footer__grid {
  display: grid; gap: calc(var(--gut) * 4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  align-items: start;
}
.footer h2, .footer h3 { font-size: .75rem; text-transform: uppercase; letter-spacing: .12em; font-family: var(--font-body); color: var(--fg-dim); font-weight: 600; }
/* Вордмарк в футере — вторая и последняя санкционированная доля золота на сайте.
   На экране футера она одна: выше него оранжевая кнопка, золота там нет. */
.footer__brand b { display: block; font-family: var(--font-display); font-size: 1.25rem; text-transform: uppercase; letter-spacing: -0.02em; margin-bottom: 8px; color: var(--accent-rare-text); }
.footer__brand p { color: var(--fg-dim); font-size: .875rem; max-width: 34ch; }
.footer__list { display: grid; gap: 8px; margin-top: 12px; }
.footer a { color: var(--fg); text-decoration: none; font-size: .9375rem; border-bottom: 1px solid var(--line); padding-bottom: 1px; width: fit-content; }
.footer a:hover { color: var(--action-text); border-bottom-color: var(--action-text); }
.footer__legal {
  margin-top: calc(var(--gut) * 5); padding-top: calc(var(--gut) * 2);
  border-top: 1px solid var(--line-soft);
  display: grid; gap: 6px; color: var(--fg-dim); font-size: .75rem; max-width: 76ch;
}

/* ── ИНТРО — сборка вордмарка «Selena Educates» ───────────────────────────
   Оверлей поверх страницы, position: fixed. В поток не входит, раскладку не
   двигает — CLS нулевой. Контент первого экрана под ним свёрстан в финальном
   виде с самого начала и только прячется краской и сдвигом.

   Гейтов два, и это не дубль:
     .intro-armed         — ставит блокирующий скрипт из <head> ДО первой отрисовки.
                            Держит спрятанным первый экран. Снимается в фазе 3,
                            когда контент начинает проявляться.
     [data-intro=running] — ставит intro.js на всё время таймлайна. Держит сам
                            оверлей. Снимается в самом конце: display: none.
   Будь гейт один, снятие класса в фазе 3 убило бы оверлей вместе с летящим
   вордмарком — ровно посреди перехода.

   Стартовые кадры букв и линии держит .intro:not([data-ready]), а не .intro-armed:
   к посадке букв класс ещё жив, и CSS вернул бы их в opacity: 0, как только
   у анимации кончится обратная заливка. Атрибут data-ready ставится один раз,
   ровно перед созданием анимаций.

   Без JS ни одного гейта нет — оверлея нет вовсе, страница сразу читается. */
.intro { display: none; }

.intro-armed .intro,
[data-intro='running'] .intro {
  display: grid;
  position: fixed;
  inset: 0;
  z-index: 100;
  place-items: center;
  padding: var(--pad);
  /* Клики оверлей забирает себе. С pointer-events: none пропуск по клику заодно
     нажимал бы на CTA под оверлеем. */
  cursor: pointer;
}

/* Фон отдельным слоем: в фазе 3 он уходит в прозрачность и открывает страницу,
   а вордмарк в это время продолжает лететь непрозрачным. */
.intro__bg { position: absolute; inset: 0; background: var(--surface); }

.intro__stage { position: relative; max-width: 100%; }

.intro__wordmark {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 .3em;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  /* На 360 px это ~30 px: «Selena» и «Educates» встают в две строки и в экран
     помещаются с запасом. На широком — одна строка. Перенос делает flex-wrap,
     а не медиазапрос: точка перелома зависит от метрик шрифта, не от брейкпоинта. */
  font-size: clamp(1.875rem, 8.4vw, 5.25rem);
  line-height: 1.06;
  letter-spacing: -0.02em;
  text-align: center;
  /* FLIP совмещает центры коробок — начало координат должно быть в центре. */
  transform-origin: center center;
}

.intro__word--gold { color: var(--orange); }
.intro__word--bone { color: var(--ink); }

/* Абстрактная «буква». Сегодня span, завтра — <path> из SVG-вордмарка;
   inline-block нужен ровно затем, чтобы к букве применялся transform. */
.intro [data-letter] { display: inline-block; }

/* Волосяная линия фазы 2: 1 px золота, слева направо. */
.intro__rule {
  display: block;
  height: 1px;
  margin-top: clamp(12px, 2vw, 26px);
  background: var(--orange);
  transform-origin: left center;
}

/* Стартовые кадры. Пока шрифт не готов — чёрный экран без контента: догрузись
   Unbounded в процессе, буквы переедут и вся сборка развалится. */
.intro:not([data-ready]) [data-letter] { opacity: 0; }
.intro:not([data-ready]) .intro__rule { transform: scaleX(0); }

/* Первый экран под оверлеем: свёрстан целиком, спрятан только краской и сдвигом —
   ни одного свойства, которое двигает раскладку.
   .hero__mark в общий подъём не входит: она принимает вордмарк из FLIP и
   проявляется вместе с ним, перекрёстно, в самом конце. */
.intro-armed .hero__mark { opacity: 0; }
.intro-armed .hero__mid,
.intro-armed .hero__bottom { opacity: 0; transform: translateY(18px); }

@media (prefers-reduced-motion: reduce) {
  /* Полётов нет: вордмарк проявляется за 250 мс, вся последовательность
     укладывается в 600 мс, FLIP заменяется мгновенным переходом — ветка в intro.js.
     Здесь снимаем только сдвиг: краску по-прежнему ведёт таймлайн.
     Правило ниже к интро отношения не имеет — Web Animations API живёт мимо
     CSS-свойства animation-duration и этим !important не режется. */
  .intro-armed .hero__mid,
  .intro-armed .hero__bottom { transform: none; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media (max-width: 719px) {
  .hero { gap: calc(var(--gut) * 2); }
  .hero__bottom { align-items: stretch; }
  /* Три плиты в ряд на 360 px не живут: «Топ-100» в Unbounded шире колонки.
     Разворачиваем в строки — значение слева, подпись справа. */
  .stats { width: 100%; flex-direction: column; gap: 4px; }
  .stat { display: flex; gap: 10px; align-items: baseline; padding: 10px 14px; min-width: 0; }
  .stat b { font-size: 1.125rem; flex: none; }
  .stat span { margin-top: 0; max-width: none; }
}

/* ── Верхняя панель: язык и меню ───────────────────────────────────────────
   Прибита к правому верхнему углу и едет со страницей. Висит то над тёмной
   секцией, то над светлой, поэтому несёт свою тему (data-theme="dark" в разметке)
   и свою плиту: --bg-raised с линией. На светлом это тёмный островок — читается,
   на тёмном — приподнятая плита, как кнопки галереи. Верх совпадает с вордмарком
   первого экрана: оба стоят на --pad от края.

   z-index 50: выше содержимого секций (там максимум 2), ниже оверлея интро (100) —
   интро её перекрывает и открывает вместе со страницей. Диалоги (меню, скриншот
   отзыва) живут в top layer и выше её без всякого z-index. */
.topbar {
  position: fixed; top: var(--pad); inset-inline-end: var(--pad); z-index: 50;
  display: flex; gap: 6px; align-items: stretch;
  background: none; color: var(--fg);
  transition: opacity .2s ease, transform .2s var(--snap), visibility 0s;
}
/* Прячется, пока на телефоне к верху экрана прилипли имена вузов в сравнении:
   иначе панель ложится поверх правого имени. Класс ставит js/menu.js. */
.topbar.is-away {
  opacity: 0; transform: translateY(-8px); pointer-events: none;
  visibility: hidden; transition: opacity .2s ease, transform .2s var(--snap), visibility 0s .2s;
}

/* Знак в панели — только на телефоне (на широком экране знак крупно на первом экране).
   Плита той же высоты и вида, что у бургера. */
.topbar__logo {
  display: none; place-items: center;
  width: 46px; height: 44px; padding: 0 5px;
  background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px;
}
.topbar__logo img { display: block; width: 100%; height: auto; }
@media (max-width: 899px) { .topbar__logo { display: grid; } }
/* Узкий телефон: знак, языки и меню в панели плюс «SELENA EDUCATES» слева должны
   встать в одну строку без наложения — языки чуть уже, вордмарк чуть плотнее. */
@media (max-width: 420px) {
  .topbar .langs__opt { min-width: 30px; padding: 0 5px; letter-spacing: .08em; }
  .hero__mark { letter-spacing: .06em; }
}
@media (max-width: 370px) { .hero__mark { font-size: .6875rem; } }

/* RU / EN. Та же пара состояний, что у чипов фильтра: выбранное — заливка
   --action с тёмной подписью, остальное — приглушённый текст на плите. */
.langs {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--bg-raised);
  border: 1px solid var(--line-soft); border-radius: 2px;
}
.langs__opt {
  display: grid; place-items: center;
  min-width: 36px; padding: 0 8px;
  font-size: .75rem; font-weight: 600; letter-spacing: .12em; line-height: 1;
  color: var(--fg-dim); text-decoration: none; border-radius: 1px;
}
.langs__opt:hover { color: var(--fg); }
.langs__opt[aria-current='true'] { background: var(--action); color: var(--on-action); }

/* Три полоски. В меню та же кнопка стоит на том же месте и сложена в крест —
   глаз видит, что бургер превратился в «закрыть», а не что открылось новое окно. */
.burger {
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  background: var(--bg-raised); color: var(--fg);
  border: 1px solid var(--line-soft); border-radius: 2px; cursor: pointer;
}
.burger:hover { border-color: var(--action-edge); color: var(--action-text); }
.burger__bars { display: grid; gap: 5px; width: 18px; }
.burger__bars i {
  display: block; height: 2px; background: currentColor; border-radius: 1px;
  transition: transform .24s var(--snap), opacity .16s ease;
}
.burger.is-open .burger__bars i:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger.is-open .burger__bars i:nth-child(2) { opacity: 0; }
.burger.is-open .burger__bars i:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ── Меню ─────────────────────────────────────────────────────────────────
   Нативный <dialog> панелью справа: на телефоне во весь экран, на широком —
   колонка до 440 px, слева видна притушенная страница. Отступы и раскладка
   шапки повторяют .topbar до пикселя, поэтому RU/EN и крест стоят ровно там,
   где были RU/EN и бургер. Сам диалог без отступов: клик, у которого целью стал
   <dialog>, — это клик по подложке, и он закрывает меню (js/menu.js). */
.menu {
  position: fixed; inset-block: 0; inset-inline: auto 0;
  width: min(440px, 100%); max-width: 100%;
  height: 100%; max-height: 100%;
  margin: 0; padding: 0; border: 0;
  border-inline-start: 1px solid var(--line-soft);
  background: var(--bg); color: var(--fg);
  overflow: hidden;
}
.menu::backdrop { background: color-mix(in srgb, var(--ink) 72%, transparent); }
.menu[open] { display: block; animation: menu-in .32s var(--snap); }
.menu[open]::backdrop { animation: menu-fade .32s ease; }
html:has(.menu[open]) { overflow: hidden; }

.menu__panel {
  display: flex; flex-direction: column; gap: calc(var(--gut) * 4);
  height: 100%; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--pad);
}
.menu__bar { display: flex; justify-content: flex-end; gap: 6px; }

/* <ol> без браузерных номеров и отступа: номер рисует .menu__num. */
.menu__list { display: grid; list-style: none; margin: 0; padding: 0; }
.menu__list li { animation: menu-item .42s var(--snap) both; animation-delay: calc(60ms + var(--i, 0) * 28ms); }
.menu__list a {
  display: flex; align-items: baseline; gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line-soft);
  color: var(--fg); text-decoration: none;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.125rem, 1rem + .6vw, 1.25rem); line-height: 1.3;
  letter-spacing: -0.005em;
}
.menu__list li:first-child a { border-top: 1px solid var(--line-soft); }
.menu__num {
  flex: none; min-width: 2ch;
  font-family: var(--font-body); font-size: .75rem; font-weight: 600; letter-spacing: .12em;
  color: var(--fg-dim);
}
.menu__list a:hover { color: var(--action-text); }
.menu__list a:hover .menu__num { color: var(--action-text); }

.menu__foot { margin-top: auto; display: grid; gap: calc(var(--gut) * 3); }
.menu__cta { justify-content: space-between; }
.menu__contacts { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.menu__contacts a {
  color: var(--fg); text-decoration: none; font-size: .9375rem;
  border-bottom: 1px solid var(--line); padding-bottom: 1px;
}
.menu__contacts a:hover { color: var(--action-text); border-bottom-color: var(--action-text); }

@keyframes menu-in { from { transform: translateX(calc(24px * var(--dir))); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes menu-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes menu-item { from { transform: translateX(calc(16px * var(--dir))); opacity: 0; } to { transform: none; opacity: 1; } }

/* ── Арабская версия: типографика и зеркало ───────────────────────────────
   Раскладку зеркалят логические свойства выше по файлу и --dir. Здесь — то,
   что зеркалом не решается.

   Арабское письмо связное: разрядка (letter-spacing) отрывает буквы слова друг
   от друга, поэтому у арабских заголовков и меток её нет. Капса в арабском нет —
   text-transform там просто ничего не делает. Зато у букв высокие верхние и
   глубокие нижние элементы, и интерлиньяж, подобранный под капс Unbounded
   (1.04–1.2), их сталкивает: строки разведены шире. */
:root[lang='ar'] :is(h1, h2, h3, .label, .fallback th, .cmp__name, .menu__list a, .menu__num,
  .review__highlight, .footer h2, .footer h3) { letter-spacing: 0; }

:root[lang='ar'] body { line-height: 1.75; }
:root[lang='ar'] h1 { line-height: 1.4; max-width: 18ch; }
:root[lang='ar'] h2 { line-height: 1.35; }
/* Ограничение кегля под «ОБРАЗОВАТЕЛЬНОГО» — русское: в арабском заголовке такого
   длинного слова нет, и общий clamp h2 подходит как есть. */
:root[lang='ar'] #route-title { font-size: clamp(1.5rem, 3.6vw, 2.5rem); }
:root[lang='ar'] :is(.route__title, .stat b, .fact b) { line-height: 1.5; }
:root[lang='ar'] :is(.route__text, .about__body p, .review__text p) { line-height: 1.85; }
:root[lang='ar'] :is(.menu__list a, .review__highlight) { line-height: 1.5; }
:root[lang='ar'] .about__tagline { line-height: 1.6; }

/* Маска строк SplitText (overflow: clip по коробке строки) срезала арабские точки
   под буквами нижней строки: «تعليمي» превращалось в «تعليمى». Коробку маски
   расширяем по вертикали и тут же возвращаем раскладке отрицательным полем —
   ни строки, ни секция не сдвигаются. */
:root[lang='ar'] .section__head h2 > [class*='mask'] { padding-block: .3em; margin-block: -.3em; }

/* Стрелка в кнопке смотрит туда, куда читают. */
[dir='rtl'] .cta svg { transform: scaleX(-1); }

/* Номер телефона — латинские цифры и «+» в начале: поле пишет слева направо,
   а прижато, как и всё на странице, к правому краю. */
[dir='rtl'] .field input[type='tel'] { direction: ltr; text-align: right; }

/* ── Перевод ещё не приехал ───────────────────────────────────────────────
   Для en и ar: <head> ставит класс до первой отрисовки, js/i18n.js снимает,
   когда статика переведена (или через 2 с, что бы ни случилось). Прячем краской,
   а не display — раскладка та же, CLS ноль, и русский текст не мелькает. */
.i18n-pending main,
.i18n-pending footer,
.i18n-pending .topbar,
.i18n-pending .skip { visibility: hidden; }

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

/* ══ ПРАВКИ 20.10.2026: Marquette, школы, сопровождение, форматы консультаций ═══
   Новой краски нет: плиты, значки в кругах, --action и --accent-rare — те же
   роли, что в «О нас» и маршруте. Все отступы логические — арабская версия
   зеркалится сама. */

/* Первый экран: две кнопки. Вторая — контурная: главное действие одно. */
.hero__ctas { display: flex; gap: var(--gut); flex-wrap: wrap; }
button.cta { appearance: none; }
.cta--ghost { background: transparent; color: var(--fg); border-color: var(--line); }
.cta--ghost:hover { background: transparent; border-color: var(--action-edge); color: var(--action-text); }
.cta__arrow { display: inline-flex; }
[dir='rtl'] .cta svg, [dir='rtl'] .cta__arrow svg { transform: scaleX(-1); }

/* Неинтерактивный чип: страна или город как метка, не действие. */
.chip--static { display: inline-block; cursor: default; }
.geo .chip--static:hover:not([disabled]) { border-color: var(--line); }

/* ── Marquette Explorer Program ─────────────────────────────────────────── */
.prog { display: grid; gap: calc(var(--gut) * 4); }

/* Схема пути: три плиты, между ними золотая волосяная линия — продолжение
   линии маршрута, не новая доля золота. Последний шаг — с залитым значком. */
.prog__path { display: grid; gap: var(--gut); padding: 0; list-style: none; }
.prog__step {
  position: relative; display: flex; gap: 14px; align-items: start;
  padding: 16px 18px;
  background: var(--bg-raised); border: 1px solid var(--line-soft); border-radius: 2px;
  box-shadow: var(--shadow);
}
.prog__step-body { display: grid; gap: 6px; min-width: 0; }
.prog__step-title { font-size: var(--fs-h3); line-height: 1.2; letter-spacing: -0.01em; }
.prog__step-text { color: var(--fg); font-size: 1rem; line-height: 1.55; }
@media (max-width: 719px) {
  .prog__step:not(:last-child)::after {
    content: ''; position: absolute; inset-inline-start: calc(18px + 22px); top: 100%;
    width: 1px; height: var(--gut); background: var(--accent-rare);
  }
}
@media (min-width: 720px) {
  .prog__path { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .prog__step:not(:last-child)::after {
    content: ''; position: absolute; inset-inline-start: 100%; top: calc(16px + 22px);
    width: var(--gut); height: 1px; background: var(--accent-rare);
  }
}

.prog__result > .ico { grid-row: 1 / span 3; }
.prog__result .label { color: var(--fg-dim); }

.prog__accent {
  max-width: 60ch;
  padding-inline-start: 18px;
  border-inline-start: 3px solid var(--action-edge);
  font-size: clamp(1.0625rem, 1.6vw, 1.3125rem); line-height: 1.45; font-weight: 600;
}

.prog__blocks { display: grid; gap: calc(var(--gut) * 4); }
@media (min-width: 900px) { .prog__blocks { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); } }
.prog__groups { display: grid; gap: var(--gut); }
@media (min-width: 560px) { .prog__groups { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.prog__group { padding: 16px 18px; display: grid; gap: 10px; align-content: start; }
.prog__group-title { font-family: var(--font-body); font-size: .9375rem; font-weight: 600; letter-spacing: 0; line-height: 1.3; margin: 0; }
.prog__unis { display: grid; gap: 2px; }
/* Имя вуза — ссылка на его карточку в каталоге. Подчёркивание держит
   --line, а не цвет: акцент на списке из шести имён был бы шумом. */
.prog__uni {
  font: inherit; font-size: .9375rem; text-align: start; cursor: pointer;
  background: 0; border: 0; padding: 6px 0; color: var(--fg);
  text-decoration: underline; text-decoration-color: var(--line);
  text-underline-offset: 4px; text-decoration-thickness: 1px;
}
.prog__uni:hover { color: var(--action-text); text-decoration-color: currentColor; }
.prog__uni:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.prog__foot { display: flex; flex-wrap: wrap; gap: var(--gut); }

/* ── Поступление в школы ───────────────────────────────────────────────── */
.schools { display: grid; gap: calc(var(--gut) * 4); }
.schools__grid { display: grid; gap: calc(var(--gut) * 4); }
@media (min-width: 960px) { .schools__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr); } }
.schools__side { display: grid; gap: calc(var(--gut) * 3); align-content: start; }
.schools__body { color: var(--fg); font-size: var(--fs-body); line-height: 1.6; max-width: 52ch; }
/* Системы — тот же список с квадратиком, что направления в «О нас», но в одну
   колонку: четыре пункта разной длины в две колонки ломали бы ритм. */
.dirs.schools__systems { grid-template-columns: 1fr; grid-template-rows: none; grid-auto-flow: row; }
.schools__support { display: grid; gap: var(--gut); padding: 0; list-style: none; }
@media (min-width: 560px) { .schools__support { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.schools__support li {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: 14px; row-gap: 4px; align-items: start; padding: 16px 18px;
}
.schools__support .ico { grid-row: 1 / span 2; }
.schools__num { font-family: var(--font-display); font-size: .75rem; line-height: 1.2; color: var(--action-text); }
.schools__support p { font-size: 1rem; line-height: 1.5; }

/* ── Как проходит сопровождение ────────────────────────────────────────── */
.route--flat { padding: 0; }
.route--flat::before { content: none; }
@media (min-width: 1100px) {
  .route--flat .route__steps[data-steps='5'] { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* ── Два формата консультации над формой ───────────────────────────────── */
.consult__opts { display: grid; gap: var(--gut); max-width: 1040px; margin-bottom: calc(var(--gut) * 3); }
@media (min-width: 720px) { .consult__opts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.consult__opt {
  font: inherit; color: var(--fg); text-align: start; cursor: pointer;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 14px; row-gap: 6px; align-items: start; padding: 18px;
  transition: border-color .2s var(--snap), box-shadow .2s var(--snap);
}
.consult__opt > .ico { grid-row: 1 / span 2; }
.consult__title { grid-column: 2; font-weight: 700; font-size: var(--fs-h3); line-height: 1.25; color: var(--fg-strong); }
.consult__text { grid-column: 2; color: var(--fg); font-size: 1rem; line-height: 1.5; }
/* Кружок выбора — как у радиокнопки: выбран формат или нет, видно без цвета. */
.consult__pick {
  grid-column: 3; grid-row: 1; width: 20px; height: 20px;
  border: 1px solid var(--line); border-radius: 50%;
}
.consult__opt:hover { border-color: var(--line); }
.consult__opt[aria-pressed='true'] { border-color: var(--action-edge); box-shadow: inset 0 0 0 1px var(--action-edge), var(--shadow); }
.consult__opt[aria-pressed='true'] .consult__pick {
  background: var(--action); border-color: var(--action-edge);
  box-shadow: inset 0 0 0 4px var(--bg-raised);
}
.consult__opt:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
/* Блоки рядом не тянут друг друга по высоте: иначе многострочный ряд чипов
   растягивался на высоту соседней колонки и чипы разъезжались. */
.prog__blocks { align-items: start; }
.geo { align-content: flex-start; }

/* ── Результаты студентов (25.10.2026) ─────────────────────────────────────
   Четыре карточки: крупная оранжевая цифра — главное, вуз — заголовок карточки.
   Секция белая, поэтому #E8750A крупным кеглем проходит (3.0, порог для
   крупного текста 3:1). */
.cases { display: grid; gap: calc(var(--gut) * 2); padding: 0; list-style: none; }
@media (min-width: 720px) { .cases { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .cases { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.case { display: flex; flex-direction: column; gap: 12px; padding: 24px; }
.case__value { display: grid; gap: 4px; }
.case__value b {
  font-family: var(--font-display); font-weight: 800; font-size: var(--fs-num); line-height: 1.05;
  letter-spacing: -0.02em; color: var(--orange); font-variant-numeric: tabular-nums;
  justify-self: start; white-space: nowrap;
}
.case__value span { font-size: .9375rem; font-weight: 600; color: var(--fg-strong); }
.case__uni { padding-top: 12px; border-top: 1px solid var(--line-soft); margin-bottom: 8px; }
/* Кнопка документа — внизу карточки, чтобы в ряду все четыре стояли на одной линии. */
.case__doc { margin-top: auto; align-self: start; text-decoration: none; }
