/* ── Спецноминация «Лучший студенческий спортивный стартап» ──
   Секция главной между пятью live-треками и FAQ. Совместная с Чемпионатом.

   Зачем отдельной плитой, а не шестым треком: у неё нет ни лидера, ни своих
   экспертов, ни трёх номинаций — она идёт поперёк всех пяти направлений. Стоя
   в общем ряду, она пообещала бы сущности, которых у неё нет.

   Главное, что секция делает по смыслу — снимает противоречие. Страница трижды
   утверждает, что заявок нет (ось этапов #timeline, интро FAQ, тизеры треков),
   а здесь заявку подают сами. Поэтому первой строкой идёт признание исключения,
   а не обход его.

   Кадр — передача огня, images/student-startup-torch.webp. Он светлый
   намеренно (avg 111, верх 130), и глобального гашения здесь нет: гасить
   снимок целиком — значит потерять то, ради чего он выбран.

   Композиция «Табло» и её оформление приняты по стендам:
     student-startup-variants.html      пять композиций, выбрана «Огонь»
     student-startup-05-variants.html   четыре оформления, выбрано «Табло»
     student-startup-05a-veil.html      пять форм затемнения, выбрана диагональ
     student-startup-05b-crop.html      четыре кадрирования, выбрано 22%
   Принятый вариант целиком — student-startup-final.html.

   ВАЖНО про имена классов: в них не должно встречаться «nom». Генератор
   scripts/build-static-pages.mjs вытаскивает названия номинаций треков из
   разметки по маске class="[a-z-]*nom[a-z_-]*__title" и вшивает их в JSON-LD —
   спецноминация молча подмешалась бы в список номинаций трека. */

.startup {
  /* Высота открытого кадра — одна переменная на отступ и на завесу.
     Проценты высоты для стопов не годятся: отступ растёт по vw, высота
     секции — нет, и на 768–1080px перелом промахивался мимо титула
     (контраст падал до 1.5). Стопы, отсчитанные от самого отступа,
     держат перелом ровно там, где начинаются буквы, на любой ширине. */
  --frame-open: clamp(270px, 33vw, 480px);

  /* Доля, срезаемая у кадра сверху. Ручка, а не константа; объявлена на
     секции, а не на самом img, чтобы дев-панель могла писать её инлайн.
     Почему 22% и почему кроп вообще — в комментарии к .startup__frame img. */
  --frame-crop: 22%;

  /* ── Ручки плёнки ──
     Имена из семейства --track-film-*: секцию крутит та же дев-панель, что и
     пять треков (scripts/track-tune-panel.js, ?dev=1). Значения продублированы
     здесь, чтобы посетитель без панели видел ровно то же самое.

     Значения выставлены владельцем в дев-панели 20.08.2026. Яркость держим
     на 1: в :root у live-track-base.css стоит 1.04 под серо-холодные кадры
     треков, и она бы сюда унаследовалась, задавив пламя. Контраст 0.83 —
     свой, а не унаследованные 0.82: совпадение случайное, ручку крутили
     отдельно.

     ВНИМАНИЕ про вуаль 0.57. Замер композитом «кадр + завеса» по строкам
     текста (см. цифры у .startup__veil): на этой плотности лид даёт 2.8–3.1
     при норме 4.5 для мелкого текста. Кадр открыт так, как хотел владелец,
     и решение за ним — но если контраст надо вернуть в норму, вуаль должна
     подняться до ~0.89 либо лид перестать быть --muted-soft.

     --track-film-cool и --track-film-shade-opacity секция не читает вовсе:
     первый в треках идёт после grayscale(1), второй кладёт своё затемнение
     поверх завесы. И то и другое здесь либо убьёт цвет, либо продублирует
     диагональ. Панель их для этой секции и не показывает. */
  --track-film-brightness: 1;
  --track-film-contrast: 0.83;
  --track-film-veil-opacity: 0.57;
  --track-film-grain-opacity: 0.5;

  position: relative;
  isolation: isolate;
  overflow: clip;
  border-top: 1px solid var(--film-line);
}

.startup__frame {
  position: absolute;
  inset: 0;
  z-index: -3;
}

