/* Особенности страниц. Компоненты — в components.css, значения — токены из tokens.css.
   План: docs/Визуальный-план-v3.md, разделы 12 и 13. Все страницы на композициях v3 (этапы 2–9). */

/* ===== Первый раздел страницы: воздух над заголовком первого экрана (7.1) =====
   Между разделами — --section-gap (layout.css). */
.main > .section:first-child { margin-top: var(--sp-8); }

/* ===== Вход и регистрация: одна стеклянная карточка по центру ===== */
.auth {
  max-width: var(--auth-width);
  margin-inline: auto;
  padding: var(--sp-5);
}
@media (min-width: 600px) {
  .auth { padding: var(--sp-6); }
}
.auth > * + * { margin-top: var(--sp-5); }
.auth h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2); }

/* ===== Политика (13): текст до 68ch ===== */
.policy .lead { margin-top: var(--sp-3); }
.policy__text { margin-top: var(--sp-7); }
.policy__text h2 { font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--ls-h3); }
.policy__text h2 + p { margin-top: var(--sp-3); }
.policy__text p + h2 { margin-top: var(--sp-6); }
.policy__text ul { margin-top: var(--sp-3); padding-left: var(--sp-5); list-style: disc; }
.policy__text li + li { margin-top: var(--sp-2); }
.policy__text ul + h2, .policy__text ul + p { margin-top: var(--sp-4); }
.policy__text p + ul { margin-top: var(--sp-3); }
.policy__text p + p { margin-top: var(--sp-3); }

/* ===== 404 (13): короткое состояние по центру (5) ===== */
.not-found { padding-block: var(--sp-8); text-align: center; }
.not-found .display { text-wrap: balance; }
.not-found .lead { max-width: var(--measure); margin: var(--sp-4) auto 0; text-wrap: pretty; }
.not-found__code { font-size: var(--fs-score); line-height: 1; font-weight: 600; color: var(--text-2); margin-bottom: var(--sp-4); }
.not-found__actions { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--sp-4); margin-top: var(--sp-6); }

/* ===== Тест (план дизайна теста v2, 2–4; визуальный план v3, 12.12, 13): колонка до 640 px ===== */
.quiz-page { display: flex; flex-direction: column; gap: var(--sp-5); }

/* Строка заголовка (2.2): h1, справа «Начать заново»; на телефоне «Начать заново» — под абзацем */
.quiz-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--sp-4); align-items: baseline; }
.quiz-head__title { grid-area: 1 / 1 / 2 / -1; }
.quiz-head__lead { grid-area: 2 / 1 / 3 / -1; margin-top: var(--sp-3); }
.quiz-head__restart { grid-area: 3 / 1 / 4 / -1; justify-self: end; margin-top: var(--sp-3); }
@media (min-width: 600px) {
  .quiz-head__title { grid-area: 1 / 1; }
  .quiz-head__restart { grid-area: 1 / 2; margin-top: 0; }
}

/* Счётчик (2.3): «Около 5 минут» / «Вопрос N» / «Ещё пара вопросов» */
.quiz__count { margin-bottom: var(--sp-3); color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }

/* Карточка вопроса (2.4): высота постоянная — у сцены и плиток фиксированная высота в строках (lh) */
.question { margin: 0; padding: var(--sp-5); border: 0; }
@media (min-width: 600px) {
  .question { padding: var(--sp-6); }
}
/* legend внутри fieldset браузер рисует на рамке; float возвращает его внутрь блока */
.question__text {
  float: left;
  width: 100%;
  height: calc(var(--quiz-scene-lines) * 1lh);
  margin-bottom: var(--sp-5);
  padding: 0;
  font-size: var(--fs-h4);
  line-height: var(--lh-h4);
  letter-spacing: var(--ls-h4);
  font-weight: var(--fw-semibold);
  text-wrap: balance;
}
.question__text + * { clear: both; }

/* Плитки-занятия — .btn .btn--lg: столбиком, от 768 px в ряд, между ними «или».
   [допущение: в плане ряд от 600 px. Замер по всему банку: в ряд при карточке уже 640 px
   (600–687 px) занятия занимают до 6 строк; столбиком до 768 px и с полями 16 px
   любое занятие банка помещается в 3 строки на любой ширине]
   Фон --raise нет (блок не .card), берутся запасные --surface-2 / --surface-3 — те же ступени */
.question__choices { display: flex; flex-direction: column; gap: var(--sp-2); }
.question__choice {
  height: calc(var(--quiz-plate-lines) * 1lh + 2 * var(--btn-pad-y-lg));
  padding-inline: var(--sp-4);
  white-space: normal;
  text-align: center;
  text-wrap: balance;
}
.question__or { align-self: center; color: var(--text-3); font-size: var(--fs-small); line-height: var(--lh-small); }
@media (min-width: 768px) {
  .question { --quiz-scene-lines: 1; }  /* сцены до 45 знаков в карточке 640 px — в одну строку */
  .question__choices { flex-direction: row; align-items: center; gap: var(--sp-3); }
  .question__choice { flex: 1 1 0; min-width: 0; }
}

/* Отклик выбора и смена вопроса (план v2, 5). Классы ставит quiz.js; без JS ничего этого нет.
   Пока идёт запрос, кнопки disabled — но выглядят как выбранная и погасшая, а не как недоступные. */
.question__choice {
  transition:
    background-color var(--dur-pick) var(--ease),
    color var(--dur-pick) var(--ease),
    transform var(--dur-press) var(--ease),
    opacity var(--dur-pick) var(--ease);
}
.question__choice:disabled,
.question__none:disabled { color: var(--text-2); cursor: default; }
.question__choice.is-picked { --btn-bg: var(--surface-4); }
.question__choice.is-dimmed { opacity: var(--pick-dim); }
.question__choice.is-half { opacity: var(--pick-half); }

[data-quiz-slot] { transition: opacity var(--dur-step) var(--ease), transform var(--dur-step) var(--ease); }
[data-quiz-slot].is-leaving { opacity: 0; transform: translateX(calc(-1 * var(--step-shift))); }
[data-quiz-slot].is-entering { opacity: 0; transform: translateX(var(--step-shift)); transition: none; }
[data-quiz-slot].is-entering .question__or + .question__choice { opacity: 0; transition: none; }
[data-quiz-slot].is-arriving .question__or + .question__choice {
  transition-duration: var(--dur-pick), var(--dur-pick), var(--dur-press), var(--dur-step);
  transition-delay: 0s, 0s, 0s, var(--stagger-pair);
}

/* «Не могу выбрать» — тихая текстовая кнопка по центру под плитками */
.question__none { display: flex; width: fit-content; margin: calc(var(--sp-5) - var(--sp-2)) auto calc(-1 * var(--sp-2)); }  /* компенсация полей .btn--text */


/* ----- Фигуры текущей пары (4): слой за блоком вопроса, места a1, a2 (левое занятие), b1, b2 (правое) -----
   До 1024 px — только a1 и b1 под карточкой, у краёв экрана, частично срезаны.
   От 1024 px — по две в полях слева и справа от карточки, раскладка .qfigs--lN (номер с сервера).
   Позиция места — свойство translate: при смене раскладки места переезжают (quiz.js, часть 3).
   Расстояние до карточки: --k — доля свободного поля (не дальше --qfig-reach), --y — от верха блока.
   Раскладки не зеркальны, но у левой и правой пары одни размеры и похожие расстояния. [допущение: координаты] */