/* ── Кадрирование: снять пустое небо сверху ──
   В мастере верхняя четверть — ровное небо без сюжета, а внизу чаша стадиона,
   ради которой кадр и выбирался. Полоса секции по пропорции почти совпадает с
   кадром (1.47 против 1.50), поэтому object-position здесь бессилен: обрезать
   нечего, видна вся высота, и половину открытой части занимает пустота.

   Кадр растягивается выше полосы и подтягивается вверх — это тот же кроп
   «сверху 18%», только без нового файла: перевыкладывать картинку с новым
   именем ради смены рамки не нужно (старая на сервере вечная, см. правило про
   immutable). Лишние килобайты неба в загрузке остаются, но это единицы
   процентов веса.

   Второе, что делает работу, — object-position: center bottom вместо
   center 26%. На широком окне (от ~1700px) полоса и так режет кадр по высоте,
   и прежняя привязка к 26% срезала низ: чаша стадиона уходила, а небо
   оставалось. С привязкой к низу срезается ровно небо.

   22% выбраны владельцем на стенде student-startup-05b-crop.html: рамка
   тесная, пламя крупное. Плата — левый атлет теряет голову, у борта остаётся
   тёмное плечо; передачу огня держат две руки с факелами в центре, и её
   читаемость от этого не страдает. На 1920px величина кроппинга роли не
   играет: там всё решает привязка к низу. */
.startup__frame img {
  position: absolute;
  left: 0;
  top: calc(var(--frame-crop) * -1);
  width: 100%;
  height: calc(100% + var(--frame-crop));
  object-fit: cover;
  object-position: center bottom;
  /* Без grayscale: пламя — единственный тёплый акцент на всей полосе. */
  filter: brightness(var(--track-film-brightness, 1)) contrast(var(--track-film-contrast, 1));
}

/* Затемнение идёт по диагонали, из левого нижнего угла — там, где стоят буквы.
   Выбрано сравнением пяти форм на стенде student-startup-05a-veil.html, и
   решило не число, а свойство границ.

   Плашка узнаётся не по резкости перепада, а по его прямизне: пока изолинии
   плотности совпадают с краями кадра, глаз читает наложенный прямоугольник —
   даже если перепад мягкий. У прежней версии (вертикальный градиент с
   горизонтальной маской) пик был всего 0.30 альфы на 100px, мягче любой другой
   формы, и она всё равно опознавалась ступенью по середине кадра. У диагонали
   пик 0.15 и ни одной границы, параллельной борту, — на снимке она читается
   падением света.

   202deg, а не 158: в CSS отсчёт идёт по часовой от «вверх», и 158 уводит
   плотность вниз-вправо, в противоположный угол. На глаз ошибка не видна,
   замер показал 2.3 вместо 4.5.

   Цена приёма: гасит 47% полосы против 29% у маски. Эллипс и наложение мягких
   пятен гасят меньше, но у обоих в ровном небе проступает дуга.

   Замер композитом «кадр + завеса» по строкам текста, худшая точка.
   При opacity 1.0 (как форма выбиралась на стенде): лид 4.8–5.2, титул 6.9.
   При принятых 0.57 — 1200 / 1440 / 1900: лид 2.96 / 3.11 / 2.78, титул
   5.02 / 3.60 / 3.35. То есть титул норму 3.0 держит везде, лид под нормой
   4.5 на всех трёх ширинах. Возврат лида к 4.5 требует вуали ~0.89.
   Ниже 1080px замер не про завесу: она снята, текст стоит на панели. */
.startup__veil {
  position: absolute;
  inset: 0;
  z-index: -2;
  opacity: var(--track-film-veil-opacity, 1);
  background: linear-gradient(
    202deg,
    rgba(10, 12, 16, 0) 0%,
    rgba(10, 12, 16, 0) 30%,
    rgba(10, 12, 16, 0.4) 46%,
    rgba(10, 12, 16, 0.82) 62%,
    rgba(10, 12, 16, 0.92) 80%,
    rgba(10, 12, 16, 0.94) 100%
  );
}