.quiz-stage { position: relative; }
.qfigs { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.qfig {
  position: absolute;
  top: calc(100% + var(--sp-5));
  width: var(--qfig-size);
  height: var(--qfig-size);
  opacity: var(--qfig-op);
}
.qfig--a1, .qfig--b1 { --qfig-size: var(--qfig-phone); --qfig-op: var(--fig-op-near); }
.qfig--a2, .qfig--b2 { display: none; --qfig-size: var(--fig-mid); --qfig-op: var(--fig-op-mid); }
.qfig--a1 { left: calc(50% - 50vw - var(--qfig-size) * (1 - var(--fig-giant-visible))); }
.qfig--b1 { left: calc(50% + 50vw - var(--qfig-size) * var(--fig-giant-visible)); }
.qfig__float {
  width: 100%;
  height: 100%;
  animation: fig-float var(--float-dur, var(--float-near)) var(--ease-float) var(--float-delay, 0s) infinite alternate;
}
/* Старая и новая фигура места лежат друг на друге: при смене вопроса одна гаснет, другая проявляется */
.qfig__float { position: relative; }
.qfig__shape { position: absolute; inset: 0; color: var(--c, var(--text-2)); transition: opacity var(--dur-reveal) var(--ease); }
.qfig__shape.is-new,
.qfig__shape.is-old { opacity: 0; }
[data-theme="light"] .qfig__shape { color: var(--c-ink, var(--text-2)); }
.qfig__shape svg { display: block; width: 100%; height: 100%; }
@media (max-width: 1023.98px) {
  .quiz-page { padding-bottom: calc(var(--qfig-phone) + var(--sp-5)); }  /* место под фигуры у краёв */
}
@media (min-width: 1024px) {
  .qfigs { --field: calc((100vw - var(--quiz-width)) / 2); }        /* поле сбоку от карточки */
  .qfig {
    --free: min(var(--field) - var(--qfig-size) - var(--sp-4) - var(--sp-5), var(--qfig-reach));
    --d: calc(var(--sp-4) + var(--free) * var(--k));
    top: 0;
    transition: translate var(--dur-fig-move) var(--ease);
  }
  .qfig--a1, .qfig--b1 { --qfig-size: var(--fig-near); }
  .qfig--a2, .qfig--b2 { display: block; }
  .qfig--a1, .qfig--a2 { left: auto; right: 100%; translate: calc(-1 * var(--d)) var(--y); }
  .qfig--b1, .qfig--b2 { left: 100%; translate: var(--d) var(--y); }
  .qfig--a1 { --k: var(--a1k); --y: var(--a1y); }
  .qfig--a2 { --k: var(--a2k); --y: var(--a2y); }
  .qfig--b1 { --k: var(--b1k); --y: var(--b1y); }
  .qfig--b2 { --k: var(--b2k); --y: var(--b2y); }

  .qfigs--l0 { --a1k: .55; --a1y: -24px; --a2k: .15; --a2y: 196px; --b1k: .25; --b1y: 150px; --b2k: .7;  --b2y: 8px; }
  .qfigs--l1 { --a1k: .2;  --a1y: 120px; --a2k: .75; --a2y: -16px; --b1k: .6;  --b1y: 24px;  --b2k: .2;  --b2y: 210px; }
  .qfigs--l2 { --a1k: .45; --a1y: 180px; --a2k: .3;  --a2y: 16px;  --b1k: .35; --b1y: -12px; --b2k: .55; --b2y: 200px; }
  .qfigs--l3 { --a1k: .7;  --a1y: 64px;  --a2k: .1;  --a2y: 226px; --b1k: .15; --b1y: 96px;  --b2k: .65; --b2y: -30px; }
  .qfigs--l4 { --a1k: .3;  --a1y: -30px; --a2k: .6;  --a2y: 176px; --b1k: .5;  --b1y: 170px; --b2k: .25; --b2y: -20px; }
  .qfigs--l5 { --a1k: .1;  --a1y: 92px;  --a2k: .5;  --a2y: -36px; --b1k: .4;  --b1y: 60px;  --b2k: .1;  --b2y: 220px; }
}
@media (prefers-reduced-motion: reduce) {
  .qfig__float { animation: none; }
}

/* ----- Маршрут прогресса (3): кривая, 4 остановки, ромб с кругом. Разметка — quiz/_route.html -----
   До 1024 px — компактный над счётчиком (ширина колонки), от 1024 px — широкий во всю ширину окна.
   Пройденная часть и путь впереди вырезаются масками по --progress (0–100). */
.route { position: relative; display: flex; align-items: center; color: var(--c, var(--text-2)); pointer-events: none; transition: color var(--dur-slow) var(--ease); }
[data-theme="light"] .route { color: var(--c-ink, var(--text-2)); }
.route__track { position: relative; flex: 1; min-width: 0; }
.route__line { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.route__done,
.route__ahead { fill: none; stroke: currentColor; stroke-width: var(--route-line); stroke-linecap: round; vector-effect: non-scaling-stroke; }
.route__done { opacity: var(--route-op); }
.route__ahead { stroke-dasharray: var(--route-dash); opacity: var(--route-op-ahead); }
/* 100 — pathLength путей масок: маска пройденного открывает [0, progress], маска пути — [progress, 100] */
.route__mask--done { stroke-dashoffset: calc((100 - var(--progress)) * 1px); }
.route__mask--ahead { stroke-dashoffset: calc(var(--progress) * -1px); }
.route__mask { transition: stroke-dashoffset var(--dur-route) var(--ease); }  /* дорисовка после ответа */
.route__stop {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--route-stop);
  height: var(--route-stop);
  translate: -50% -50%;
  border: var(--route-stop-line) solid currentColor;
  border-radius: var(--r-round);
  opacity: var(--route-op-ahead);
  transition: background-color var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.route__stop.is-passed { background: currentColor; opacity: var(--route-op); }
.route__finish {
  flex: none;
  width: var(--route-mark);
  height: var(--route-mark);
  fill: none;
  stroke: currentColor;
  stroke-width: var(--route-line);
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  opacity: var(--route-op-ahead);
  transition: opacity var(--dur-slow) var(--ease);
}
.route__finish * { vector-effect: non-scaling-stroke; }
.route.is-finished .route__finish { opacity: 1; }  /* финал: линия дошла до ромба */
.route--compact .route__track { height: var(--route-compact-h); }
.route--compact .route__finish { width: var(--route-mark-compact); height: var(--route-mark-compact); }
.route--wide { display: none; }
@media (min-width: 1024px) {
  .route--compact { display: none; }
  .route--wide {
    display: flex;
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    padding-inline-end: var(--gutter);
  }
  .route--wide .route__track { aspect-ratio: 1600 / 140; }  /* холст кривой в _route.html */
}

/* ===== Результат теста (план дизайна теста v2, 6; визуальный план v3, 12.13, 13) =====
   Первый экран: заголовок, фраза, описания сильных типов, кнопки. Ниже [ Области XL, главная ][ Полосы M ]. */
.result-head__lead { max-width: var(--measure); margin-top: var(--sp-4); }

/* Описания сильных типов: 1–3 колонки на компьютере (--cols — число сильных типов), на телефоне столбиком */
.result-desc { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); margin-top: var(--sp-6); }
@media (min-width: 768px) {
  .result-desc { grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr)); }
}
.result-desc__name { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-h4); line-height: var(--lh-h4); letter-spacing: var(--ls-h4); }
.result-desc__type p { max-width: var(--measure); margin-top: var(--sp-2); color: var(--text-2); }
.result-desc__type p:first-child { margin-top: 0; }  /* один тип: только описание, без названия */

.result-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4); margin-top: var(--sp-6); }
.result-actions__note { margin-top: var(--sp-3); }

/* Появление первого экрана (6.3): по очереди, шаг --stagger. Только с JS (класс js ставится в <head>
   до отрисовки) и без «уменьшить движение»; это CSS-анимация — она доигрывает сама, даже если motion.js
   не запустился, и ничего не остаётся скрытым. motion.js первый экран не трогает (показывает сразу). */
@media (prefers-reduced-motion: no-preference) {
  .js .result-head > * { animation: result-rise var(--dur-reveal) var(--ease) both; animation-delay: calc(var(--i, 0) * var(--stagger)); }
}
.result-head > :nth-child(2) { --i: 1; }
.result-head > :nth-child(3) { --i: 2; }
.result-head > :nth-child(4) { --i: 3; }
.result-head > :nth-child(5) { --i: 4; }
@keyframes result-rise {
  from { opacity: 0; transform: translateY(var(--reveal-shift)); }
}

/* Области: строка — точка цвета типа, название, под ним 2–3 направления; вся строка — ссылка в подбор */
.result-area { align-items: flex-start; }
.result-area .dot { margin-top: calc((1lh - var(--dot)) / 2); }
.result-area__text { flex: 1; min-width: 0; }
.result-area__name { color: var(--text); }
.result-area__dirs { margin-top: var(--sp-1); color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }

.result-types .bars { margin-top: var(--sp-2); }

/* ===== Лента ===== */

/* ===== Лента вузов (13) ===== */
.feed-head .lead { max-width: var(--measure); margin-top: var(--sp-3); }
.feed-result__lead { margin-top: var(--sp-1); color: var(--text-2); }  /* названия ведущих типов (план дизайна теста v2, 7.2) */
.feed-result .bars { margin-top: var(--sp-1); }
.feed-quiz > p:not([class]) { color: var(--text-2); }

/* ===== Проверочная страница фигур (/dev/figures/, только DEBUG) ===== */
.fig-check-giant ~ .fig-check-giant { display: none; }
.fig-check {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--fig-check-cell), 1fr));
  gap: var(--sp-4);
}
.fig-check__item {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  color: var(--text-2);
}
.fig-check__swatches { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
/* data-theme на плашке включает токены темы локально, c--<тип> — цвет области в этой теме */
.fig-check__swatch {
  display: grid;
  place-items: center;
  padding: var(--sp-2);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--c, var(--text));
}
.fig-check__swatch[data-theme="light"] { color: var(--c-ink, var(--text)); }  /* как .fig на сайте */
.fig-check__swatch svg { width: var(--fig-check-lg); height: var(--fig-check-lg); }
.fig-check__swatch--sm svg { width: var(--fig-check-sm); height: var(--fig-check-sm); }

/* ===== Подбор программ (/podbor/, промт подбора 4.2) [допущение: композиция в 13] =====
   Три раздела: заголовок; баллы + фильтры; результаты по группам. */