/* ── Зерно ──
   Две причины, и обе не про вкус.

   Первая — ряд. Все пять live-треков идут через плёнку с зерном 0.06–0.16
   (styles/live-track-base.css), и спецноминация стоит прямо под треком 05,
   у которого 0.16. Без своего зерна она оказывалась единственным чистым
   снимком на странице — не «аккуратнее», а из другого набора.

   Вторая — полосы. Завеса выше это длинный мягкий градиент поперёк почти
   ровного неба, то есть ровно тот случай, когда 8-битный экран показывает
   ступени. Зерно работает здесь дизером и снимает их.

   0.5 — выбор владельца, и это потолок ползунка «Зерно» в дев-панели
   (?dev=1): втрое выше самого зернистого трека (0.16). Расчётной стартовой
   точкой было 0.09 — в треках шум ложится на grayscale(1) и холодный тон,
   здесь на цветное пламя с пиками 247, и soft-light поверх таких светов
   грязнит быстрее. Владелец увёл ручку в максимум, значит зерно тут не
   дизер, а фактура. Понадобится больше — поднимать max у контрола `grain`
   в scripts/track-tune-panel.js, ползунок упёрт.

   На контраст текста зерно не влияет: фактура шума симметрична около
   середины, soft-light с 0.5-серым — тождество, поэтому средняя яркость
   подложки не сдвигается, растёт только разброс.

   Слой отдельным элементом, а не псевдо на .startup: ниже 1080px завеса
   снимается, кадр ужимается в баннер высотой --frame-open, и зерно должно
   уйти вместе с ним. Поверх плоской базы страницы оно читается серой пеленой
   (тот же вывод, что и у #founder / #timeline в track-tune-panel.js).

   z-index -1: выше кадра и завесы, ниже текста и ленты — по буквам и по стеклу
   ленты шум не идёт. */
.startup__grain {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--track-film-grain-opacity, 0);
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

/* Обёртка нужна ниже 1080px: там она становится плоскостью во всю ширину, на
   которую садится текст вместо завесы. На ПК прозрачна и ничего не делает. */
.startup__panel {
  position: relative;
}

/* Верхний отступ отдан кадру: пламя и небо стоят над текстом, буквы
   начинаются там, где завеса уже набрала плотность. */
.startup__body {
  width: min(100% - 2.5rem, 1220px);
  margin: 0 auto;
  padding: var(--frame-open) 0 clamp(26px, 3vw, 40px);
}

.startup__eyebrow,
.startup__title,
.startup__lead {
  text-shadow: var(--track-title-edge);
}

/* Кикер стоит на ещё открытом небе: своя подложка вместо того, чтобы гасить
   небо ради одной строки. Под ней есть кадр — стекло уместно. Заодно строка
   читается как метка-ярлык, а не как текст, брошенный в воздух. */
.startup__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--glass-strong);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--ink);
  font: 800 var(--text-xs) / 1.2 var(--font-ui);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

/* Знак партнёра — парой light+color, как в ростере подвала: серый в покое,
   цветной на наведении. */
.startup__partner {
  height: 15px;
  width: auto;
  opacity: 0.72;
  transition: opacity 180ms ease;
}

.startup__eyebrow:hover .startup__partner {
  opacity: 1;
}

.startup__title {
  margin: 14px 0 0;
  max-width: 18ch;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-h1);
  line-height: 0.98;
  letter-spacing: -0.035em;
}

.startup__lead {
  max-width: 56ch;
  margin: 14px 0 0;
  color: var(--muted-soft);
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: 1.65;
}

/* ── Лента «Табло» ──
   Условия и статус собраны в одну ленту во всю ширину окна: фон и волоски идут
   от борта до борта, содержимое выровнено по колонке текста. Стекло здесь не
   украшение — лента стоит на кадре, и блюр сбивает локальные пики яркости
   под буквами, а по ним и считается худшая точка контраста.

   Плотность стекла 0.86, а не 0.58: завеса выше гаснет вправо и до правых
   ячеек не достаёт, значит ленте приходится держать контраст самой. Заодно
   это и честнее по чтению — лента перестаёт быть полупрозрачной плёнкой
   поверх кадра и становится тем, чем должна: отдельным прибором с собственной
   плоскостью. Граница между кадром и ней — кромка элемента, а не растворение
   градиента. */
.startup__bar {
  position: relative;
  border-top: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--film-line);
  background: rgba(10, 12, 16, 0.86);
  backdrop-filter: blur(16px) saturate(120%);
  -webkit-backdrop-filter: blur(16px) saturate(120%);
}

.startup__cells {
  width: min(100% - 2.5rem, 1220px);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr)) minmax(238px, 0.92fr);
}

/* dl держит семантику пар, а сеткой правит родитель. */
.startup__terms {
  display: contents;
  margin: 0;
}

/* Три этажа вместо пилюли: метка, значение и уточнение. Пилюля «До 25 лет»
   читалась двусмысленно — непонятно, к кому относится возраст; строка «Все
   ключевые участники команды» снимает вопрос, и то же с остальными тремя. */