.podbor-head__lead { margin-top: var(--sp-3); }
/* Слева колонка: баллы и «Где учиться»; справа области. На планшете колонка на всю ширину над областями */
.podbor-form { display: contents; }
.podbor-side { display: flex; flex-direction: column; gap: var(--gap-tight); }
.podbor-side > .card { flex: none; }
.podbor-side > .where { flex: 1; }  /* низ колонки вровень с плиткой областей */
@media (min-width: 600px) and (max-width: 1023.98px) {
  .podbor-side { grid-column: 1 / -1; }
}
.where { gap: var(--sp-4); }
.where__fields { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-4) var(--sp-3); }
@media (min-width: 600px) {
  .where__fields { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }  /* слева «Бюджет и платное» — длиннее */
  /* Баллы в одну строку: три предмета помещаются в узкую колонку */
  .podbor-exams .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4) var(--sp-3); }
}
@media (min-width: 600px) and (max-width: 1023.98px) {
  .where__fields { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* Десктоп: левая колонка шире обычной M (5 из 12), чтобы поля 2×2 не обрезались; области — 7 */
@media (min-width: 1024px) {
  .podbor-side { --span: 5; }
  .podbor-side + .filters { --span: 7; }
}
.where__fee[hidden] { display: none; }
.podbor-head__quiz { margin-top: var(--sp-4); }

.podbor-exams__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.podbor-exams .stats { margin-top: var(--sp-2); }
.podbor-exams .card__footer { flex-wrap: wrap; }

/* Фильтры: всегда открыты, заголовок и сводка выбранного в одну строку */
.filters { gap: 0; }
.filters__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3); }
.filters__title { font-size: var(--fs-h4); line-height: var(--lh-h4); letter-spacing: var(--ls-h4); }
.filters__state { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.filters__form { flex: 1; display: flex; flex-direction: column; gap: var(--sp-5); margin-top: var(--sp-5); }
.filters__form .form__actions { margin-top: auto; }  /* сброс — внизу плитки, вровень с левой колонкой */
/* Живой подбор (live-podbor.js): форма применяется сама — кнопка «Показать программы» не нужна */
.podbor-form.is-live [data-live-submit] { display: none; }
.filters__areas { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; margin: 0; padding: 0; border: 0; }
.filters__areas legend { float: left; width: 100%; padding: 0; }  /* legend в потоке flex, иначе gap не работает */

/* Результаты: группы внутри одного раздела, между ними меньше воздуха, чем между разделами */
.results > * + * { margin-top: var(--sp-8); }
.results__group { scroll-margin-top: calc(var(--header-h) + var(--header-offset) + var(--sp-4)); }
.results__group > * + * { margin-top: var(--sp-5); }

.group-head { display: flex; flex-direction: column; gap: var(--sp-2); }
.group-head__title { display: flex; align-items: center; gap: var(--sp-3); }
.group-head__title .chance { --chance-size: var(--sp-4); }
.group-head__count { color: var(--text-2); font-weight: var(--fw-regular); }
.group-head__hint { max-width: var(--measure); color: var(--text-2); }

/* «Показать ещё» под группой: кнопка и подпись «Показано N из M» в одну линию */
.results__more { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4); }

/* «Шансы пока не посчитать»: тихий список строк в одной карточке */
.unknown-list { padding-block: var(--sp-2); }
.unknown-row { align-items: flex-start; }
.unknown-row .dot { margin-top: calc((var(--lh-body) * 1em - var(--dot)) / 2); }
.unknown-row__name { display: block; }
.unknown-row__meta { display: block; color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.unknown-row__score { font-size: var(--fs-small); white-space: nowrap; }
.unknown-row__save { position: relative; z-index: 1; }
.unknown-row__save .btn { white-space: nowrap; }
@media (max-width: 599.98px) {
  .unknown-row { flex-wrap: wrap; }
  .unknown-row__score,
  .unknown-row__save { margin-left: calc(var(--dot) + var(--sp-3)); }
}

/* ===== Баллы ЕГЭ (/exams/, промт подбора 4.3): карточки в .compose, как профиль и настройки =====
   Предмет — строка «название — узкое поле». Баллы сохраняются сами (exams-autosave.js). */
.exams-actions { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3); }
.exams-actions [data-autosave-status]:empty { display: none; }

.exams__subjects {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-3) var(--sp-5);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
@media (min-width: 600px) {
  .exams__subjects { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.exam-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--exam-input);
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
}
.exam-field__label { font-size: var(--fs-small); line-height: var(--lh-small); }
.exam-field__input { text-align: center; }
.exam-field__hint,
.exam-field__error { grid-column: 1 / -1; }
.exam-field:has(.field__error) .input { border-color: var(--danger); }

/* ===== Страница вуза (13; 12.7, 12.11, 12.14, 12.18) =====
   Шапка: город, название, действия; ряд [ О вузе L ][ число + мини-график S ][ области S ];
   вкладки О вузе | Программы | Новости | Фото | Отзывы (tabs.js). */
.uni-head__city { color: var(--text-2); }
.uni-head__title h1 { margin-top: var(--sp-2); }
.uni-head__title .lead { margin-top: var(--sp-3); }
.uni-head__actions { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); }
@media (min-width: 1024px) {
  .uni-head__actions { justify-content: flex-end; }
}
.uni-head__cards { margin-top: var(--sp-7); }

/* Плитки-ссылки на вкладки (шаг «плитка → вкладка», tabs.js): вся карточка — одна растянутая ссылка.
   Наведение — общее .card--link (фон на ступень, подъём, --dur-base); стрелка ↗ проявляется за --dur-fast.
   Фокус с клавиатуры — обводка по контуру всей плитки, у самой ссылки её нет */
.uni-tile__link { color: inherit; }
.uni-tile__link:hover { color: inherit; }
.uni-tile__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.uni-tile__link:focus-visible { outline: none; }
.uni-tile:has(.uni-tile__link:focus-visible) { outline: var(--border-strong) solid var(--focus); outline-offset: var(--focus-offset); }
.uni-tile > :first-child { padding-right: calc(var(--icon-size) + var(--sp-2)); }
.uni-tile__arrow {
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  width: var(--icon-size);
  height: var(--icon-size);
  color: var(--text-2);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
  pointer-events: none;
}
.uni-tile:hover .uni-tile__arrow,
.uni-tile:has(.uni-tile__link:focus-visible) .uni-tile__arrow { opacity: 1; }

/* Текст «О вузе» — до 5 строк, полный текст во вкладке */
.uni-about__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  overflow: hidden;
  color: var(--text);
}
/* Одно крупное число: подпись во всю ширину карточки, не в узкую колонку .stats */
.uni-key .stats { grid-template-columns: minmax(0, 1fr); }
.uni-key .stat dd { font-size: var(--fs-score); line-height: 1; }
.uni-key__program { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.uni-key .chart { margin-top: auto; }
.uni-key__chance { margin-top: var(--sp-2); font-size: var(--fs-small); line-height: var(--lh-small); }
/* Узкая плитка (1024 px): длинное слово («предпринимательство») переносится по слогам (lang="ru" в base.html),
   а не наезжает на число программ; число не сжимается */
.uni-areas .list__name { overflow-wrap: anywhere; hyphens: auto; }
.uni-areas .list__value { flex-shrink: 0; }
.uni-areas__hint { margin-top: auto; color: var(--text-2); font-size: var(--fs-caption); line-height: var(--lh-caption); }

/* Второй ряд: [ карта L ][ правая колонка .uni-side L: фото + новость ]. Модификаторы — из шаблона.
   Телефон и планшет: всё по содержимому одной колонкой (фото, новость, карта), фото 4:3 как карта.
   Десктоп с картой: колонка не участвует в высоте ряда (height: 0) и тянется до низа квадрата карты
   (min-height: 100%); фото забирает остаток, новость — по содержимому.
   Десктоп без карты: фото и новость рядом 6 + 6, высота по содержимому, фото 4:3. */
.uni-side {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-tight);
  align-content: start;
}
.uni-side > * { min-width: 0; }
.uni-photo-tile { aspect-ratio: 4 / 3; }

@media (min-width: 1024px) {
  /* Карта слева, колонка справа: в разметке колонка раньше карты (порядок на телефоне) */
  .uni-side--map { order: 2; }
  .uni-head__cards > .uni-map { order: 1; }

  .uni-side--map {
    height: 0;
    min-height: 100%;
    grid-template-rows: minmax(0, 1fr);
    align-content: stretch;
  }
  .uni-side--map.uni-side--photo.uni-side--news { grid-template-rows: minmax(0, 1fr) auto; }
  .uni-side--map .uni-photo-tile { aspect-ratio: auto; }

  /* Нет карты, есть фото и новость — рядом 6 + 6 */
  .uni-side--photo.uni-side--news:not(.uni-side--map) {
    grid-column: span 12;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-content: stretch;
  }
}

/* Плитка «Фото»: лента фото на всю площадь, скругление как у карты, без подъёма при наведении.
   Листание — горизонтальная прокрутка со scroll-snap; кнопки ‹ › в стекле по краям (как кнопки карты),
   внизу стеклянные метки: слева «Все фото · N», справа счётчик «n / 5» (uni-photos.js) */