.startup__cell {
  padding: clamp(16px, 1.8vw, 22px) clamp(12px, 1.5vw, 22px);
  border-left: 1px solid var(--line-soft);
}

.startup__cell:first-child {
  padding-left: 0;
  border-left: 0;
}

.startup__cell dt {
  margin: 0 0 7px;
  color: var(--color-text-muted);
  font: 800 var(--text-2xs) / 1.2 var(--font-ui);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

/* Значение — условным дисплейным: в ленте это счёт на табло. */
.startup__cell dd {
  margin: 0;
  font: 700 var(--text-h3) / 1.05 var(--font-display);
  letter-spacing: -0.02em;
}

/* Уточнение в ленте — на --muted-soft, а не на --muted: под правыми ячейками
   завесы уже нет, и полшага яркости здесь решают 4.1 против 5.0 по худшей
   точке. */
.startup__cell dd span {
  display: block;
  margin-top: 6px;
  color: var(--muted-soft);
  font: 400 var(--text-sm) / 1.5 var(--font-body);
  letter-spacing: 0;
}

/* ── Статус вместо кнопки ──
   Кнопки нет намеренно, и это не заглушка «на потом». Погашенная кнопка
   читается как сломанная вёрстка, а не как «ещё не время»; строка-статус
   с живой ссылкой на канал не оставляет читателя в тупике.
   Включать форму нельзя и юридически: она собирает ПД (контакты участника,
   состав команды), значит политика и согласие по 152-ФЗ нужны до запуска.

   Пятая ячейка ленты — живая: единственное золото в ленте, и оно на
   состоянии, а не на украшении. */
.startup__live {
  display: grid;
  align-content: start;
  gap: 7px;
  padding: clamp(16px, 1.8vw, 22px) 0 clamp(16px, 1.8vw, 22px) clamp(16px, 1.6vw, 22px);
  border-left: 2px solid var(--gold-border);
  background: linear-gradient(180deg, rgba(232, 195, 106, 0.07), rgba(232, 195, 106, 0) 62%);
}

/* Точка вынесена в строку заголовка, а не отдельным этажом: в узкой ячейке
   она иначе съедала бы целую строку. */
.startup__live-main {
  display: grid;
  grid-template-columns: 7px minmax(0, 1fr);
  align-items: baseline;
  gap: 10px;
  font: 700 var(--text-md) / 1.3 var(--font-ui);
  letter-spacing: -0.01em;
}

.startup__live-sub {
  color: var(--muted-soft);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.startup__dot {
  position: relative;
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--gold);
}

.startup__dot::after {
  content: '';
  position: absolute;
  inset: -5px;
  border: 1px solid var(--gold-border);
  border-radius: 50%;
  animation: startupPulse 2.6s ease-out infinite;
}

@keyframes startupPulse {
  0% {
    opacity: 0.7;
    transform: scale(0.7);
  }
  70%,
  100% {
    opacity: 0;
    transform: scale(1.35);
  }
}

@media (prefers-reduced-motion: reduce) {
  .startup__dot::after {
    animation: none;
    opacity: 0.5;
  }
}

.startup__link {
  color: var(--color-gold-text);
  font: 700 var(--text-sm) / 1 var(--font-ui);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid rgba(225, 177, 79, 0.4);
  transition:
    color 160ms ease,
    border-color 160ms ease;
}

.startup__live .startup__link {
  justify-self: start;
  margin-top: 2px;
}

.startup__link:hover,
.startup__link:focus-visible {
  color: var(--gold);
  border-color: var(--gold);
}

/* ——— ниже 1080px завесы нет вовсе ———
   Диагональ держится на том, что текст занимает левую треть полосы, а справа
   остаётся открытый кадр. На узком окне текст идёт во всю ширину, и любая
   боковая форма начинает съедать плотность под самими буквами.

   Но и вертикальная завеса тут не выход: cover кадрирует снимок по горизонтали
   и оставляет в полосе центральную колонку — ту самую, где пламя с пиками 247.
   Завеса, достаточная для чтения, гасит 71% полосы с перепадом 0.77 — та же
   плашка, только во всю ширину.

   Поэтому текст садится на собственную панель над лентой: кадр остаётся
   баннером сверху и не тронут вовсе (погашено 0%), а секция читается как
   «кадр + прибор». Контраст держит панель, а не завеса: лид 4.8. */

@media (max-width: 1080px) {
  .startup {
    background: var(--bg-base-top);
  }

  .startup__veil {
    display: none;
  }

  /* Кадр обрезается по высоте полосы, а не тянется на всю секцию. Иначе он
     остаётся под панелью и просвечивает сквозь неё размытым призраком — на
     телефоне это выглядело грязью под буквами.

     Зерно ужимается тем же правилом: ниже панели снимка уже нет, и шум по
     плоской базе дал бы серую пелену. */
  .startup__frame,
  .startup__grain {
    bottom: auto;
    height: var(--frame-open);
  }

  /* Панели хватает волоска: под ней теперь база страницы, а не снимок,
     поэтому ни заливка, ни блюр не нужны — размывать нечего. */
  .startup__panel {
    margin-top: var(--frame-open);
    border-top: 1px solid var(--line-strong);
  }

  .startup__body {
    padding: clamp(24px, 3vw, 34px) 0 clamp(20px, 2.4vw, 28px);
  }

  /* Кромка больше не нужна: буквы стоят на плоскости, а не на снимке. */
  .startup__eyebrow,
  .startup__title,
  .startup__lead {
    text-shadow: none;
  }

  /* Плашка кикера тоже лишняя — она была подложкой под небо. */
  .startup__eyebrow {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    color: var(--color-text-muted);
  }

  .startup__title {
    max-width: none;
  }

  /* Волосок панели уже разделил кадр и текст — ленте хватит тихого. */
  .startup__bar {
    border-top-color: var(--line-soft);
  }

  .startup__cells {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .startup__cell:nth-child(odd) {
    padding-left: 0;
    border-left: 0;
  }

  .startup__cell:nth-child(n + 3) {
    border-top: 1px solid var(--line-soft);
  }

  .startup__live {
    grid-column: 1 / -1;
    border-top: 1px solid var(--line-soft);
  }
}

@media (max-width: 640px) {
  /* Меняется только высота полосы кадра — панель и снятая завеса приходят
     из блока 1080. */
  .startup {
    --frame-open: clamp(200px, 58vw, 380px);
  }

  .startup__body {
    padding: clamp(22px, 5vw, 30px) 0 clamp(18px, 4vw, 26px);
  }

  /* «СПЕЦНОМИНАЦИЯ · СОВМЕСТНО С» в 11px с трекингом .16em не влезает в 390px
     и роняет одинокую «С» на вторую строку. Кегль и трекинг поджаты ровно
     настолько, чтобы строка встала целиком рядом со знаком. */
  .startup__eyebrow {
    font-size: 9.5px;
    letter-spacing: 0.1em;
    gap: 8px;
  }

  .startup__eyebrow img {
    height: 13px;
  }

  .startup__title {
    font-size: clamp(26px, 8vw, 34px);
  }

  .startup__cells {
    grid-template-columns: 1fr;
  }

  .startup__cell {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--line-soft);
  }

  .startup__cell:first-child {
    border-top: 0;
  }
}

/* ── Пункт в выпадающем меню «Треки» ──
   Шестым, но без номера: это не шестое направление, а сквозная номинация по
   всем пяти. Волосок сверху отделяет её от списка треков, иначе прочитается
   как трек 06. */
.lock-nav__dropdown-special {
  margin-top: 0.35rem;
  padding-top: 0.6rem !important;
  border-top: 1px solid var(--line-soft) !important;
}

.lock-nav__dropdown-mark {
  justify-self: center;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-gold-text);
}

.lock-nav__dropdown-spec {
  display: block;
}

.lock-nav__dropdown-eyebrow {
  display: block;
  margin-bottom: 2px;
  color: var(--color-gold-text);
  font-family: var(--font-ui);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Раскладка спецноминации в desktop-мега-меню теперь общая для всех страниц
   и живёт в lock-nav.css: от 721px — шестая карточка того же рецепта, что
   треки (сетка 3×2 на планшете, шесть равных в ряд от 1360px). */

/* Мобильное меню: тот же приём — без номера, отделено волоском. */
.mobile-menu__track-list a.mobile-menu__track-special {
  margin-top: 6px;
  border-color: var(--line-strong);
}

.mobile-menu__track-special .mobile-menu__track-num {
  font-size: 9px;
  letter-spacing: 0.1em;
  line-height: 1.2;
}