.uni-photo-tile {
  gap: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(0 round var(--r-lg));
  background: var(--surface-2);  /* видно, пока фото грузится */
}
.uni-photo-tile__track {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  border-radius: inherit;
}
.uni-photo-tile__track::-webkit-scrollbar { display: none; }
.uni-photo-tile__track:focus { outline: none; }  /* tabindex="-1" — фокус только программный */
.uni-photo-tile__slide {
  display: block;
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.uni-photo-tile img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Кнопки ‹ › — стеклянные кнопки-иконки, как у карты. По центру по высоте через calc:
   у .btn transform занят анимацией нажатия */
.uni-photo-tile__nav {
  --btn-bg: var(--glass-bg);
  --btn-bg-hover: var(--glass-bg-hover);
  position: absolute;
  top: calc(50% - var(--icon-btn) / 2);
  border-radius: var(--r-md);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  transition: opacity var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.uni-photo-tile__nav--prev { left: var(--sp-3); }
.uni-photo-tile__nav--next { right: var(--sp-3); }
/* С мышью стрелки видны при наведении и при фокусе внутри плитки; на тач-устройствах — всегда */
@media (hover: hover) {
  .uni-photo-tile__nav { opacity: 0; }
  .uni-photo-tile:hover .uni-photo-tile__nav,
  .uni-photo-tile:focus-within .uni-photo-tile__nav { opacity: 1; }
}

/* Стеклянные метки внизу: «Все фото · N» (ссылка, в фокусе с клавиатуры) и счётчик */
.uni-photo-tile__chip {
  position: absolute;
  bottom: var(--sp-3);
  margin: 0;
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--r-sm);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.uni-photo-tile__all { left: var(--sp-3); color: var(--text); transition: background-color var(--dur-fast) var(--ease); }
.uni-photo-tile__all:hover { background: var(--glass-bg-hover); color: var(--text); }
.uni-photo-tile__counter { right: var(--sp-3); color: var(--text-2); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .uni-photo-tile__nav { --btn-bg: var(--glass-fallback); }
  .uni-photo-tile__chip { background: var(--glass-fallback); }
}

/* Плитка «Новость»: подпись, дата, заголовок до 3 строк, анонс до 2, внизу «Все новости →» */
.uni-news-tile__date { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.uni-news-tile__title,
.uni-news-tile__summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.uni-news-tile__title {
  -webkit-line-clamp: 3;
  line-clamp: 3;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}
.uni-news-tile__summary {
  -webkit-line-clamp: 2;
  line-clamp: 2;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
/* Узкий десктоп с картой: без анонса, иначе фото над новостью ниже ~250 px (на 1024 — около 190) */
@media (min-width: 1024px) and (max-width: 1199.98px) {
  .uni-side--map.uni-side--photo .uni-news-tile__summary { display: none; }
}
.uni-news-tile__more {
  margin-top: auto;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}

/* Карта вуза (uni-map.js): плитка .card span-l во втором ряду композиции, под «О вузе».
   Без отступов — карта заполняет плитку. Не кликабельная: без подъёма и смены фона.
   Фон --surface-1 виден, пока грузятся тайлы, и без JS. Поверх — стеклянные плашки, отступ 12 px.
   clip-path скругляет углы: Firefox не обрезает WebGL-холст через overflow + border-radius */
.uni-map {
  gap: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(0 round var(--r-lg));
  aspect-ratio: 1 / 1;
  /* Safari игнорирует aspect-ratio у элемента, растянутого по высоте ряда сетки (align-self: stretch):
     содержимое карты absolute, поэтому высота выходила 0, а колонка с фото и новостью (height: 0;
     min-height: 100%) схлопывалась и наезжала на вкладки. start — высота строго по aspect-ratio */
  align-self: start;
}
@media (min-width: 600px) and (max-width: 1023px) {
  .uni-map { aspect-ratio: 4 / 3; }
}
/* Двойной класс сильнее .maplibregl-map { position: relative } из CSS библиотеки,
   иначе у холста высота 0. isolation — слои MapLibre (z-index) не всплывают над нашими плашками */
.uni-map .uni-map__canvas {
  position: absolute;
  inset: 0;
  isolation: isolate;
  border-radius: inherit;
  background: var(--surface-1);
  font: inherit;
}
.uni-map .maplibregl-canvas-container,
.uni-map .maplibregl-canvas { border-radius: inherit; }
/* Фокус на холсте карты (стрелки двигают карту) — внутри плитки: снаружи его обрезал бы clip-path */
.uni-map .maplibregl-canvas:focus-visible { outline: var(--border-strong) solid var(--focus); outline-offset: calc(-1 * var(--border-strong)); }

/* Стекло для плашек поверх карты (4.2): размытие обязательно, без него — плотный фоллбэк */
.uni-map__glass {
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .uni-map__glass { background: var(--glass-fallback); }
}

/* Метка: капля --text с точкой --bg, без тени. Кончик в точке вуза (anchor: 'bottom' в uni-map.js) */
.uni-map__pin { width: var(--map-pin); height: var(--map-pin); }
.uni-map__pin::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-round) var(--r-round) var(--r-round) 0;
  background: var(--text);
  transform: rotate(-45deg);
}
.uni-map__pin::after {
  content: "";
  position: absolute;
  inset: calc((var(--map-pin) - var(--map-pin-dot)) / 2);
  border-radius: var(--r-round);
  background: var(--bg);
}

/* Группа кнопок-иконок справа вверху: +/− (uni-map.js) и «Открыть в OpenStreetMap» (ссылка в разметке).
   .btn--icon 40×40, на телефоне 44×44; между кнопками --divider. Без JS в группе одна ссылка */
.uni-map__controls {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-md);
  clip-path: inset(0 round var(--r-md));
}
.uni-map__controls .btn--icon { --btn-bg-hover: var(--glass-bg-hover); border-radius: 0; }
.uni-map__controls .btn--icon + .btn--icon { border-top: var(--border) solid var(--divider); }
/* фокус внутри плашки: снаружи его обрезал бы clip-path */
.uni-map__controls .btn--icon:focus-visible { outline-offset: calc(-1 * var(--border-strong)); }

/* Подпись © (лицензия, убирать нельзя): одна строка справа внизу, на стекле.
   Если не влезает — обрезается многоточием, но при 375 px все три имени видны */
/* угол MapLibre растянут на всю ширину карты: иначе max-width ниже считается от ширины самой подписи */
.uni-map .maplibregl-ctrl-bottom-right { left: 0; }
.uni-map .maplibregl-ctrl-bottom-right .uni-map__attrib {
  max-width: calc(100% - 2 * var(--sp-3));
  margin: 0 var(--sp-3) var(--sp-3) 0;
  padding: var(--sp-1) var(--sp-2);
  overflow: hidden;
  border-radius: var(--r-sm);
  clip-path: inset(0 round var(--r-sm));
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  color: var(--text-3);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  white-space: nowrap;
  text-overflow: ellipsis;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .uni-map .maplibregl-ctrl-bottom-right .uni-map__attrib { background: var(--glass-fallback); }
}
/* .uni-map впереди: CSS MapLibre подключается после pages.css и красит ссылки тёмным */
.uni-map .uni-map__attrib a { color: var(--text-2); }
.uni-map .uni-map__attrib a:hover { color: var(--text); }
/* фокус внутри плашки: снаружи его обрезал бы clip-path */
.uni-map .uni-map__attrib a:focus-visible { outline-offset: 0; }

/* Подсказка cooperativeGestures («двигайте двумя пальцами») — стекло и шрифт сайта */
.uni-map .maplibregl-cooperative-gesture-screen {
  padding: var(--sp-5);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur));
  backdrop-filter: blur(var(--glass-blur));
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  text-align: center;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .uni-map .maplibregl-cooperative-gesture-screen { background: var(--glass-fallback); }
}

/* Вкладки и панели. Без JS панели идут подряд со своими заголовками;
   с JS заголовок панели повторяет вкладку — оставляем его только для программ чтения с экрана */
.tabs__count { color: var(--text-2); }
.uni-panel { margin-top: var(--sp-6); }
.uni-panel + .uni-panel { margin-top: var(--sp-8); }
[role="tabpanel"].uni-panel { margin-top: var(--sp-6); }
[role="tabpanel"]:focus-visible { outline-offset: var(--sp-2); border-radius: var(--r-lg); }
[role="tabpanel"] > .uni-panel__title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.uni-panel__title { margin-bottom: var(--sp-5); }
.uni-panel__count { color: var(--text-2); font-weight: var(--fw-regular); }

/* ===== Программы: папки факультетов, строки программ (12.19) =====
   Размеры текста: --fs-body (названия, число проходного), --fs-small (адрес, шанс, подписи),
   --fs-caption — только маленькие заголовки блоков в подробностях (как .stat dt) и источник */
/* Тихая строка над списком программ: «выбранных областей здесь нет», «баллов не хватает», «введите баллы ЕГЭ» */
.uni-programs__note { margin-bottom: var(--sp-5); }
.uni-programs { padding-block: var(--sp-2); }
.uni-programs__year,
.uni-programs__legend { margin-bottom: var(--sp-3); }
.uni-programs__year:has(+ .uni-programs__legend) { margin-bottom: var(--sp-1); }
.uni-programs__disclaimer { margin-top: var(--sp-5); }

/* Шанс словами (components/_chance.html): значок-форма и подпись, нейтрально */
.chance-label { display: inline-flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }

/* Раскрытие папок и строк плавное (static/js/disclosure.js): высота содержимого, проявление, стрелка и заливка идут
   одной длительностью --disclosure-dur [допущение: псевдоним --dur-slow, как у меню телефона]. JS на время закрытия
   вешает на <details> класс .is-closing: стили «открыто» снимаются сразу, содержимое сворачивается, потом
   снимается атрибут open. Без JS и при «уменьшить движение» — мгновенно, как у обычного <details>.
   Исключение из 11.1 [допущение]: здесь анимируется высота — иначе список не раскрыть плавно */
.faculty, .program { --disclosure-dur: var(--dur-slow); }

/* Факультеты: <details> на факультет. Закрытые — строки через разделитель; открытая — заливка на ступень
   (--raise карточки), скругление 10: summary и программы одним блоком. Поля внутрь есть у всех папок (минус margin
   и плюс padding гасят друг друга), поэтому раскрытие ничего не двигает — только проявляется заливка.
   У вуза без факультетов (ЦУ) этого блока нет — плоский список */
.faculty {
  position: relative;
  margin-inline: calc(-1 * var(--sp-4));
  padding-inline: var(--sp-4);
  border-radius: var(--r-md);
  transition: background-color var(--disclosure-dur) var(--ease);
}
.faculty[open]:not(.is-closing) {
  --raise: var(--surface-3);
  --raise-hover: var(--surface-4);
  background: var(--surface-2);
}
/* Разделитель между папками — линия на поле внутри, её скрывает залитая соседка (проявляется вместе с заливкой) */
.faculty + .faculty::before {
  content: "";
  position: absolute;
  top: 0;
  inset-inline: var(--sp-4);
  height: var(--border);
  background: var(--divider);
  transition: opacity var(--disclosure-dur) var(--ease);
}
.faculty[open]:not(.is-closing) + .faculty::before,
.faculty + .faculty[open]:not(.is-closing)::before { opacity: 0; }
/* Код и название — --fs-body; справа точки типов и одна подпись --fs-small (колонка фиксированной ширины:
   точки во всех папках стоят друг под другом), стрелка — крайняя */
.faculty__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  min-height: var(--tap);
  padding: var(--sp-3) 0;
  list-style: none;
  cursor: pointer;
}
.faculty__summary::-webkit-details-marker { display: none; }
.faculty__name { flex: 1 1 16em; min-width: 0; }
.faculty__code { font-weight: var(--fw-semibold); }
.faculty__areas { display: inline-flex; gap: var(--sp-1); }
.faculty__count {
  min-width: 17ch;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  text-align: right;
  white-space: nowrap;
}
.faculty__chevron {
  flex-shrink: 0;
  width: var(--icon-size);
  height: var(--icon-size);
  color: var(--text-2);
  transition: transform var(--disclosure-dur) var(--ease);
}
.faculty[open]:not(.is-closing) .faculty__chevron { transform: rotate(180deg); }
.faculty__summary:hover .faculty__chevron { color: var(--text); }
.faculty__programs { padding-bottom: var(--sp-2); }

/* Строка программы (catalog/_program_row.html): <li class="program"> → <details class="program-row">.
   Наведение и раскрытая строка — подложка --raise, --r-md (12.9); поля внутрь, текст не прыгает.
   --row-bg — заливка строки, --row-up и --row-up2 — на одну и две ступени дальше: кнопка в залитой строке берёт
   --raise от строки, а не от карточки, иначе её фон совпал бы с заливкой */
.program {
  --row-bg: var(--surface-2); --row-up: var(--surface-3); --row-up2: var(--surface-4);
  margin-inline: calc(-1 * var(--sp-3));
  padding-inline: var(--sp-3);
  border-top: var(--border) solid var(--divider);
  border-radius: var(--r-md);
  transition: background-color var(--dur-fast) var(--ease);
}
.program:first-child { border-top: 0; }
.faculty[open]:not(.is-closing) .program { --row-bg: var(--surface-3); --row-up: var(--surface-4); --row-up2: var(--surface-5); }
.program:not(.is-chosen):has(> .program-row[open]:not(.is-closing)) { --raise: var(--row-up); --raise-hover: var(--row-up2); background: var(--row-bg); }
/* Наведение — только на устройствах с мышью: на тач-экранах залипшего hover нет. Срабатывает, когда курсор на шапке
   строки (summary), а заливается весь элемент строки <li> (у выбранной — тем же условием, см. ниже --pick-now) */
@media (hover: hover) {
  .program:not(.is-chosen):has(> details.program-row > summary:hover) { --raise: var(--row-up); --raise-hover: var(--row-up2); background: var(--row-bg); }
}
/* Заливка раскрытой строки проявляется и гаснет той же длительностью, что и высота; наведение — быстрее */
.program:has(> .program-row[open]:not(.is-closing)),
.program:has(> .program-row.is-closing) { transition-duration: var(--disclosure-dur); }
.program:has(> details.program-row > summary:hover) + .program,
.program:has(> .program-row[open]:not(.is-closing)) + .program,
.program.is-target + .program { border-top-color: transparent; }
/* «Коробка в коробке»: раскрытая строка внутри залитой папки — без второй заливки: отделена разделителями
   сверху и снизу (нижний — линия-псевдоэлемент, проявляется прозрачностью, поэтому высоту не меняет);
   наведение по-прежнему подсвечивает */
.program { position: relative; }
.program::after {
  content: "";
  position: absolute;
  bottom: 0;
  inset-inline: var(--sp-3);
  height: var(--border);
  background: var(--divider);
  opacity: 0;
  transition: opacity var(--disclosure-dur) var(--ease);
}
.faculty[open]:not(.is-closing) .program:not(.is-chosen):has(> .program-row[open]:not(.is-closing)):not(:hover):not(.is-target) { background: none; }
.faculty[open]:not(.is-closing) .program:has(> .program-row[open]:not(.is-closing))::after { opacity: 1; }
/* Выбранная область («Мои области», .is-chosen; один приём и токены --pick-* — в components.css): свет от точки.
   Рисует его псевдоэлемент <li> (::before, под содержимым: isolation + z-index: -1) на всём элементе строки — один раз,
   на закрытой и на раскрытой строке; шапка своей заливки не имеет. Раскрытая строка: тот же градиент не обрывается на
   шапке, а продолжается по подробностям и затухает к низу — маска linear-gradient to bottom гасит псевдоэлемент
   (цвет и оттенок те же, ступеньки между шапкой и подробностями нет). Псевдоэлемент растёт вместе с <li>, а не
   лежит на анимируемом блоке .program-row__body: во время раскрытия он тянется с высотой и не мерцает, disclosure.js
   не затронут. Первые --program-head-h маска держит полную яркость (высота шапки, когда подробностей ещё нет), затем
   затухает. При закрытии (.is-closing) маска снимается сразу. Наведение: то же условие и тот же элемент, что у
   невыбранной строки (курсор на шапке, меняется вся строка), только при hover: hover — --pick-now становится
   --pick-from-hover. Нейтральные правила заливки (.program:not(.is-chosen)…) выбранной не касаются. */
.program.is-chosen,
.program.is-chosen + .program { border-top-color: color-mix(in srgb, var(--divider) 40%, transparent); }
.program.is-chosen {
  isolation: isolate;
  /* центр света — точка в строке «бакалавриат…» под названием: 3.1rem от верха на десктопе. Название и числа
     переносятся по-разному, поэтому pick-light.js подставляет точный центр (--pick-x, --pick-y) в px; без JS
     остаются эти значения. Круг большой: свет достаёт далеко вдоль строки и вниз по подробностям, маска ниже
     гасит его к низу раскрытой строки */
  --pick-y: 3.1rem;
  --pick-r: clamp(280px, 48vw, 600px);
  transition: --pick-now var(--dur-fast) var(--ease);
}
.program.is-chosen::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--pick-grad);
  pointer-events: none;
}
@media (hover: hover) {
  .program.is-chosen:has(> details.program-row > summary:hover) { --pick-now: var(--pick-from-hover); }
}
.program.is-chosen.is-target { --pick-now: var(--pick-from-hover); }
.program.is-chosen:has(> details.program-row[open]:not(.is-closing)) { transition-duration: var(--dur-fast); }
.program.is-chosen:has(> details.program-row[open]:not(.is-closing))::before {
  --program-head-h: 6rem;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 var(--program-head-h), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, #000 var(--program-head-h), transparent 100%);
}
.program.is-target:not(.is-chosen) { --raise: var(--row-up2); --raise-hover: var(--row-up2); background: var(--row-up); }

/* Свёрнутая строка — сетка 2×2 и колонки действий. Колонки чисел и кнопки фиксированной ширины (ch, без px):
   числа и шанс во всех строках стоят ровно друг под другом по правому краю, кнопка и стрелка — по центру двух строк */
.program-row__summary {
  --program-nums: 28ch;
  --program-save: var(--icon-btn);
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--program-nums) var(--program-save) var(--icon-size);
  grid-template-areas:
    "name score save chev"
    "meta aside save chev"
    "subj subj .    .";
  align-items: baseline;
  column-gap: var(--sp-4);
  row-gap: var(--sp-1);
  padding-block: var(--sp-3);
  list-style: none;
}
summary.program-row__summary { cursor: pointer; }
.program-row__summary::-webkit-details-marker { display: none; }
.program-row__name { grid-area: name; color: var(--text); }
.program-row__score {
  grid-area: score;
  justify-self: end;
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}
.program-row__meta {
  grid-area: meta;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.program-row__meta .dot { margin-right: var(--sp-2); }
.program-row__subjects { grid-area: subj; }
.program-row__aside {
  grid-area: aside;
  min-width: 0;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  text-align: right;
}
.program-row__aside .chance-label { color: var(--text); vertical-align: top; white-space: normal; text-align: left; }
/* «ИУ7 · бакалавриат», «платное · 2024 · Надёжно +105»: точки между фактами — в CSS, шаблон не собирает строку из кусков */
.program-row__fact + .program-row__fact::before { content: "·"; margin-inline: var(--sp-2); }
.program-row__save { grid-area: save; align-self: center; justify-self: center; }
.program-row__chevron {
  grid-area: chev;
  align-self: center;
  width: var(--icon-size);
  height: var(--icon-size);
  color: var(--text-2);
  transition: transform var(--disclosure-dur) var(--ease);
}
.program-row[open]:not(.is-closing) .program-row__chevron { transform: rotate(180deg); }
summary.program-row__summary:hover .program-row__chevron { color: var(--text); }

/* Подробности: только заполненное, одинаковый шаг --sp-4 между блоками; левый край — по названию.
   Текст --fs-small, заголовки блоков и подписи пар — как .stat dt (--fs-caption, --text-2) */
.program-row__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-bottom: var(--sp-4);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}
.program-row__pairs {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: baseline;
  gap: var(--sp-2) var(--sp-5);
}
.program-row__pairs > div { display: contents; }
.program-row__pairs dd { margin: 0; }
.program-row__pairs dt,
.program-row__label {
  color: var(--text-2);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  letter-spacing: var(--ls-caption);
  font-weight: var(--fw-regular);
}
.program-row__text { max-width: var(--measure); }
.program-row__cols { display: grid; gap: var(--sp-4) var(--sp-6); grid-template-columns: minmax(0, 1fr); }
/* Всегда две равные колонки: если «Что сдавать» нет, график остаётся половинной ширины, а не растягивается */
@media (min-width: 768px) {
  .program-row__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.program-row__col { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
/* График вдвое ниже полного; цвет — область строки (c--<тип> на <li>) */
.program-row__chart .chart__svg { height: calc(var(--chart-h) / 2); }
.program-row__you { color: var(--text-2); }
/* Два года — словами вместо графика: «2024 — 253 · 2025 — 255»; платное второй строкой */
.program-row__history { display: flex; flex-direction: column; gap: var(--sp-1); }
.program-row__history-kind { margin-right: var(--sp-2); color: var(--text-2); }
.program-row__exam-list { list-style: none; }
.program-row__or { color: var(--text-2); font-weight: var(--fw-semibold); }
.program-row__problem { color: var(--text-2); }
.program-row__source { color: var(--text-2); font-size: var(--fs-caption); line-height: var(--lh-caption); }
.program-row__source a { text-decoration: underline; text-underline-offset: 0.2em; }

/* Телефон: заголовок папки — название и точки в первой строке, подпись под ними слева, стрелка в углу */
@media (max-width: 599.98px) {
  .faculty__summary {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto var(--icon-size);
    grid-template-areas: "name areas chev" "count count count";
    align-items: center;
  }
  .faculty__name { grid-area: name; }
  .faculty__areas { grid-area: areas; }
  .faculty__count { grid-area: count; min-width: 0; text-align: left; }
  .faculty__chevron { grid-area: chev; }
}

/* Телефон: название на всю ширину (стрелка в углу поверх, а не в колонке кнопки); мета слева и кнопка справа
   в одной строке; ниже «число · шанс» на всю ширину — длинная подпись («платное · 2024 · Надёжно +105 · и ДВИ»)
   помещается, а если нет — переносится, а не обрезается. Высота строки от кнопки не растёт */
@media (max-width: 599.98px) {
  .program-row__summary {
    position: relative;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "name  name  name"
      "meta  meta  save"
      "subj  subj  subj"
      "score aside aside";
    align-items: start;
    column-gap: var(--sp-3);
    row-gap: var(--sp-2);
  }
  .program-row__name { padding-inline-end: calc(var(--icon-size) + var(--sp-2)); }
  .program-row__chevron { position: absolute; top: var(--sp-3); right: 0; }
  .program-row__score { justify-self: start; align-self: baseline; }
  .program-row__meta { align-self: center; }
  .program-row__aside { align-self: baseline; text-align: left; }
  .program-row__aside .program-row__fact { display: inline; }
  /* Нет числа проходного — шанс начинается от левого края, без пустой колонки */
  .program-row__summary:not(:has(.program-row__score)) {
    grid-template-areas:
      "name  name  name"
      "meta  meta  save"
      "subj  subj  subj"
      "aside aside aside";
  }
  /* Узкая мета переносится по словам, а не рвёт «·» на начало строки: точки заменяет промежуток */
  .program-row__meta { column-gap: var(--sp-3); }
  .program-row__meta .program-row__fact + .program-row__fact::before { content: none; }
}

/* «Уменьшить движение»: подсветка и стрелки без перехода */
@media (prefers-reduced-motion: reduce) {
  .faculty,
  .faculty::before,
  .program,
  .program::after,
  .program-row__chevron,
  .faculty__chevron { transition: none; }
}

/* Предметы ЕГЭ (12.18): «Русский язык, математика, физика или информатика».
   Запятые и заглавная буква — в CSS, чтобы шаблон не собирал строку из кусков */
.subjects {
  display: flex;
  flex-wrap: wrap;
  color: var(--text-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  list-style: none;
}
.subjects > :not(:last-child)::after { content: ","; margin-right: var(--sp-1); }
.subjects > :first-child::first-letter { text-transform: uppercase; }

/* Новости: «газетная» сетка (components/_news_grid.html, _news_card.html).
   Блоки по 7 новостей идут столбиком, каждый блок — своя сетка из стопок:
     десктоп:  [ главная  главная ][ C ]     зеркальный:  [ C ][ главная  главная ]
               [    A   ][   B    ][ C ]                  [ C ][    A   ][   B    ]
     планшет:  главная на всю ширину, ниже C слева, A и B друг под другом справа;
     телефон:  одна колонка, стопки «растворяются» (display: contents) и карточки
               идут по порядку даты — его задаёт style="order: N" в разметке. */
.news-grid { display: flex; flex-direction: column; gap: var(--gap-tight); }
.news-grid__more { align-self: center; }
.news-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--gap-tight);
}
.news-block > *,
.news-stack > * { min-width: 0; }
.news-stack { display: contents; }

/* Анонс обрезается по строкам; сколько строк — задаёт тип карточки через --clamp */
.news-card > p:not([class]) {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--clamp);
  line-clamp: var(--clamp);
  overflow: hidden;
}
.news-card--lead { --clamp: 5; --news-h: var(--news-h-lead); }
.news-card--column { --clamp: 8; --news-h: var(--news-h-column); }
.news-card--note { --news-h: var(--news-h-note); }
.news-card--middle { --clamp: 3; --news-h: var(--news-h-middle); }

/* Вариант высоты по id новости: s / m / l — 0, 1 или 2 шага сверх минимума типа */
.news-card--s { --news-step: 0; }
.news-card--m { --news-step: 1; }
.news-card--l { --news-step: 2; }

@media (min-width: 600px) {
  /* Планшет: главная на всю ширину и без минимальной высоты, ниже две стопки */
  .news-block {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "lead lead"
      "c    a"
      "c    b";
  }
  .news-card--lead { grid-area: lead; }
  .news-stack--a { grid-area: a; }
  .news-stack--b { grid-area: b; }
  .news-stack--c { grid-area: c; }

  /* Стопка — колонка карточек. Сетка растягивает стопку до низа блока,
     а последняя карточка забирает остаток (flex-grow), поэтому низ блока ровный */
  .news-stack { display: flex; flex-direction: column; gap: var(--gap-tight); }
  .news-stack > :last-child { flex-grow: 1; }
  .news-stack > .news-card { min-height: calc(var(--news-h) + var(--news-h-step) * var(--news-step)); }

  /* Анонса нет — пустую высоту не держим */
  .news-stack > .news-card--bare { min-height: 0; }
}

@media (min-width: 1024px) {
  /* Десктоп: три стопки одинаковой ширины, главная — на ширину двух */
  .news-block {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas:
      "lead lead c"
      "a    b    c";
  }
  .news-block--mirror {
    grid-template-areas:
      "c lead lead"
      "c a    b";
  }
  .news-card--lead:not(.news-card--bare) { min-height: calc(var(--news-h) + var(--news-h-step) * var(--news-step)); }
  .news-card--lead .card__title { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2); }
}
.uni-news__source { margin-top: var(--sp-5); }

/* Вкладка «Фото»: «кирпичная» раскладка на всю ширину, как в Яндекс Картах — колонки, фото своей высоты
   без обрезки, идут сверху вниз. Колонок: телефон 2, планшет 3, десктоп 4 (при 1200 px фото ~290 px).
   Под сеткой одной строкой — источник и ссылка на Яндекс Карты */
.uni-photos {
  columns: 2;
  column-gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.uni-photos > li {
  break-inside: avoid;           /* фото не рвётся между колонками */
  margin-bottom: var(--sp-2);
}
@media (min-width: 600px) {
  .uni-photos { columns: 3; column-gap: var(--sp-3); }
  .uni-photos > li { margin-bottom: var(--sp-3); }
}
@media (min-width: 1024px) {
  .uni-photos { columns: 4; }
}
/* 1–2 фото [допущение]: колонки вышли бы пустыми — ряд из половинок, одно фото — половина ширины */
.uni-photos--few {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  columns: auto;
}
.uni-photos--few > li { flex: 0 1 calc((100% - var(--sp-2)) / 2); margin-bottom: 0; }
@media (min-width: 600px) {
  .uni-photos--few { gap: var(--sp-3); }
  .uni-photos--few > li { flex-basis: calc((100% - var(--sp-3)) / 2); }
}
.uni-photos__item {
  margin: 0;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: var(--surface-2);  /* видно, пока фото грузится */
}
.uni-photos__item img {
  display: block;
  width: 100%;
  height: auto;                  /* своя высота: вертикальные фото выше, горизонтальные ниже */
}
.uni-photos__empty[hidden] { display: none; }
.uni-photos__source { margin-top: var(--sp-5); }
.uni-photos__source-link { white-space: nowrap; }
.uni-photos__source-link svg { display: inline-block; width: 1em; height: 1em; vertical-align: -0.125em; }

/* Отзывы: форма и список (8), правила сбоку (4) */
.uni-reviews { display: flex; flex-direction: column; gap: var(--sp-4); }
.uni-rules { align-self: start; }

/* ===== Профиль (13, промт подбора 4.5) [допущение: композиция в 13] ===== */
.profile-head .lead { margin-top: var(--sp-3); }
.profile-head__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); margin-top: var(--sp-4); }
.profile-head__actions form { margin: 0; }

/* Настройки: форма «Основное» в две колонки, справа стопка карточек (как .my-top) */
.settings-message { margin-top: var(--sp-4); }
.settings-fields { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
@media (min-width: 700px) {
  .settings-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--sp-6); align-items: start; }
}
.settings-main { align-self: start; }
.settings-side { display: flex; flex-direction: column; gap: var(--gap-tight); }

.my-top { display: flex; flex-direction: column; gap: var(--gap-tight); }
.my-list__counts { max-width: var(--measure); }
.my-list__hints { display: flex; flex-direction: column; gap: var(--sp-2); color: var(--text-2); list-style: none; }
.my-list__hints li { padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); background: var(--surface-3); }
.my-exams__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.my-exams__stats { --stat-min: 100px; }
.my-exams__stats .stat dd { font-size: var(--fs-h3); line-height: var(--lh-h3); }

.my-result__date { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
/* Строка-итог теста, как заголовок результата (план дизайна теста v2, 7.1) */
.my-result__summary { margin-top: var(--sp-1); font-size: var(--fs-h4); line-height: var(--lh-h4); letter-spacing: var(--ls-h4); font-weight: var(--fw-semibold); }

/* Вкладки «Программы | Вузы»: панель — обёртка, сетка внутри (display у панели перебил бы hidden) */
.my-panel { padding-top: var(--sp-5); }
.my-unis__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-tight); }
@media (min-width: 600px) {
  .my-unis__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1000px) {
  .my-unis__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.my-news .list__name { color: var(--text); }

/* ===== Главная (13): знакомство с сайтом — первый экран, лента новостей, экскурсия по главам ===== */
.home-head .lead { max-width: var(--measure); margin-top: var(--sp-4); }

/* «Ваш результат» (глава «Подбор», баллы введены): три числа и три лучших варианта из разных вузов */
.home-result__counts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-4);
}
.home-result__count { display: flex; flex-direction: column; gap: var(--sp-1); }
.home-result__count dt { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.home-result__count dd { margin: 0; font-size: var(--fs-score); line-height: 1; letter-spacing: var(--ls-h2); font-weight: var(--fw-semibold); }
.home-result__top .list__name { display: flex; flex-direction: column; color: var(--text); }
.home-result__uni { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.home-result__top .list__value { font-size: var(--fs-small); text-align: right; }

/* Лента новостей разных вузов: две одинаковые дорожки едут по кругу и на наведении не останавливаются; фокус с клавиатуры — пауза.
   При «уменьшить движение» вторая копия скрыта, ленту листают вбок. Без движения и без JS ссылки работают */
.home-news__title { font-size: var(--fs-h4); line-height: var(--lh-h4); letter-spacing: normal; margin-bottom: var(--sp-4); }
.ticker {
  display: flex;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.ticker::-webkit-scrollbar { display: none; }
.ticker__track { flex: none; display: flex; gap: var(--gap-tight); padding-right: var(--gap-tight); list-style: none; }
.ticker__track--copy { display: none; }
.ticker__link {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  width: 280px;
  height: 100%;
  padding: var(--sp-4);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  color: var(--text);
  transition: background-color var(--dur-base) var(--ease);
}
.ticker__link:hover { background: var(--surface-2); color: var(--text); }
.ticker__uni { color: var(--text-2); font-size: var(--fs-caption); line-height: var(--lh-caption); letter-spacing: var(--ls-caption); }
.ticker__text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (prefers-reduced-motion: no-preference) {
  .ticker { overflow: hidden; }
  .ticker__track--copy { display: flex; }
  .ticker__track { animation: ticker-run calc(var(--n, 12) * 7s) linear infinite; }
  .ticker:focus-within .ticker__track { animation-play-state: paused; }  /* только для клавиатуры: на наведении лента едет */
}
@keyframes ticker-run { to { transform: translateX(-100%); } }

/* Экскурсия: главы друг за другом, за ними маршрут на фоне (от 1024 px, рисует js/story.js, как маршрут теста).
   Глава = текст + сцена. Слева от глав полоса под остановки маршрута */
.story { position: relative; }
.story__chapters { position: relative; z-index: 1; }
@media (min-width: 1024px) { .story__chapters { padding-left: 72px; } }
/* will-change: transform выносит маршрут в свой слой. Пунктир и пульс маршрута анимируются всегда (stroke-dashoffset и SVG
   не идут на композитор), а SVG растянут на всю главу: в общем слое с текстом каждый кадр заново растеризовал всё под ним, в
   том числе ленту предметов, и она дёргалась. В своём слое перерисовывается только маршрут (растровых задач втрое меньше). */
.story-route { display: none; position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; color: var(--text); will-change: transform; }
/* Цвет маршрута нейтральный: белый в тёмной теме, чёрный в светлой (--text) */
@media (min-width: 1024px) { .story-route { display: block; } }
.story-route__ahead,
.story-route__done { fill: none; stroke: currentColor; stroke-width: 2.25px; stroke-linecap: round; }
.story-route__ahead { stroke-dasharray: 3 8; opacity: .4; }
.story-route__done { opacity: .95; stroke-dasharray: 100; }
.story-route__stop { fill: var(--bg); stroke: currentColor; stroke-width: 2px; opacity: .55; transition: opacity var(--dur-fast) var(--ease); }
.story-route__stop.is-passed { fill: currentColor; opacity: 1; }
.story-route__tick { fill: var(--bg); stroke: currentColor; stroke-width: 1.5px; opacity: .45; transition: opacity var(--dur-fast) var(--ease); }
.story-route__tick.is-passed { fill: currentColor; opacity: .9; }
.story-route__ring { fill: none; stroke: currentColor; stroke-width: 1.5px; opacity: 0; transition: opacity var(--dur-base) var(--ease); }
.story-route__ring.is-current { opacity: .7; }
.story-route__head { fill: currentColor; filter: drop-shadow(0 0 6px currentColor); transition: opacity var(--dur-base) var(--ease); }
.story-route__pulse { fill: none; stroke: currentColor; stroke-width: 1.5px; transform-box: fill-box; transform-origin: center; transition: opacity var(--dur-base) var(--ease); }
.story-route__head.is-hidden, .story-route__pulse.is-hidden { opacity: 0; }
.story-route__finish { fill: none; stroke: currentColor; stroke-width: 2px; stroke-linejoin: round; opacity: .45; transition: opacity var(--dur-slow) var(--ease); }
.story-route__finish.is-finished { opacity: 1; filter: drop-shadow(0 0 6px currentColor); }
@media (prefers-reduced-motion: no-preference) {
  /* пунктир впереди бежит вперёд по маршруту; 11 px за 1.4 с — доли пикселя за кадр, поэтому ступеньки по 0.5 px (≈16 перерисовок в секунду вместо 60) */
  .story-route__ahead { animation: route-march 1.4s steps(22) infinite; }
  .story-route__pulse { animation: route-pulse 2s var(--ease) infinite; }
}
@keyframes route-march { to { stroke-dashoffset: -11; } }
@keyframes route-pulse { from { transform: scale(1); opacity: .8; } to { transform: scale(3.2); opacity: 0; } }

.chapter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  gap: var(--sp-6);
  padding-block: var(--sp-7);
  scroll-margin-top: calc(var(--header-h) + var(--header-offset));
}
@media (min-width: 1024px) {
  .chapter { min-height: 60vh; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: center; gap: var(--sp-7); }
  .chapter--wide { grid-template-columns: minmax(0, 1fr); align-content: center; }
  .chapter--wide .chapter__text { max-width: var(--measure); }
}
.chapter__step { color: var(--text-3); font-size: var(--fs-small); line-height: var(--lh-small); margin-bottom: var(--sp-2); }
.chapter__text .lead { margin-top: var(--sp-3); }
.chapter__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.chapter__scene > .card { height: 100%; }
.chapter__note { max-width: var(--measure); margin-top: var(--sp-4); color: var(--text-2); }
.chapter__extra { min-width: 0; }
@media (min-width: 1024px) { .chapter__extra { grid-column: 1 / -1; } }

/* Глава «Баллы»: предметы ЕГЭ крутятся тремя лентами, средняя — в обратную сторону. Края мягко гаснут.
   Каждая лента — четыре одинаковые группы, сдвиг на четверть = бесшовный круг; без движения копии скрыты */
.reel {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-3);
  height: 320px;
  padding-inline: var(--sp-2);
  overflow: hidden;
  border-radius: var(--r-lg);
  background: var(--surface-1);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 18%, #000 82%, transparent);
}
.reel__col { overflow: hidden; }
.reel__group { display: flex; flex-direction: column; gap: var(--sp-3); padding-bottom: var(--sp-3); list-style: none; }
.reel__chip {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  text-align: center;
}
.reel__col--2 .reel__chip { background: var(--surface-3); }
.reel__group[aria-hidden="true"] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .reel__group[aria-hidden="true"] { display: flex; }
  .reel__track { animation: reel-up 28s linear infinite; will-change: transform; }   /* свой слой: лента едет на композиторе, дробные пиксели без дрожания текста */
  .reel__col--2 .reel__track { animation-name: reel-down; animation-duration: 34s; }
  .reel__col--3 .reel__track { animation-duration: 40s; }
}
@keyframes reel-up { to { transform: translateY(-25%); } }
@keyframes reel-down { from { transform: translateY(-25%); } to { transform: translateY(0); } }
@media (max-width: 599px) { .reel { height: 260px; } .reel__chip { font-size: var(--fs-caption); } }

/* Глава «Подбор» для гостя: строки трёх зон подсвечиваются по очереди (один цикл 12 с) */
.scale { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--card-pad); border-radius: var(--r-lg); background: var(--surface-2); }
.scale__title { font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--ls-h3); }
.scale__zones { display: flex; flex-direction: column; list-style: none; }
.scale__zone { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3) 0; border-top: var(--border) solid var(--divider); }
.scale__zone:first-child { border-top: 0; }
.scale__hint { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
@media (prefers-reduced-motion: no-preference) {
  .scale__zone { animation: scale-zone 12s var(--ease) infinite; opacity: .55; }
  .scale__zone--2 { animation-delay: 4s; }
  .scale__zone--3 { animation-delay: 8s; }
}
@keyframes scale-zone {
  0%, 26% { opacity: 1; }
  33%, 100% { opacity: .55; }
}

/* Глава «Вузы»: колода — у каждой карточки видна шапка, наведение поднимает карточку */
.deck { position: relative; height: 340px; list-style: none; }
.deck__item {
  position: absolute;
  inset-inline: 0;
  top: calc(var(--i) * 92px);
  z-index: var(--i);
  transition: transform var(--dur-base) var(--ease);
}
.deck__item:hover, .deck__item:focus-within { transform: translateY(calc(-1 * var(--sp-2))); }
.deck__card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  height: 150px;
  padding: var(--card-pad);
  border-radius: var(--r-lg);
  color: var(--text);
  background: var(--surface-1);
  transition: background-color var(--dur-base) var(--ease);
}
.deck__item:nth-child(2) .deck__card { background: var(--surface-2); }
.deck__item:nth-child(3) .deck__card { background: var(--surface-3); }
.deck__card:hover { color: var(--text); }
.deck__name { font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--ls-h3); font-weight: var(--fw-semibold); }
.deck__meta { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }

/* Глава «Мой список»: закладка и сердечко по очереди «ставятся» той же анимацией, что настоящие
   кнопки (like-in, components.css): вход с пружиной и заливка. */
.keep { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-tight); }
@media (max-width: 599px) { .keep { grid-template-columns: minmax(0, 1fr); } }
.keep__item { position: relative; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--card-pad); border-radius: var(--r-lg); background: var(--surface-1); }
.keep__item--heart { background: var(--surface-2); }
.keep__icon { width: 64px; height: 64px; margin-bottom: var(--sp-3); color: var(--text); fill: transparent; transform-box: fill-box; transform-origin: center; }
.keep__title { font-weight: var(--fw-semibold); }
.keep__text { color: var(--text-2); }
@media (prefers-reduced-motion: no-preference) {
  .keep__item .keep__icon { animation: keep-stamp 5s var(--ease) infinite; }
  .keep__item--heart .keep__icon { animation-delay: 2.5s; }
}
@media (prefers-reduced-motion: reduce) {
  .keep__icon { fill: currentColor; }   /* без движения — сразу «поставлено» */
}
@keyframes keep-stamp {   /* как настоящая кнопка: вход из .8 с пружиной (like-in), заливка проявляется */
  0%, 12%, 100% { transform: scale(1); fill: transparent; }
  12.01% { transform: scale(.8); fill: transparent; animation-timing-function: cubic-bezier(.34, 1.56, .64, 1); }
  19% { transform: scale(1); fill: currentColor; }
  60% { transform: scale(1); fill: currentColor; }
  66% { transform: scale(1); fill: transparent; }
}

/* Глава «Интересы»: шесть типов. Плитка нейтральная, цвет у точки и фигуры; наведение — ступень заливки;
   «ваш тип» (.is-chosen) — тот же свет от точки, что у выбранных строк и чипов (--pick-grad, components.css) */
.type-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap-tight); }
@media (min-width: 600px) { .type-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .type-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.type-tile {
  overflow: hidden;
  color: var(--text);
}
.type-tile:hover { color: var(--text); transform: translateY(var(--lift)); background: var(--surface-2); }
.type-tile.is-chosen {
  /* центр света — точка у названия. Запасные значения по вёрстке (поле карточки, фигура 72 px и её отступ,
     полстроки названия); точный центр замеряет pick-light.js и пишет --pick-x / --pick-y в px */
  --pick-x: calc(var(--card-pad) + var(--dot) / 2);
  --pick-y: calc(var(--card-pad) + 72px + var(--sp-5) + var(--lh-h4) * var(--fs-h4) / 2);
  --pick-r: 300px;                                    /* круг света накрывает почти всю плитку */
  --pick-core: 36px;
  background: var(--pick-grad), var(--surface-1);
  transition: background-color var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), --pick-now var(--dur-fast) var(--ease);
}
.type-tile.is-chosen:hover { --pick-now: var(--pick-from-hover); }
.type-tile:focus-visible { outline: var(--border-strong) solid var(--focus); outline-offset: var(--focus-offset); }
/* Фигура типа — над текстом слева, в потоке, чтобы не лежать под названием */
.type-tile__figure {
  display: block;
  width: 72px;
  height: 72px;
  margin-bottom: var(--sp-5);
  color: var(--c);
  transition: transform var(--dur-slow) var(--ease);
}
[data-theme="light"] .type-tile__figure { color: var(--c-ink); }
.type-tile:hover .type-tile__figure { transform: rotate(-6deg) scale(1.06); }
.type-tile__figure svg { display: block; width: 100%; height: 100%; }
.type-tile .card__title { display: flex; align-items: center; gap: var(--sp-2); }
.type-tile__areas { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.type-tile__count { font-size: var(--fs-small); line-height: var(--lh-small); }

/* Три числа базы: типографикой, без плиток */
.home-stats { --stat-min: 180px; }
.home-stats .stat { justify-content: flex-start; }
.home-stats .stat dd { order: -1; font-size: var(--fs-score); line-height: 1; letter-spacing: var(--ls-h2); }
.home-loop > p:not([class]) { max-width: var(--measure); }

/* ===== О проекте: создатели ===== */
.about-head .lead { max-width: var(--measure); margin-top: var(--sp-4); }
.about-team { list-style: none; padding: 0; }
.about-person { align-items: flex-start; gap: var(--sp-4); }
.about-person__mark {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: var(--r-round);
  background: var(--c-tint);
  color: var(--c-ink);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-h3);
}
.about-person__mail { color: var(--text-2); overflow-wrap: anywhere; }
.about-person__mail:hover { color: var(--text); }
.about-person__role { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }

/* Фильтр по вузам: кнопка и окно с поиском (unis-filter.js) */
.unis-open { display: flex; align-items: center; justify-content: space-between; text-align: start; cursor: pointer; }
.unis-dialog {
  --uni-pick: var(--accent); --uni-pick-bg: rgb(226 226 223 / 0.12);
  width: min(62rem, calc(100vw - 2 * var(--sp-4))); max-height: min(44rem, 88vh);
  padding: 0; border: 0; border-radius: var(--r-lg); background: var(--surface-1); color: var(--text);
  box-shadow: 0 24px 64px rgb(0 0 0 / 0.45);
}
[data-theme="light"] .unis-dialog { --uni-pick-bg: rgb(30 30 29 / 0.08); }
.unis-dialog::backdrop { background: rgb(0 0 0 / 0.6); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.unis-dialog__box { display: flex; flex-direction: column; gap: var(--sp-4); max-height: inherit; padding: var(--sp-6, 32px); }
.unis-dialog__title { font-size: var(--fs-h3, var(--fs-h4)); line-height: var(--lh-h3, var(--lh-h4)); }
.unis-dialog__list {
  flex: 1; min-height: 0; margin: 0; padding: 2px; overflow-y: auto; list-style: none;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); align-content: start;
}
@media (max-width: 860px) { .unis-dialog__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .unis-dialog__list { grid-template-columns: minmax(0, 1fr); } .unis-dialog__box { padding: var(--sp-4); } }
.unis-dialog__list li[hidden] { display: none; }
.unis-dialog__item {
  position: relative; display: flex; flex-direction: column; gap: var(--sp-1); height: 100%;
  padding: var(--sp-4) var(--sp-5) var(--sp-4) var(--sp-4);
  border: var(--border) solid var(--line); border-radius: var(--r-md); background: var(--surface-2);
  cursor: pointer; transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.unis-dialog__item:hover { background: var(--surface-3); }
.unis-dialog__item input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.unis-dialog__item:has(input:focus-visible) { outline: var(--border-strong) solid var(--focus); outline-offset: var(--focus-offset); }
.unis-dialog__item:has(input:checked) { border-color: transparent; background: var(--uni-pick); color: var(--on-accent); }
.unis-dialog__item:has(input:checked) :is(.unis-dialog__name, .unis-dialog__city) { color: inherit; opacity: .72; }
.unis-dialog__item::after {   /* галочка в углу выбранного */
  content: ""; position: absolute; top: var(--sp-3); right: var(--sp-3); width: 18px; height: 18px; border-radius: 50%;
  background: var(--on-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 12.5 4 4 8-9'/%3E%3C/svg%3E") center / 12px no-repeat;
  opacity: 0; transform: scale(.6); transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.unis-dialog__item:has(input:checked)::after { opacity: 1; transform: none; }
[data-theme="light"] .unis-dialog__item::after { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23111113' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 12.5 4 4 8-9'/%3E%3C/svg%3E"); }
.unis-dialog__short { font-weight: 600; font-size: var(--fs-body); line-height: var(--lh-body); padding-right: var(--sp-5); }
.unis-dialog__name { color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.unis-dialog__city { margin-top: auto; padding-top: var(--sp-2); color: var(--text-3); font-size: var(--fs-caption); line-height: var(--lh-caption); }
.unis-dialog__actions { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); }

/* Поиск вузов в ленте (feed-search.js): строка на всю ширину под заголовком */
.section + .feed-searchbar { margin-top: var(--sp-6); }  /* поиск — часть шапки ленты, без большого отступа раздела */
.feed-search { position: relative; display: flex; align-items: center; }
.feed-search[hidden] { display: none; }
.feed-search__input { width: 100%; padding-inline: calc(var(--field-pad-x) + 1.75rem) calc(var(--field-pad-x) + 2rem); }
.feed-search__input::-webkit-search-cancel-button { display: none; }
.feed-search__icon { position: absolute; left: var(--field-pad-x); width: 1.25rem; height: 1.25rem; color: var(--text-2); pointer-events: none; }
.feed-search__clear { position: absolute; right: var(--sp-1); }
.feed-search__count { margin-top: var(--sp-3); color: var(--text-2); font-size: var(--fs-small); line-height: var(--lh-small); }
.feed-search__count[hidden] { display: none; }
.uni-card mark { background: var(--surface-5); color: inherit; border-radius: 3px; padding-inline: 1px; }
/* Режим результатов: лента — ровная сетка одинаковых карточек */
.is-searching [data-search-hide] { display: none; }
/* Вуз-фаворит в результатах поиска — обычная карточка: без программы и графика */
.uni-card--featured.is-result .uni-card__program,
.uni-card--featured.is-result .uni-card__score,
.uni-card--featured.is-result .uni-card__no-score { display: none; }
