/* ============================================================================
   SARMAT — оформление сайта.

   ОТКУДА ВЗЯТЫ ЧИСЛА. Палитра, размеры карточек, отступы и скругления сняты
   с живого образца (live.strikepackagestudios.com) вычислением стилей прямо в
   браузере, а не подобраны на глаз: фон 12/14/19, панель 26/33/48, линия
   42/47/56, зелёный 55/214/122, голубой 77/210/255, красный 255/90/90;
   полоса содержимого 1180 с полями 24, карточки серверов 557 в два ряда с
   просветом 18, строки-ссылки 368 в три ряда с просветом 14, скругления 14 и
   11. Первый экран — по spacex.com: полноэкранные кадры, текст слева внизу,
   кнопка тонкой рамкой, чёрный фон.

   ШРИФТ — СИСТЕМНЫЙ, И ЭТО ПРАВКА. Прежний сайт тянул Oswald и Inter с
   fonts.googleapis.com на КАЖДОЙ из восьми страниц. Сервер кампании стоит за
   брандмауэром, и у зрителя без выхода в интернет оформление рассыпалось. У
   образца, с которого снят дизайн, тоже стоит системный шрифт — ни одного
   внешнего файла. Мы теперь так же.
   ============================================================================ */

:root {
  /* ------------------------------------------------------------------------
     ЕДИНСТВЕННАЯ ПАЛИТРА — «СУ-57»: тёмная бирюза, серый металл, медь сопел.

     Решение заказчика 7 сентября: «убираем дизайн night, оставляем только
     SU-57». До этого схем было две и между ними стоял ползунок в шапке.

     ПОЧЕМУ ЦВЕТА ПЕРЕЕХАЛИ СЮДА, А НЕ ОСТАЛИСЬ В СВОЁМ БЛОКЕ. Пока схем две,
     вторая живёт в `html[data-skin="metal"]` и включается атрибутом. Схема
     одна — значит атрибут ставить некому, и блок молча перестал бы
     действовать: сайт открылся бы с прежними сине-серыми числами, которые
     никто не менял. Поэтому числа «Су-57» стоят прямо в `:root`, а блок
     второй схемы снят целиком.

     ЧИСЛА СНЯТЫ СО СНИМКА МАШИНЫ, а не подобраны: тёмная бирюза теней борта,
     холодный серый камуфляжа в тексте, светлая бирюза подсветки фонаря в
     ссылках, медь сопел в тёплых подробностях.

     КРАСНЫЙ И СИНИЙ СТОРОН НЕ ТРОНУТЫ. Это не украшение, а язык карты: по ним
     игрок отличает своё от чужого, и они обязаны совпадать с игрой.

     СЕРЫЕ ПОДНЯТЫ ПО ЗАМЕРУ контраста (проба 06, порог AA 4.5), а не на глаз.
     ------------------------------------------------------------------------ */
  /* фон и панели */
  --bg:      #070c0d;
  --bg2:     #0a1214;
  --panel:   #101c1f;
  --panel2:  #142428;
  --panel3:  #0d1618;
  --sunk:    #091012;

  /* линии */
  --line:    #1c2c30;
  --line2:   #26403f;

  /* текст */
  --ink:     #f2f7f7;
  --ink2:    #c8d8d9;
  --ink3:    #b4c5c6;
  /*  #7d8695 подняли до #808998 — три пункта по каждому каналу. Глазом это
      тот же серый, но замер важнее глаза: на подложке выпадающего списка
      прежний давал 4.38 при пороге 4.5, и подписи «владение, секторы,
      объекты» под пунктами «Статистики» не дотягивали. Прежнюю палитру
      контрастом никто не мерил — проба 06 появилась позже неё, — и находка
      всплыла ровно в тот час, когда палитру вернули.  */
  --muted:   #93a7a9;
  /*  И второй серый — тем же порядком. #6c7382 давал 4.03 в подвале
      («SARMAT · сборка», «Не связано с Eagle Dynamics») и 3.38 на панели.
      Замер по трём подложкам сразу, а не по одной: серый ходит по всем.  */
  --muted2:  #97a9ab;

  /* смысловые цвета */
  --accent:  #47c8c2;   /* ссылки, выделение */
  --green:   #5fd3ad;   /* «на связи», «свои» */
  --red:     #ff5a5a;   /* «нет связи», потери */
  --gold:    #d59559;   /* защищённые поля, ас */
  --side-red:  #ff6b6b;
  --side-blue: #6fb5ff;
  --brd-blue:  #3a6ea5;
  --brd-red:   #a5473a;

  /* ------------------------------------------------------------------------
     МЕТАЛЛИЧЕСКИЕ ПОДРОБНОСТИ — ПЕРЕМЕННЫМИ, А НЕ ПРАВИЛАМИ СХЕМЫ.

     Новая схема «Су-57» просит бликов, кромок и фактуры. Написать их прямо в
     её блоке нельзя: правило, живущее в одной схеме, во второй молча
     исчезает, и «сломалось при переключении» ищут потом весь вечер. Поэтому
     правила общие (ниже, раздел «металлические подробности»), а СХЕМА
     ЗАДАЁТ ЗНАЧЕНИЯ. В «Ночной» они пустые — она выглядит ровно так, как её
     вернул заказчик 6 сентября, ни одним пикселем иначе.
     --------------------------------------------------------------------- */
  --sheen:   linear-gradient(180deg, rgba(233,247,247,.055) 0%,
                                   rgba(233,247,247,.012) 38%,
                                   rgba(0,0,0,.12) 100%);               /* блик по панели */
  --edge:    rgba(216,236,238,.16);        /* светлая кромка сверху */
  --tex:     none;               /* фактура фона */
  --rule:    rgba(200,130,63,.38);        /* тёплая черта под шапкой */
  --seam:    linear-gradient(90deg, rgba(200,130,63,.55) 0%,
                                  rgba(38,64,63,.85) 42%, rgba(38,64,63,.35) 100%);        /* черта справа от названия раздела */
  --btn-bg:  #c8823f;               /* кнопка под курсором */
  --btn-ink: #0a1214;
  --hover:   #142326;            /* подсветка строки под курсором */
  --copper:  #c8823f;        /* тёплый металл; в «Ночной» это прежнее золото */

  /* ------------------------------------------------------------------------
     УВЕЛИЧЕНИЕ ВСЕХ РОЛИКОВ YOUTUBE — ОДНО ЧИСЛО НА ВЕСЬ САЙТ.

     Заказчик 6 сентября: «добавить правило увеличения всех видео с ютуб как на
     остальных страницах». До этого множитель жил в ПЯТИ местах — в баннере
     главной (двумя парами чисел плюс телефонная), во внутреннем баннере
     (`scale`), в малой карточке и в квадратной. Каждая прибавка «ещё на 20%»
     означала пять правок, и первая же забытая давала страницу, где кадр
     другого размера, — заказчик это и увидел.

     Теперь размеры рамок записаны как «своё число × множитель», а множитель
     здесь. Прибавить всем роликам разом — поправить ОДНУ строку.
     --------------------------------------------------------------------- */
  /*  УВЕЛИЧЕНИЕ РАМОК СНЯТО (заказ 9 сентября: «увеличение видео в ноль»).
      Здесь было 1.44 — две прибавки по 20% от 6 сентября (1.2 × 1.2), то
      есть 44%, а не 30%: тридцать процентов — это другое число и другое
      место, окна разделов ниже. Множитель оставлен строкой, а не вырезан:
      им по-прежнему правят все рамки разом.  */
  --vzoom:  1;

  --r-card: 14px;
  --r-row:  11px;
  --wrap:   1180px;

  /* ------------------------------------------------------------------------
     СТАРЫЕ ИМЕНА ПЕРЕМЕННЫХ — ЖИВЫЕ ССЫЛКИ, А НЕ ПАМЯТНИК.
     Карта (map.html, sarmatmap.js) и часть страниц набраны на прежних именах:
     --ink-2, --ink-3, --line-2, --ok, --brand. Переименовать их разом по
     четырнадцати файлам значит переписывать РАБОЧУЮ карту на 1000 строк ради
     косметики — ровно то, чего делать нельзя. Пока имена ведут на новые цвета,
     старая вёрстка красится новой палитрой сама. Пропущенное имя было бы
     видно сразу: цвет не применился бы вовсе.
     --------------------------------------------------------------------- */
  --ink-2:  var(--ink2);
  --ink-3:  var(--ink3);
  --line-2: var(--line2);
  --bg-2:   var(--panel);
  --bg-3:   var(--panel3);
  --ok:     var(--green);
  --brand:  var(--accent);
  --brand-2: var(--accent);
  --blue:   var(--side-blue);
  --head:   "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --body:   "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --gap:    18px;
  --pad:    24px;

  color-scheme: dark;
}


* { box-sizing: border-box; }

html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  /*  Фактура — отдельным свойством, а не в сокращённой записи: сокращённая
      сбрасывала бы её всякий раз, когда правят цвет фона.  */
  background-image: var(--tex);
  background-attachment: fixed;   /* фактура принадлежит фону, а не прокрутке */
  color: var(--ink);
  font: 16px/1.55 "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; font-weight: 600; line-height: 1.15; }

.mono { font-family: Consolas, "SF Mono", ui-monospace, monospace; }
/* ----------------------------------------------------------------------------
   КОМАНДА В ТЕКСТЕ — ЖЁЛТЫМ И ЖИРНЫМ.
   Заказ 15 сентября: «в гайде команды типа .credits или /action /order жирным
   жёлтым цветом». Класс ставит разметка (`mark` в sarmat.js) только тому, что
   начинается с косой черты или точки, — разбор там же.
   Цвет из палитры: тот же --gold, что у аса и у цены головы. Своего жёлтого на
   сайте не заводим — два жёлтых однажды разойдутся.
   ---------------------------------------------------------------------------- */
.mono.cmd { color: var(--gold); font-weight: 700; }
.muted { color: var(--muted); }
.hidden { display: none !important; }
.grow { flex: 1 1 auto; }
.row { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.stack > * + * { margin-top: 12px; }

/* ---------- полоса содержимого ---------- */
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap-x { overflow-x: auto; }

/* ----------------------------------------------------------------------
   СПРЯТАННОЕ — ПРЯЧЕТСЯ. НАЙДЕНО СНИМКОМ 12 сентября.

   Кнопка «Сбросить» на странице заказов стояла с атрибутом `hidden`, а
   была видна. Причина не в ней: у браузера `[hidden]` значит
   `display: none`, но это правило САМОЕ СЛАБОЕ, и любое наше
   `display: inline-flex` его перебивает — а оно стоит у `.btn`, у
   `.btn-line`, у всего, что мы верстаем рядами.

   То есть любая наша кнопка, спрятанная атрибутом, оставалась на экране.
   Чинить это в каждой странице по-своему значило бы чинить следствие;
   правило одно, здесь, и с `!important` — потому что перебить оно обязано
   именно наши собственные `display`.
   ---------------------------------------------------------------------- */
[hidden] { display: none !important; }

/* ----------------------------------------------------------------------
   ЗНАЧОК «ОДНА МАШИНА» У ЗАКАЗА.

   В меню F10 единичные машины стоят своей подгруппой наверху, и по одному
   этому видно, что «IFV» — это одна БМП, а не колонна. В таблице, которую
   можно сортировать, подгруппа не живёт: первый же щелчок по заголовку её
   разрушит. Поэтому признак едет со строкой — тихой пометкой у имени.
   ---------------------------------------------------------------------- */
.one {
  display: inline-block; margin-left: 8px; padding: 1px 7px;
  border: 1px solid var(--line2); border-radius: 999px;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); vertical-align: 1px; white-space: nowrap;
}

/* ============================================================================
   ЧЕРДАК
   ========================================================================= */
/* ЛИПНЕТ ОБЁРТКА, А НЕ САМА ШАПКА — И ЭТО НЕ ПРИДИРКА.
   `position: sticky` держит элемент в пределах РОДИТЕЛЯ. Шапка вставляется
   скриптом в <div id="hdr">, высота которого равна высоте самой шапки, —
   значит липнуть ей было некуда, и на всех страницах она честно уезжала
   вверх при первой же прокрутке, хотя правило `sticky` стояло здесь с
   самого начала и выглядело работающим. Замечено на руководстве: полоса
   правки липла «под шапку» на 67 px, а шапки на экране уже не было, и в
   зазор просвечивал текст. Липким объявлена обёртка; правило у `.top`
   оставлено — оно безвредно и показывает замысел. */
#hdr { position: sticky; top: 0; z-index: 60; }
.top {
  display: flex; align-items: center; gap: 18px;
  height: 66px; padding: 0 26px;
  background: var(--bg2);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 60;
}
.brand { display: flex; align-items: center; gap: 10px; color: var(--ink); }
.brand:hover { text-decoration: none; }
.brand img { height: 30px; width: auto; display: block; }
.brand b {
  font-size: 15px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase;
}

.nav { display: flex; align-items: center; gap: 2px; margin-left: 8px;
       min-width: 0; overflow-x: auto; scrollbar-width: none; }
.nav::-webkit-scrollbar { height: 0; }
.nav a, .nav .drop > button {
  display: block; padding: 8px 10px; border-radius: 8px;
  color: var(--ink3); font-size: 12.5px; font-weight: 500;
  letter-spacing: .04em; text-transform: uppercase;
  background: none; border: 0; cursor: pointer; font-family: inherit;
  white-space: nowrap;
}
/*  ПОДСВЕТКА ПУНКТА — ПЕРЕМЕННОЙ, А НЕ ЧИСЛОМ. Здесь стояли `#16211a` и
    `#1c2a21` — оттенки зелёной схемы, вписанные числами. Пока зелёная была
    единственной, это не было видно; стоило вернуть сине-серую — и активный
    пункт меню остался зелёным пятном на сине-сером сайте. Переменная
    красится той схемой, которая включена.  */
.nav a:hover, .nav .drop > button:hover { color: var(--ink); background: var(--panel); text-decoration: none; }
.nav a.on, .nav .drop > button.on { color: var(--ink); background: var(--panel2); }
/* Строка внутри выпадающего списка тоже помечается: «я в Статистике» и
   «я именно на Сводке» — разные сведения, и человеку нужны оба. */
.drop-menu a.on { color: var(--ink); background: var(--panel2); }

/* ============================================================================
   ВЫПАДАЮЩЕЕ МЕНЮ «СТАТИСТИКА» — РАЗБОР ПОЛОМКИ.

   ЧТО БЫЛО. Меню не открывалось НИ НА ОДНОЙ ширине окна, и в консоли при
   этом было чисто: и щелчок, и наведение честно ставили `display: block`,
   но увидеть список было нельзя.

   ПРИЧИНА. У строки меню стоит `overflow-x: auto` — чтобы на узком экране
   пункты можно было пролистать вбок. Но `overflow-x: auto` при видимом
   `overflow-y` по правилам CSS превращает и вертикальный в `auto`, то есть
   строка меню СТАЛА КОРОБКОЙ С ОБРЕЗКОЙ. Список открывался вниз — за её
   край, и обрезался целиком. Замер: `display: block`, размеры настоящие, а
   точка в середине первой строки списка попадает в шапку под ним.

   ЛЕЧЕНИЕ. Список выкладывается `position: fixed` — по окну, а не внутри
   строки меню, — и обрезать его нечем. Место под кнопкой считает скрипт при
   открытии (`dropAt` в sarmat.js): у постоянного положения нет «низа
   родителя», от которого можно оттолкнуться.

   ПОЧЕМУ НЕ УБРАЛ ОБРЕЗКУ. Она там не для красоты: без неё пункты меню на
   узком экране уезжают за край и до половины из них не добраться вовсе.
   Менять высоту шапки тоже нельзя — от неё отмеряют своё место полоса
   правки руководства и оглавление, и они уехали бы вместе с ней.
   ============================================================================ */
.drop { position: relative; }
.drop-menu {
  position: fixed; min-width: 210px;
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: 10px; padding: 6px; display: none; z-index: 90;
  box-shadow: 0 18px 40px rgba(0,0,0,.55);
}
.drop.open .drop-menu { display: block; }
.drop-menu a {
  display: block; padding: 9px 11px; border-radius: 7px;
  text-transform: none; letter-spacing: 0; font-size: 13.5px; color: var(--ink2);
}
.drop-menu a small { display: block; color: var(--muted); font-size: 11.5px; }
/*  У ВЫДЕЛЕННОЙ строки подложка светлее, и приглушённый текст на ней
    проваливается: замер дал 4.26 при пороге 4.5. Подпись выделенной
    строки берёт цвет поярче — она и так важнее прочих.  */
.drop-menu a.on small { color: var(--ink3); }

/* Полоса связи не сжимается и не выталкивается за край: меню умеет
   прокручиваться, а «сервер не отвечает» обрезаться не должно — это
   единственное место, где сайт признаётся, что данные несвежие. */
/* ----------------------------------------------------------------------------
   КТО ИЗ ДВОИХ ЖМЁТСЯ ПЕРВЫМ — ЭТО РЕШЕНИЕ, А НЕ НАСТРОЙКА.

   Здесь стояло `flex: none`, и стояло по делу: полоса связи не должна была
   обрезаться, потому что это единственное место, где сайт признаётся, что
   данные несвежие. Но 7 сентября в шапку пришли вкладка «Учебка» и три
   внешние ссылки, и защищённых мест стало два: строка вкладок и эта полоса.
   Оба целыми на 1280 не помещаются — замер даёт нехватку в полсотни
   пикселей, — и «не жмётся никто» на деле означало «жмётся строка вкладок»:
   у неё `overflow-x: auto`, она молча обрезала последний пункт посреди слова
   и даже полоски прокрутки не показывала.

   Выбор сделан в пользу вкладок. Пункт меню, обрезанный до «DIS», читается
   как поломка сайта; надпись о свежести данных, укороченную многоточием,
   видно, что она укорочена, — и она не единственный знак: рядом горит точка
   связи, красная при молчании сервера, а полный текст остаётся во
   всплывающей подсказке (`title` ставится там же, где сама надпись).
   ---------------------------------------------------------------------------- */
.live { margin-left: auto; display: flex; align-items: center; gap: 8px;
        font-size: 12.5px; color: var(--muted); white-space: nowrap;
        flex: 0 60 auto; min-width: 0; }
/*  Шестьдесят против единицы — это не «побольше», а порядок жертв, записанный
    числом: сжатие делится между соседями по весу «доля × ширина», и при таком
    перевесе строка вкладок отдаёт из полусотни недостающих пикселей один. А
    внутри самой полосы связи жмётся ровно надпись: у ссылок, языков и точки
    сжатие снято, иначе кнопки RU/EN расползлись бы вместо неё. */
.nav { flex: 0 0 auto; }
.live > .hlinks, .live > .lang, .live > .dot { flex: none; }
/*  ТОЛЬКО ПРЯМОЙ РЕБЁНОК — и это не придирка к записи правила.
    В правой группе появились три внешние ссылки, а у каждой внутри свой
    `<span>` с надписью. Правило `.live span` доставало и их: подписи
    «Discord», «Tacview», «Patreon» получали чужой межбуквенный просвет и
    обрезку по 260 px, а на телефоне — `max-width: 100%` из узкого правила.
    Замер это и показал: `.live span` вернул «Discord» вместо надписи о
    свежести данных. Стрелка `>` возвращает правилу его законный адрес —
    `<span id="hTxt">`, лежащий прямо в полосе связи. */
.live > span { letter-spacing: .04em; max-width: 260px; overflow: hidden;
               text-overflow: ellipsis; flex: 0 1 auto; min-width: 0; }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--red);
       box-shadow: 0 0 0 3px rgba(255,90,90,.15); display: inline-block; }
.dot.on { background: var(--green); box-shadow: 0 0 0 3px rgba(55,214,122,.15); }

/* переключатель языка */
.lang { display: flex; border: 1px solid var(--line2); border-radius: 8px; overflow: hidden; }
.lang button {
  background: none; border: 0; color: var(--muted); cursor: pointer;
  font: 600 11px/1 inherit; letter-spacing: .1em;
  padding: 7px 9px; font-family: inherit;
}
.lang button.on { background: var(--panel2); color: var(--ink); }

/* ============================================================================
   ТРИ ВНЕШНИЕ ССЫЛКИ СПРАВА — Discord, Tacview, Patreon.
   Решение заказчика 7 сентября по образцу: надпись с логотипом, Discord —
   залитой плашкой, остальные — просто надписями.

   ПОЧЕМУ ВЫСОТА ЗАДАНА, А НЕ ОТДАНА КАРТИНКЕ. Логотипы придут файлами
   разного размера, и если высоту диктует картинка, то в день замены одного
   файла на другой поедет вся правая половина шапки. Высота — у строки,
   картинка вписывается в неё.

   ПОЧЕМУ НЕ `flex: none`. У полосы связи справа `flex: none` стоит нарочно —
   «сервер не отвечает» обрезаться не должно. Ссылкам такой брони не нужно:
   на тесном экране они сжимаются и прокручиваются вместе с шапкой, а самое
   нужное (адрес Discord) продублировано в подвале.
   ============================================================================ */
.hlinks { display: flex; align-items: center; gap: 2px; min-width: 0; }
.hlinks a {
  display: inline-flex; align-items: center; gap: 7px;
  height: 30px; padding: 0 10px; border-radius: 8px;
  color: var(--ink3); font-size: 12px; font-weight: 600;
  letter-spacing: .04em; white-space: nowrap;
}
.hlinks a:hover { color: var(--ink); background: var(--panel); text-decoration: none; }
.hlinks a.lead { color: var(--ink); background: var(--panel2); }
.hlinks a.lead:hover { background: var(--panel); }
.hlinks img { height: 15px; width: auto; display: block; flex: none; }

/*  ПОЛЗУНКА СХЕМ БОЛЬШЕ НЕТ (решение заказчика 7 сентября: «убираем дизайн
    night, оставляем только SU-57»). Схема одна, переключать нечего — а
    переключатель, который ничего не переключает, читается как поломка.

    ЕГО ПРАВИЛА СНЯТЫ ЦЕЛИКОМ, вместе с двумя порогами ширины, заведёнными
    ради него: на 1520 у него прятались подписи, на 1450 поджимались поля
    пунктов меню. Оставь я их — в шапке навсегда осталась бы теснота ради
    того, чего в ней уже нет. Порог 1350 (ниже) остаётся: он про сами пункты
    меню и к ползунку отношения не имел.  */
/*  И ВТОРАЯ СТУПЕНЬ, ТОЖЕ ПО ЗАМЕРУ. Одних подписей мало: на 1440 меню
    влезает, на 1280 — нет, потому что сам ползунок занимает полсотни
    пикселей. Вместо того чтобы прятать ползунок (его просили в шапку) или
    резать надпись о свежести данных (это единственное место, где сайт
    признаётся, что данные несвежие), поджимаем поля у пунктов меню:
    восемь пунктов по семь пикселей и дают недостающее.  */
@media (max-width: 1450px) {
  .nav a, .nav .drop > button { padding: 8px 6px; }
  .top { gap: 12px; padding: 0 18px; }
  /*  ЧЕТВЁРТАЯ СТУПЕНЬ, И ЖМЁМ ТЕПЕРЬ НЕ МЕНЮ, А ССЫЛКИ.
      7 сентября в шапку пришли сразу вкладка «Учебка» и три внешние ссылки
      справа. Замер на 1440 с длинной надписью о свежести данных: строке меню
      нужно 738 px при 677 доступных — не влезает 61. Резать пункты меню
      дальше некуда, а надпись «данным 1375 мин — сервер молчит» резать
      нельзя вовсе: это единственное место, где сайт признаётся, что данные
      несвежие. Значит жмётся то, что здесь младше всех — надписи ссылок,
      которые ведут наружу. */
  .hlinks a { padding: 0 7px; gap: 5px; font-size: 11.5px; }
  /*  И САМА СТРОКА ВКЛАДОК СТАНОВИТСЯ НА ПОЛПУНКТА МЕЛЬЧЕ. Одних полей и
      ссылок не хватило: замер после них дал те же 738 при 677. Восемь
      пунктов набраны прописными с просветом — при 11.5 px они читаются
      ровно так же, а строка теряет как раз недостающие шесть десятков
      пикселей. Жертвуем РАЗМЕРОМ, а не пунктом: пункт, обрезанный посреди
      слова, читается как поломка сайта, мелкий — как теснота. */
  .nav a, .nav .drop > button { font-size: 11.5px; }
}
/*  И ТРЕТЬЯ СТУПЕНЬ — ПОТОМУ ЧТО В МЕНЮ ПРИБАВИЛСЯ ПУНКТ.
    Приглашение в Discord встало девятым пунктом строки меню и отняло у неё
    около восьмидесяти пикселей. Замер после этого: на 1280 меню — 736 px при
    690 доступных, то есть «Discord» обрезался посреди слова и читался как
    «DIS». Видно это было на снимке страницы, а не в пробе: у пробы 06 в
    списке ширин 1280 не было вовсе — 1440 влезало, 1000 и уже проверяются
    как заведомо прокручиваемые. Дыра закрыта и в пробе тоже.

    Поджимаем те же поля дальше: девять пунктов по четыре пикселя с каждой
    стороны дают 36, поля верхней строки — ещё 8, просвет — 8. Пятьдесят два
    при нехватке в сорок шесть; замером на 1280 остаётся два пикселя запаса,
    и это не «на глаз»: шаг с просветом 10 давал ровно минус два. Порядок
    жертв прежний: сначала воздух, потом украшение, и никогда — сам пункт
    меню.  */
/* ----------------------------------------------------------------------------
   НИЖЕ 1250 ШАПКА СТАНОВИТСЯ ДВУХСТРОЧНОЙ — И ЭТО ДЕШЕВЛЕ ВСЕХ ОСТАЛЬНЫХ ЖЕРТВ.

   Замер после того, как в шапку пришли «Учебка» и три внешние ссылки: на 1100
   строке вкладок нужно 614 px, а свободных 610, и надпись о свежести данных к
   этому мигу ужата до 27 px — то есть не читается ни то, ни другое. Порог
   переноса до сих пор стоял на 1000, и весь промежуток 1000–1250 жил в этой
   тесноте.

   Что здесь важно: перенос — единственная жертва, которая НИЧЕГО не отнимает.
   Пункты меню остаются целыми, надпись о данных — целой, ссылки — на месте;
   платим высотой шапки, а её на ноутбуке хватает. Поэтому порог поднят до
   1250, а не «пусть прокручивается».
   ---------------------------------------------------------------------------- */
@media (max-width: 1250px) {
  .top { height: auto; padding: 10px 16px; flex-wrap: wrap; row-gap: 6px; }
  .nav { flex: 1 1 100%; max-width: 100%; }
  .live { flex: 1 1 100%; margin-left: 0; min-width: 0; }
  .live > span { max-width: 100%; }
}

@media (max-width: 1350px) {
  .nav a, .nav .drop > button { padding: 8px 4px; }
  .top { gap: 8px; padding: 0 14px; }
  /*  На 1280 после той же прибавки не хватало ещё 36 px. Отсюда просвет
      между ссылками уходит совсем, а межбуквенный — в ноль: надписи
      остаются читаемыми целиком, а это здесь важнее воздуха. */
  .hlinks { gap: 0; }
  .hlinks a { padding: 0 5px; gap: 4px; font-size: 11px; letter-spacing: 0; }
  .nav a, .nav .drop > button { font-size: 11px; letter-spacing: .02em; }
}

/* ============================================================================
   ПЕРВЫЙ ЭКРАН ПО SPACEX: полноэкранные кадры, текст слева внизу
   ========================================================================= */
/* =========================================================================
   ДРУЗЬЯ И ПАРТНЁРЫ — три круглых места под фотографии.

   КРУГ, А НЕ КАРТОЧКА. Логотип сообщества узнаётся по рисунку, а не по
   рамке; круглая маска — то, к чему глаз привык в Discord, и три круга в
   ряд не спорят с карточками ниже, у которых прямые углы.

   КНОПОК ПРАВКИ У КРУЖКОВ БОЛЬШЕ НЕТ (решение заказчика 6 сентября): имя,
   картинка и адрес партнёра меняются правкой разметки. Поэтому кружок —
   это `<span class="pimg">`, пока адреса нет, и `<a class="pimg">`, когда
   адрес вписан. Оформление у обоих одно, а приподнимается при наведении
   ТОЛЬКО ссылка: движение под курсором обещает переход, и обещать его
   там, где перехода нет, — обманывать.
   ========================================================================= */
.partners { display: grid; grid-template-columns: repeat(3, 1fr);
            gap: 26px; justify-items: center; margin-bottom: 8px; }
/*  ТРИ КОЛОНКИ ТРЕБУЮТ 820 px, А НЕ 700. Замер на планшете (768): кружки
    занимали 787 px при полосе 736 и выносили страницу на 828. Порог взят по
    замеру: 240 px карточка × 3 + просветы 52. */
@media (max-width: 820px) { .partners { grid-template-columns: 1fr; } }

.partner { text-align: center; position: relative; width: 100%;
           max-width: 240px; }
.partner .pimg {
  display: block; width: 148px; height: 148px; margin: 0 auto;
  border-radius: 50%; overflow: hidden;
  border: 1px solid var(--line2); background: var(--panel3);
  transition: border-color .15s, transform .15s;
}
.partner a.pimg:hover { border-color: var(--accent); transform: translateY(-2px); }
.partner img { width: 100%; height: 100%; object-fit: cover; display: block; }
.partner b { display: block; margin-top: 12px; font-size: 14.5px; font-weight: 600; }
.partner small { display: block; color: var(--muted); font-size: 12px; }

/* =========================================================================
   РЯД ПРОИЗВОДИТЕЛЕЙ ЖЕЛЕЗА — КВАДРАТНЫЕ ПЛИТКИ (заказ 6 сентября).

   ПОЧЕМУ КВАДРАТ, А НЕ КРУГ, КАК У ПАРТНЁРОВ. Два ряда рядом должны
   различаться с одного взгляда: круги — те, с кем сервер дружит, квадраты —
   железо, на котором летают. Одинаковые кружки читались бы как один список,
   и разница между «партнёр» и «производитель» пропала бы.

   ПЛИТКА ДЕРЖИТ КВАДРАТ САМА (`aspect-ratio`), а не подпоркой из отступов:
   картинка внутри может не приехать, и высота, набранная содержимым,
   схлопнулась бы — ряд поехал бы ступенькой.

   ЧУЖИЕ ЗНАКИ НЕ РИСУЮТСЯ. Пока файла логотипа нет, в плитке стоит ИМЯ
   НАБОРОМ — это честно и меняется одной строкой. Рисовать чужую эмблему по
   памяти нельзя: получится похожая, но не их, и это хуже пустого места.
   ========================================================================= */
/*  РЯД РАСКЛАДЫВАЕТСЯ ПОТОКОМ, А НЕ СЕТКОЙ — РАДИ ПОСЛЕДНЕЙ СТРОКИ.
    Решение заказчика 7 сентября: «лого по центру».

    Что было. Плиток пять, а колонок ниже 1000 px — три (ниже 620 — две).
    Пятёрка на тройку не делится: во второй строке оставались две плитки, и
    сетка прижимала их к ЛЕВОМУ краю — ряд выглядел оборванным. На двух
    колонках хуже: последняя плитка стояла одна слева.

    Поток с переносом кладёт неполную строку по середине сам. Ширины
    оставлены прежними — те же пять, три и две плитки в строке, — так что на
    широком экране ничего не сдвинулось: правило меняет только поведение
    ОБОРВАННОЙ строки, которой на широком экране не бывает. */
.makers { display: flex; flex-wrap: wrap; justify-content: center;
          gap: 18px; margin-bottom: 8px; }
.maker { flex: 0 0 calc((100% - 4 * 18px) / 5); }
@media (max-width: 1000px) { .maker { flex-basis: calc((100% - 2 * 18px) / 3); } }
@media (max-width: 620px)  { .maker { flex-basis: calc((100% - 18px) / 2); } }

.maker { text-align: center; }
.maker .mimg {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; width: 100%;
  border: 1px solid var(--line2); border-radius: var(--r-card);
  background: var(--panel3); overflow: hidden;
  transition: border-color .15s, transform .15s;
}
.maker a.mimg:hover { border-color: var(--accent); transform: translateY(-2px); }
.maker .mimg img { width: 100%; height: 100%; object-fit: contain; padding: 14%; }
/*  ПЛИТКА С КАДРОМ, А НЕ СО ЗНАКОМ. У знака вокруг обязаны быть поля — он
    рисован под белый лист и на всю плитку смотрится грубо. Фотография
    наоборот: с полями она висит маленьким прямоугольником посреди пустого
    квадрата. Пометка `photo` переключает одно на другое, разметка та же.  */
.maker .mimg.photo img { object-fit: cover; padding: 0; }
/*  ЗНАК-ПОЛОСА. Знаки бывают двух форм: близкой к квадрату (VIRPIL, VKB,
    Tobii) и вытянутой лентой — как присланный 11 сентября WINWING HOTAS
    ORION, у него 2.2:1. Общие поля в 14 % считаются от КВАДРАТА, и лента при
    них занимает 72 % ширины и треть высоты: рядом с соседями она читается
    вдвое мельче, хотя места вокруг полно. Поля по бокам убавлены, сверху и
    снизу оставлены — плитка не становится плотнее соседних.  */
.maker .mimg.wide img { padding: 10% 4%; }
/*  ИМЯ НАБОРОМ — ЗАГЛУШКА, А НЕ ЛОГОТИП. Поэтому оно нарочно спокойное:
    крупная надпись в рамке выглядела бы готовым знаком, и никто бы не
    прислал настоящий. */
.maker .mimg b { font-size: 15px; font-weight: 700; letter-spacing: .04em;
                 color: var(--ink2); padding: 0 8px; }
.maker small { display: block; margin-top: 8px; color: var(--muted);
               font-size: 11.5px; }

/* =========================================================================
   ОКНО ПОД КАРТИНКУ И РОЛИК В РУКОВОДСТВЕ.

   БЫЛО 21:9 И НЕ ВЫШЕ 320 px — узкая полоса. Придумана она была верно: окно
   стоит НАД заголовком раздела и не должно отодвигать текст с экрана. Но
   снимки из игры и ролики — 16:9, и в полосе 21:9 у них срезалось по краю
   сверху и снизу: на снимке заказчика от 7 сентября у кадра отрезало нижнюю
   треть вместе с надписью SARMAT.

   Стало 16:9 и до 520 px. Отношение сторон теперь СОВПАДАЕТ с тем, что в это
   окно кладут, — значит `cover` ничего не режет, а не «режет поменьше».
   Пропорции по-прежнему держит само окно, а не картинка: без этого блок до
   загрузки имеет нулевую высоту, и оглавление прыгает, когда снимок доезжает.
   ========================================================================= */
.gpic { position: relative; margin: 0 0 14px; border-radius: var(--r-card);
        overflow: hidden; border: 1px solid var(--line2);
        background: var(--panel3); aspect-ratio: 16 / 9; max-height: 520px; }
/*  ОКНА РАЗДЕЛОВ — С УВЕЛИЧЕНИЕМ 30% ПО УМОЛЧАНИЮ (заказ 7 сентября: «все
    блоки где фото и видео КРОМЕ ВЕРХНЕГО сделай с увеличением в 30%»).

    Верхний баннер (`.pagehero` в начале страницы) сюда не попадает нарочно:
    у него своё увеличение, общее с главной (`--vzoom`), и заказчик просил его
    не трогать. Здесь — только окна разделов.

    Число стоит В СТИЛЯХ, а не в коде страницы: кнопка «Увеличение» у каждого
    окна перебивает его своим, а «Как в стилях» возвращает сюда. Впиши я 1.3
    в скрипт — кнопка перестала бы что-либо значить для тех окон, где хозяин
    её не нажимал.  */
/*  РОЛИКУ И РАМКЕ УВЕЛИЧЕНИЕ СНЯТО, ФОТОГРАФИИ ОСТАВЛЕНО (заказ 9 сентября).

    Прежде одно правило накрывало обоих — и кадр-заставку, и ролик. Теперь
    их двое, и это НЕ разделение ради разделения: увеличение просили снять у
    видео, а 30% у окон разделов заказаны 7 сентября и никем не отменялись.

    ЧЕСТНАЯ ОГОВОРКА, КОТОРУЮ НАДО ЗНАТЬ ВЛАДЕЛЬЦУ: раз у фотографии 1.3, а
    у ролика 1, в миг подмены картинка заметно отскочит — она крупнее ролика
    на треть. Убрать отскок можно только одним из двух способов, и оба меняют
    вид: поставить 1 и фотографии (окна разделов станут мельче, чем просили
    7 сентября) либо вернуть 1.3 ролику. Решение за владельцем; пока стоит
    то, что меньше ломает уже заказанное.  */
.gpic img {
  transform-origin: 50% 50%; transform: scale(1.3); }
.gpic [data-bv] iframe, .gpic [data-bv] video {
  transform-origin: 50% 50%; transform: none; }
.gpic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gpic > .edit-bar { position: absolute; left: 12px; bottom: 12px; margin: 0;
                    background: rgba(0,0,0,.6); backdrop-filter: blur(2px); }
/*  Узкое правило снято: 16:9 теперь и есть основное отношение сторон.  */

.slides { background: #000; }
/* ----------------------------------------------------------------------
   ПЕРВЫЙ ЭКРАН: КОРОБ ПО СОРАЗМЕРНОСТИ САМОЙ КАРТИНКИ — И ТОГДА СВЕРХУ НЕ
   СРЕЗАЕТСЯ НИЧЕГО.

   ЗАКАЗЧИК 6 сентября: «баннер с видео на главной обрезан сверху — ЭТО НЕ
   ПРИЕМЛЕМО, откорректируй в нормальный размер». И он прав: срез сверху был
   не побочным следствием, а тем, что здесь было НАПИСАНО НАРОЧНО. Стояло
   три вещи разом, и каждая ела верх:
     • высота 80vh — короб мерялся ОТ ЭКРАНА, а не от картинки;
     • увеличение слоя на 30% от нижней кромки — лишнее уходило вверх;
     • `object-position: 50% 100%` у кадра и `bottom: 0` у рамки ролика.
   Вместе они срезали около четверти кадра сверху: небо, верх эмблемы.
   Отдельными правками это не лечится — снимаю все три и беру другую опору.

   ОПОРА ТЕПЕРЬ — САМА КАРТИНКА. Кадр 2592 × 1080, то есть 2.4 к 1; такое же
   соотношение получает и короб. Тогда «покрыть без полей» и «показать
   целиком» перестают спорить: картинка ложится точно, срезать нечего ни
   сверху, ни снизу. Высота считается от ШИРИНЫ окна (1440 → 600 px,
   1920 → 800), а не от его высоты, — баннер больше не занимает экран
   целиком и не прыгает от того, что у кого-то панель задач крупнее.

   `min-height: 400px` — только для телефона: при ширине 390 соразмерность
   дала бы полосу в 162 px, на которой не помещаются заголовок и кнопки.
   Там короб выше картинки, и обрезаются БОКА — те самые дорисованные края,
   ради которых кадр и расширяли.

   Текст и кнопки стоят у нижнего края (`align-items: flex-end`).
   ---------------------------------------------------------------------- */
.slide {
  /*  ШИРИНА ЗАДАНА ЯВНО, И ЭТО НЕ ЛИШНЯЯ СТРОКА. Замер на телефоне: с одной
      лишь соразмерностью и `min-height` короб выехал на 960 px при экране
      390 — упёршись в наименьшую высоту, браузер пересчитал по соразмерности
      уже ШИРИНУ, раз она не задана. Страница поехала вбок. `width: 100%`
      закрепляет ширину за окном, и соразмерность считает только высоту.  */
  position: relative; width: 100%; aspect-ratio: 2592 / 1080; min-height: 400px;
  /*  `stretch` ВМЕСТО `flex-end` — иначе «верх» прижимать не к чему.
      Заказ 9 сентября: надпись, заголовок и описание в ЛЕВЫЙ ВЕРХ, кнопки в
      ПРАВЫЙ НИЗ. Прежний `flex-end` прижимал ко дну ВЕСЬ короб с текстом
      целиком, и внутри него верха не существовало: короб был ровно по высоте
      текста. Растянув короб на всю высоту баннера, мы получаем и верх, и низ,
      а кто где — решает сетка ниже.  */
  display: flex; align-items: stretch;
  overflow: hidden; background: #000;
}
.slide-media { position: absolute; inset: 0; }
/* ----------------------------------------------------------------------
   УВЕЛИЧЕНИЯ СЛОЯ БОЛЬШЕ НЕТ.

   Здесь стояло `transform: scale(1.3)` от нижней кромки — «картинка крупнее
   на 30%». Оно и съедало верхнюю четверть кадра: слой становился выше
   короба, а прижат был к низу, значит лишнее уходило ВВЕРХ и обрезалось.
   Заказчик увидел это как «баннер обрезан сверху» — и это ровно оно.

   Заменять множитель на меньший смысла нет: любой множитель больше единицы
   при опоре на низ снова начнёт есть верх. Крупность кадра теперь задаётся
   соразмерностью короба, а она совпадает с соразмерностью картинки.
   ---------------------------------------------------------------------- */
/*  ПРАВИЛО ДЛЯ КАДРА-ЗАСТАВКИ, А НЕ ДЛЯ ЛЮБОЙ КАРТИНКИ В СЛОЕ.
    Метка `[data-bi]` здесь не украшение: в этом же слое лежит знак студии
    (`.vstamp img`), и без метки он получал «во всю ширину и высоту, cover» —
    то есть растягивался на весь баннер. На главной это было незаметно
    (правило знака стоит ниже и побеждало), а на внутренних страницах
    `.pagehero .slide-media img` весомее — и знак там раздувался во всю
    ширину. Заказчик увидел это как «на других страницах логотип другого
    масштаба». Метка адресует правило ровно тому, для кого оно написано.  */
.slide-media img[data-bi], .slide-media video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* ЗАТЕМНЕНИЕ СНИЗУ — иначе белый текст на светлом небе не читается.

   ОСЛАБЛЕНО У САМОГО НИЗА (6 сентября). Было .8 — почти чёрный; на экране
   заказчика нижняя шестая часть баннера выглядела не картинкой, а пустой
   тёмной полосой, и казалось, что между баннером и блоком «Сервер» зияет
   дыра. Дыры не было: там был кадр, закрашенный затемнением. Убавлено до
   .55 — заголовок по-прежнему читается (замер контраста в пробе 06), а
   нижняя кромка снова видна как часть картинки. */
.slide::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  /*  ДВА ЗАТЕМНЕНИЯ, А НЕ ОДНО. Сверху вниз — чтобы читалась шапка и нижняя
      строка; слева направо — под текстом. Второе понадобилось, как только
      кадр перестали резать: теперь под заголовком оказались обе машины,
      светлые, и белые буквы по ним читались хуже. Тень положена ТОЛЬКО
      слева, где текст, и сходит на нет к середине — правая половина кадра
      остаётся такой, какой её сняли.  */
  background:
    /*  Правая кромка притемнена тоже, и это не украшательство: ролик
        показывается целиком и занимает середину (74% ширины), а по краям
        остаётся кадр-заставка. Без притемнения края читались как «картинка
        не доехала»; с ним они работают рамкой вокруг ролика, а когда ролика
        нет — обычной мягкой виньеткой.  */
    linear-gradient(90deg, rgba(0,0,0,.62) 0%, rgba(0,0,0,.34) 34%,
                           rgba(0,0,0,0) 62%, rgba(0,0,0,0) 86%,
                           rgba(0,0,0,.45) 100%),
    linear-gradient(180deg, rgba(0,0,0,.45) 0%, rgba(0,0,0,0) 35%,
                            rgba(0,0,0,.12) 60%, rgba(0,0,0,.55) 100%);
}
/*  ОТСТУП ТЕКСТА ОТ НИЗА УБАВЛЕН 96 → 56 (6 сентября). Заказчик: «чтоб
    баннер был ровно между верхней строкой с кнопками и нижним блоком
    server». Отступ в 96 px поднимал заголовок к середине кадра, а под ним
    оставалась широкая пустая полоса — она и читалась как зазор. Теперь
    текст стоит у нижней кромки, и баннер занимает своё место целиком.  */
/*  ТЕКСТ СЛЕВА, КНОПКИ СПРАВА, НАПРОТИВ ЗАГОЛОВКА (решение заказчика
    6 сентября: «кнопки перенеси в правую часть экрана напротив надписи SARMAT,
    одну кнопку под другой»).

    РЯДАМИ СЕТКИ, А НЕ ОТДЕЛЬНЫМ КОРОБОМ. Проще всего было бы обернуть текст в
    новый `<div>` и поставить рядом второй — но кнопки на первом экране рисует
    склад блоков (`data-bl`), и он кладёт их РОВНО В ТОТ узел, который нашёл.
    Лишняя обёртка означала бы, что после первой же правки кнопок разметка
    станет другой, а правила — прежними. Сетка расставляет те же четыре узла,
    не трогая ни одного из них.

    Кнопки занимают строки заголовка и описания и прижаты к их верху: «напротив
    надписи SARMAT» — это одна высота с ней, а не середина текста.  */
.slide-in {
  position: relative; z-index: 2; width: 100%; padding: 0 0 56px 0;
}
/*  ДВЕ КОЛОНКИ — ТОЛЬКО У ПЕРВОГО ЭКРАНА ГЛАВНОЙ (`.slide`). Внутренние
    баннеры (`.pagehero`) носят такую же разметку `slide-in`, и общее правило
    утащило бы их кнопки вправо заодно — а заказчик просил перенести кнопки
    на главной. Правило, которое делает больше, чем просили, находят потом
    как «почему на той странице всё съехало».  */
.slide .slide-in {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 44px; align-items: end;
  /*  ЧЕТВЁРТЫЙ РЯД — ПУСТОЙ И РАСТЯЖИМЫЙ. В нём вся суть раскладки: три
      первых ряда (надпись, заголовок, описание) занимают столько, сколько им
      нужно, а `1fr` съедает весь остаток высоты. Текст оказывается вверху не
      потому, что его туда прижали, а потому что ниже него стоит распорка.
      Кнопки живут в этом же четвёртом ряду и прижаты к его низу — отсюда
      правый нижний угол.  */
  grid-template-rows: auto auto auto 1fr; align-content: start;
  /*  Отступ задан ЗДЕСЬ, а не в общем `.slide-in` выше: тот делится с
      внутренними баннерами (`.pagehero`), и правка там сдвинула бы текст на
      восьми страницах заодно.  */
  padding: 56px 0;
}
.slide .slide-kick { grid-column: 1; grid-row: 1; }
.slide .slide-h    { grid-column: 1; grid-row: 2; }
.slide .slide-p    { grid-column: 1; grid-row: 3; }
.slide .slide-in [data-bl] {
  /*  Четвёртый ряд, прижаты к его низу — правый нижний угол баннера.
      Прежде кнопки стояли во втором-третьем ряду и равнялись по верху
      заголовка; «везде в правый нижний угол» тогда сделали внутренним
      страницам правилом на `.pagehero`, а главная осталась со старой
      раскладкой — её первый экран носит другой класс.  */
  grid-column: 2; grid-row: 4; align-self: end;
  /*  Одна под другой и одной ширины: `stretch` равняет их по самой длинной
      подписи, иначе кнопки разной длины выглядят случайными.  */
  flex-direction: column; align-items: stretch; gap: 12px;
  min-width: 260px;
}
.slide .slide-in [data-bl] .btn-line { justify-content: center; }
/*  НА УЗКОМ ЭКРАНЕ — ОБРАТНО В ОДИН СТОЛБЕЦ. Две колонки на телефоне
    оставили бы заголовку около половины ширины, и «SARMAT» переносился бы
    по буквам.  */
@media (max-width: 900px) {
  /*  РЯДЫ ТОЖЕ ВОЗВРАЩАЕМ ОБЫЧНЫЕ. Растяжимый четвёртый ряд нужен только
      двухколоночной раскладке: в один столбец он раздвинул бы пустоту между
      описанием и кнопками во всю оставшуюся высоту баннера.  */
  .slide .slide-in { grid-template-columns: minmax(0, 1fr);
                     grid-template-rows: auto; }
  .slide .slide-kick, .slide .slide-h, .slide .slide-p { grid-column: 1; }
  .slide .slide-in [data-bl] { grid-column: 1; grid-row: auto;
                               align-self: start;
                               flex-direction: row; align-items: center;
                               min-width: 0; }
}
/*  `display: flex` ЗДЕСЬ — ЗВЕНО ЦЕПОЧКИ ВЫСОТЫ, а не украшение. Высота
    тянется сверху вниз: `.slide` растянул `.wrap`, но `.wrap` без `flex`
    не растянет `.slide-in`, и сетка снова окажется по высоте текста —
    ровно с той же бедой, что и до правки выше. Порвись это звено, и
    «верх» тихо перестанет отличаться от «низа».  */
.slide .wrap { width: 100%; position: relative; z-index: 2; display: flex; }
.slide-kick {
  font-size: 12px; letter-spacing: .22em; text-transform: uppercase;
  color: #fff; opacity: .95; margin-bottom: 14px; font-weight: 600;
}
.slide-h {
  font-size: clamp(30px, 4.6vw, 54px); line-height: 1.02; font-weight: 700;
  letter-spacing: -.01em; text-transform: uppercase; margin-bottom: 16px;
  max-width: 620px;
}
.slide-p { font-size: 15.5px; color: #e6e9ee; max-width: 480px; margin: 0 0 24px; }

/* кнопка SpaceX: тонкая рамка, прописные, стрелка */
.btn-line {
  display: inline-flex; align-items: center; gap: 12px;
  border: 1px solid rgba(255,255,255,.85); color: #fff;
  padding: 12px 22px; font-size: 12px; letter-spacing: .2em;
  text-transform: uppercase; font-weight: 600; background: rgba(0,0,0,.15);
  transition: background .18s, color .18s;
}
.btn-line:hover { background: var(--btn-bg); color: var(--btn-ink);
                  text-decoration: none; }

/* стрелка «листайте ниже» */
/*  СТРЕЛКА «ПРОКРУТИ НИЖЕ» УБРАНА С ГЛАВНОЙ (6 сентября). Она звала вниз,
    пока баннер занимал весь экран и под ним ничего не было видно. Теперь
    баннер соразмерен картинке, и блок «Сервер» виден сразу — звать некуда.
    К тому же стрелка встала ровно поверх подписи студии в кадре. Правило
    оставлено на случай, если стрелка понадобится на другой странице.  */
.scroll-hint {
  position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%);
  z-index: 3; color: rgba(255,255,255,.7); font-size: 22px; line-height: 1;
  animation: bob 2.2s ease-in-out infinite;
}
@keyframes bob { 0%,100% { transform: translate(-50%, 0); } 50% { transform: translate(-50%, 7px); } }

/* ============================================================================
   ЗАГОЛОВОК РАЗДЕЛА (seclabel у образца)
   ========================================================================= */
.seclabel {
  display: flex; align-items: center; gap: 14px; margin: 42px 0 14px;
  font-size: 11.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
.seclabel::before {
  content: ''; width: 0; height: 0; flex: none;
  border-left: 6px solid var(--accent);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
}
.seclabel.g::before { border-left-color: var(--green); }
.seclabel.r::before { border-left-color: var(--red); }
.seclabel .rest { flex: 1 1 auto; height: 1px; background: var(--seam); }

/*  БАННЕР СТОИТ ВПЛОТНУЮ К БЛОКУ «СЕРВЕР» (заказ 6 сентября: «чтоб баннер
    был ровно между верхней строкой с кнопками и нижним блоком server»).
    У полос разделов общий отступ сверху 42 px — он верен в середине
    страницы, где полоса отделяет один раздел от другого. Сразу под баннером
    отделять нечего: выше него ничего нет, кроме самого баннера, и эти 42 px
    выглядели зазором между шапкой сайта и первой строкой данных. Правило
    касается ТОЛЬКО первой полосы сразу за баннером — остальные не трогаем,
    иначе страница слипнется.  */
.slides + main > .seclabel:first-child { margin-top: 18px; }

/* шапка страницы (крошки + заголовок) */
.crumbs {
  padding-top: 26px; font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--muted2);
}
.crumbs .sep { margin: 0 8px; }
.pagetitle {
  font-size: clamp(28px, 4vw, 46px); font-weight: 700; letter-spacing: -.01em;
  margin: 10px 0 26px;
}
.pagetitle .accent { color: var(--accent); }

/* ============================================================================
   КАРТОЧКИ
   ========================================================================= */
.panel {
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-card); padding: 18px 20px;
}
.panel h3 {
  font-size: 11.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 12px; font-weight: 600;
}
.card {
  background: var(--panel3); border: 1px solid var(--line);
  border-radius: var(--r-row); padding: 16px 18px;
}
.card h3 { font-size: 15px; margin-bottom: 6px; text-transform: none;
           letter-spacing: 0; color: var(--ink); }
.card p { margin: 0; color: var(--ink3); font-size: 14px; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
         gap: 14px; }

/* карточка сервера — два в ряд, как у образца */
.servers { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.srv {
  display: block; background: var(--panel); border: 1px solid var(--brd-blue);
  border-radius: var(--r-card); padding: 18px 20px; color: var(--ink);
}
.srv:hover { text-decoration: none; border-color: var(--accent); }
.srv.v-red { border-color: var(--brd-red); }
.srv.soon { grid-column: 1 / -1; border: 1px dashed var(--line);
            opacity: .75; padding: 14px 20px; }
.srv .tagline { font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
                color: var(--muted); }
.srv .name { font-size: 25px; font-weight: 700; margin: 6px 0 2px; }
.srv .era { font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
            color: var(--accent); }
.srv .full { color: var(--ink3); font-size: 13.5px; margin: 10px 0 14px; }

/* ============================================================================
   МЕТАЛЛИЧЕСКИЕ ПОДРОБНОСТИ.

   Правила ОБЩИЕ для обеих схем, а вид задают переменные: в «Ночной» они
   пустые (`none` / `transparent`), и она остаётся ровно такой, какой была.
   В «Су-57» они дают блик по панели, светлую кромку сверху и тёплую медную
   черту под шапкой — то, что заказчик назвал «металлическими деталями».

   ПОЧЕМУ ОТДЕЛЬНЫМ РАЗДЕЛОМ, А НЕ ПРЯМО В КАРТОЧКАХ. У карточек фон записан
   сокращённо (`background: var(--panel)`), а сокращённая запись СБРАСЫВАЕТ
   картинку фона. Допиши я блик туда же — он исчезал бы при любой правке
   цвета. Здесь он стоит после и отдельным свойством.
   ========================================================================= */
.panel, .card, .srv, .drow, .sidevid.big, .maker .mimg, .partner .pimg {
  background-image: var(--sheen);
}
/*  Кромка — там, где у металла было бы ребро: сверху панели. Внутренняя
    тень в один пиксель, а не рамка: рамка съела бы место и поспорила с
    настоящей границей карточки.  */
.panel, .srv, .maker .mimg, .partner .pimg { box-shadow: inset 0 1px 0 var(--edge); }
/*  Медная черта под шапкой. У «Ночной» она прозрачная — шапка та же.  */
.top { box-shadow: inset 0 -1px 0 var(--rule); }
/*  Подсветка строки под курсором взята на переменную: раньше здесь стоял
    сине-серый номер, и во второй схеме строка под курсором синела посреди
    бирюзы.  */
.drow:hover { background-color: var(--hover); }

/* строка-ссылка 368×72 */
.dest { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.drow {
  display: flex; align-items: center; gap: 14px; min-height: 72px;
  padding: 15px 16px; border: 1px solid var(--line);
  border-radius: var(--r-row); background: var(--panel3); color: var(--ink);
}
.drow:hover { text-decoration: none; border-color: var(--line2); }
/* ----------------------------------------------------------------------
   ЗНАКИ РАЗДЕЛОВ — КРУПНЕЕ И ЗЕЛЁНЫЕ (заказ 11 сентября: «сюда какие-нибудь
   логотипы побольше и больше зелёного цвета»).

   ПОЧЕМУ ЭМОДЗИ УБРАНЫ, А НЕ ПОКРАШЕНЫ. Их рисует шрифт системы: цвет у них
   свой, и ни свойством, ни фильтром его не задать — а на чужой машине это ещё
   и другие картинки. Вместо них свои очертания линиями: красятся
   `currentColor`, растут без размытия и одинаковы у всех.

   ПЛАШКА БЫЛА СИНЕЙ (#1d2634), А У ТРЁХ СТРОК КРАСНОЙ (#2a1d1d) — две чужие
   палитре краски, оставшиеся от прежней схемы. Теперь обе зелёные из общей
   палитры: обычная строка тише, отмеченная (`.r`) заметнее. Чередование
   сохранено, цвет один.
   ---------------------------------------------------------------------- */
.drow .ico {
  width: 52px; height: 52px; flex: none; border-radius: 12px;
  display: grid; place-items: center;
  color: var(--green);
  background: rgba(95, 211, 173, .10);
  border: 1px solid rgba(95, 211, 173, .22);
}
.drow .ico svg {
  width: 28px; height: 28px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.drow.r .ico {
  color: var(--accent);
  background: rgba(71, 200, 194, .16);
  border-color: rgba(71, 200, 194, .34);
}
.drow b { display: block; font-size: 14.5px; font-weight: 600; }
.drow small { display: block; color: var(--muted); font-size: 12.5px; }

/* ---------- поля «ключ: значение» ---------- */
.kv { display: flex; justify-content: space-between; gap: 12px;
      padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.kv:last-child { border-bottom: 0; }
.kv span { color: var(--muted); }
.kv b { font-weight: 600; }

/* ---------- цифры ---------- */
.figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
        gap: 12px; }
.fig { background: var(--panel3); border: 1px solid var(--line);
       border-radius: var(--r-row); padding: 14px 16px; }
.fig b { display: block; font-size: 27px; font-weight: 700; letter-spacing: -.02em; }
.fig b.long { font-size: 20px; }
.fig i { display: block; font-style: normal; font-size: 11px; letter-spacing: .16em;
         text-transform: uppercase; color: var(--muted); margin-top: 5px; }
.fig.red b { color: var(--side-red); }
.fig.blue b { color: var(--side-blue); }
.fig.gold b { color: var(--gold); }

/* ---------- метки ---------- */
.pill { display: inline-block; padding: 3px 9px; border-radius: 999px;
        border: 1px solid var(--line2); font-size: 11px; letter-spacing: .1em;
        text-transform: uppercase; color: var(--muted); }
.pill.red { color: var(--side-red); border-color: #4a2b2b; }
.pill.blue { color: var(--side-blue); border-color: #27405e; }
.pill.gold { color: var(--gold); border-color: #4a3f24; }
.pill.brand { color: var(--green); border-color: #2d5a3b; }

.side-red { color: var(--side-red); }
.side-blue { color: var(--side-blue); }

/* ---------- кнопки ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  border: 1px solid var(--line2); background: #17231b; color: var(--ink);
  padding: 9px 15px; border-radius: 9px; font: 500 13.5px/1 inherit;
  font-family: inherit;
}
.btn:hover { border-color: var(--accent); text-decoration: none; }
.btn.solid { background: var(--accent); border-color: var(--accent); color: #05130a;
             font-weight: 600; }
/*  Светлее акцента — это `--green` у обеих схем, а не жёстко `#86efac`
    (зелёный «Фосфора»): в сине-серой он давал зелёную вспышку под мышью.  */
.btn.solid:hover { background: var(--green); }
.btn.ghost { background: none; }
.btn.ghost:hover { background: #17231b; }
.btn.sm { padding: 6px 11px; font-size: 12.5px; }
.btn:disabled { opacity: .45; cursor: default; }

/* ---------- поля ввода ---------- */
input, select, textarea {
  background: var(--sunk); border: 1px solid var(--line2); color: var(--ink);
  border-radius: 8px; padding: 9px 11px; font: 14px/1.4 inherit; font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--accent); }
label { display: block; font-size: 11px; letter-spacing: .16em;
        text-transform: uppercase; color: var(--muted); margin-bottom: 5px; }
textarea { min-height: 96px; resize: vertical; }

/* ---------- таблицы ---------- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
thead th {
  text-align: left; font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted); font-weight: 600; padding: 9px 10px;
  border-bottom: 1px solid var(--line2); white-space: nowrap;
}
/* Линия строки и подсветка под мышью были жёсткими `#1c2028` и `#141922` —
   остаток снятой сине-серой палитры: в зелёной схеме таблицы статистики
   расчерчивались синим по зелёному. Берём цвета схемы. */
tbody td { padding: 10px; border-bottom: 1px solid var(--line); }
tbody tr:hover td { background: var(--panel2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------------------
   ЗАГОЛОВОК-КНОПКА СОРТИРОВКИ (страница «Что можно заказать»).

   ЭТО КНОПКА, А НЕ ЩЕЛЧОК ПО ЯЧЕЙКЕ, И НАРОЧНО. По кнопке можно дойти
   табуляцией и нажать с клавиатуры; щелчок, повешенный на `th`, для того,
   кто не пользуется мышью, не существует вовсе.

   ВЫГЛЯДИТ ОНА КАК ПРЕЖНИЙ ЗАГОЛОВОК: те же размер, разрядка и цвет —
   иначе шапка таблицы разъехалась бы на «обычные» и «нажимаемые», и
   пришлось бы объяснять разницу, которой нет. Стрелка появляется только
   у того столбца, по которому сейчас сортируют.
   ---------------------------------------------------------------------- */
button.thsort {
  all: unset; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  white-space: nowrap;
}
th.num button.thsort { flex-direction: row-reverse; }
button.thsort:hover { color: var(--fg); }
button.thsort:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
button.thsort.on { color: var(--fg); }
button.thsort.on::after {
  content: '\2191'; font-size: 11px; line-height: 1; opacity: .8;
}
button.thsort.on[aria-sort="descending"]::after { content: '\2193'; }

/* Таблица, набранная разметкой в тексте (строки на «|»). Обёртка со своей
   прокруткой обязательна: без неё четыре столбца на телефоне растягивают
   страницу вбок, и вбок едет ВСЯ вёрстка, а не таблица. */
.gtwrap { overflow-x: auto; margin: 16px 0; max-width: 74ch;
          border: 1px solid var(--line); border-radius: 10px;
          background: var(--bg-2); }
.gtable { min-width: 380px; }
.gtable thead th { padding: 10px 14px; }
.gtable tbody td { padding: 10px 14px; color: var(--ink-2); vertical-align: top; }
.gtable tbody tr:last-child td { border-bottom: 0; }
/* Первый столбец — это ЧТО, остальные — СКОЛЬКО. Разный цвет отделяет
   подпись строки от числа быстрее, чем любая линейка. */
.gtable tbody td:first-child { color: var(--ink); }

/* ---------- полоса владения ---------- */
.bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden;
       background: #1b1f27; }
.bar i { display: block; height: 100%; }
.bar .r { background: var(--side-red); }
.bar .n { background: #3a4150; }
.bar .b { background: var(--side-blue); }

/* ---------- лента событий ---------- */
.feed { max-height: 460px; overflow-y: auto; }
.feed div { display: flex; align-items: baseline; gap: 10px; padding: 8px 0;
            border-bottom: 1px solid #1c2028; font-size: 13.5px; }
.feed time { color: var(--muted2); font-size: 12px; font-variant-numeric: tabular-nums; }
.feed .k { width: 7px; height: 7px; border-radius: 50%; background: #3a4150;
           flex: none; display: inline-block; }
.feed .k.red { background: var(--side-red); }
.feed .k.blue { background: var(--side-blue); }

.note { color: var(--muted); font-size: 13px; }
.eyebrow { font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
           color: var(--muted); }
.kicker { font-size: 12px; letter-spacing: .18em; text-transform: uppercase;
          color: var(--accent); }
.lede { font-size: 16px; color: var(--ink3); max-width: 760px; }
.h1 { font-size: clamp(28px, 4vw, 44px); font-weight: 700; }
.h2 { font-size: 22px; font-weight: 600; }
.sec-head { display: flex; align-items: baseline; justify-content: space-between;
            gap: 16px; margin-bottom: 12px; }
section { margin-bottom: 34px; }
/*  У ПЕРВОГО ЭКРАНА ЭТОГО ОТСТУПА НЕТ. Он тоже `section`, и общие 34 px
    доставались и ему — а под баннером отделять нечего: ниже сразу первая
    строка данных. Заказчик увидел это как «баннер должен стоять ровно между
    строкой с кнопками и блоком server» и был прав: сверху зазор был нулевой,
    снизу — 34 px, и баннер висел несимметрично. Отступ снят у баннера, а не
    у всех разделов: остальным он нужен.  */
.slide { margin-bottom: 0; }

/* «нет данных» — отдельный вид, чтобы пустоту нельзя было принять за ноль */
.nodata {
  border: 1px dashed var(--line2); border-radius: var(--r-row);
  padding: 18px; color: var(--muted); font-size: 13.5px; text-align: center;
}

/* ============================================================================
   ВРЕМЕННЫЕ КНОПКИ ПРАВКИ БЛОКА
   Видны, пока сайт наполняется. Гасятся одной строкой в blocks.js.
   ========================================================================= */
.edit-bar {
  display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
  margin: 8px 0 0; padding: 6px;
  border: 1px dashed var(--line2); border-radius: 9px;
  background: var(--panel3);
}
.edit-bar button {
  background: var(--panel2); border: 1px solid var(--line2); color: var(--accent);
  border-radius: 7px; padding: 5px 10px; cursor: pointer;
  font: 500 11.5px/1.2 inherit; font-family: inherit;
}
.edit-bar button:hover { background: var(--panel); color: var(--ink); }
.edit-bar .tag { color: var(--ink3); font-size: 11px; padding: 6px 4px;
                 letter-spacing: .08em; text-transform: uppercase; }
/* На полноэкранном кадре кнопки правки кладутся поверх картинки: слайд —
   это flex-строка, и кнопки, поставленные в поток, уезжали за правый край
   вместе с полосой содержимого шириной 100%. */
.edit-bar.on-dark { border-color: rgba(255,255,255,.35);
                    background: rgba(0,0,0,.55); backdrop-filter: blur(2px); }
.slide > .edit-bar { position: absolute; top: 18px; right: 22px; z-index: 5;
                     margin: 0; max-width: min(560px, calc(100% - 44px)); }

.modal-back {
  position: fixed; inset: 0; background: rgba(4,10,6,.72); z-index: 200;
  display: grid; place-items: center; padding: 20px;
}
.modal {
  width: min(680px, 100%); max-height: 86vh; overflow: auto;
  background: var(--panel); border: 1px solid var(--line2);
  border-radius: var(--r-card); padding: 20px 22px;
}
.modal h3 { font-size: 16px; margin-bottom: 4px; }
.modal .sub { color: var(--muted); font-size: 12.5px; margin-bottom: 16px; }

/* ============================================================================
   ПОДВАЛ — четыре колонки, как у образца
   ========================================================================= */
footer.site-footer {
  border-top: 1px solid var(--line); margin-top: 50px;
  padding: 40px 0 28px; background: var(--bg2);
}
.foot-grid {
  display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.3fr; gap: 30px;
}
.foot-brand { display: flex; align-items: flex-start; gap: 12px; }
.foot-brand img { height: 46px; width: auto; }
.foot-brand .studio { color: var(--muted); font-size: 12px; letter-spacing: .12em;
                      text-transform: uppercase; margin-top: 4px; }
footer h4 {
  margin: 0 0 12px; font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
footer a { color: var(--ink3); font-size: 13.5px; display: block; padding: 3px 0; }
footer a:hover { color: var(--ink); }
.foot-conn div { margin-bottom: 9px; }
.foot-conn i { display: block; font-style: normal; font-size: 10.5px;
               letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.foot-conn b { font-weight: 500; font-size: 13px; }
/* Строка Discord — ссылка, а не адрес для набора руками. Размер и вес те же,
   что у соседних строк: разный вид у соседей читался бы как «это что-то
   другое», хотя это тот же способ связи. */
.foot-conn a { display: inline-block; font-size: 13px; font-weight: 500;
               color: var(--accent); }
.foot-legal {
  margin-top: 26px; padding-top: 16px; border-top: 1px solid var(--line);
  color: var(--muted2); font-size: 12px; display: flex; gap: 14px; flex-wrap: wrap;
}

/* ============================================================================
   КАРТА
   ========================================================================= */
/* Карта занимает весь экран под шапкой: она главная страница сайта, и
   ужимать её в полосу содержимого нельзя — тогда на 1180 точках карта
   получается меньше боковой панели. */
.maplay { display: grid; grid-template-columns: 1fr 372px;
          min-height: calc(100vh - 66px); }
#map { width: 100%; height: 100%; min-height: 62vh; background: #0a0c10;
       position: relative; }
#map * { user-select: none; }
.side { border-left: 1px solid var(--line); background: var(--bg);
        overflow-y: auto; max-height: calc(100vh - 66px); padding: 14px; }
.side .panel { margin-bottom: 14px; }
@media (max-width: 1000px) {
  .side { border-left: 0; border-top: 1px solid var(--line); max-height: none; }
}
/* ============================================================================
   ГРАФИКИ ХОДА КАМПАНИИ: окно времени, подписи линий, строка чтения.
   Заказ 7 сентября — «этот блок нужно доработать».
   ============================================================================ */
.range { display: flex; gap: 2px; margin: 0 0 -4px auto; width: max-content; }
.range button {
  background: none; border: 1px solid var(--line2); border-radius: 8px;
  color: var(--muted); cursor: pointer; font: 600 11px/1 inherit;
  letter-spacing: .08em; text-transform: uppercase; padding: 7px 11px;
  font-family: inherit;
}
.range button:hover { color: var(--ink2); border-color: var(--accent); }
.range button.on { background: var(--panel2); color: var(--ink); }

.chartbox { padding-top: 10px; }
/*  Шапка графика прижата к его верхнему краю и НЕ переносится под него:
    строка чтения меняется под мышью, и если бы она прыгала на вторую
    строку при длинном тексте, график ездил бы вверх-вниз под курсором.  */
.chead { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px;
         min-height: 18px; }
.legend { display: flex; gap: 12px; flex: none; }
.legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px;
            margin-right: 6px; vertical-align: baseline; }
.legend { font-size: 11.5px; color: var(--ink3); letter-spacing: .04em;
          text-transform: uppercase; }
.readout { margin-left: auto; font-size: 12px; color: var(--ink2);
           font-variant-numeric: tabular-nums; text-align: right;
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chart { cursor: crosshair; }

/* ============================================================================
   ОБЪЕКТЫ ПО СЕКТОРАМ — ПОЛОСА ПОД КАРТОЙ.
   Решение заказчика 7 сентября по образцу чужого сервера, «по нашим данным».

   ЧЕТЫРЕ КОЛОНКИ, А НЕ СЕТКА ПО ЧИСЛУ СЕКТОРОВ. Секторов в кампании четыре, и
   так было все сборки, — но число задано `auto-fit`, а не четвёркой: станет их
   пять (а такое уже было: сектор 5 снимали в v11.9), и полоса разложится сама,
   вместо того чтобы молча обрезать пятый.

   ВЫСОТУ СПИСКА ОГРАНИЧИВАЕМ И ПРОКРУЧИВАЕМ ВНУТРИ КОЛОНКИ. В третьем секторе
   аэродромов и ФАРПов двадцать два: без предела одна колонка вытягивала бы
   полосу вдвое и оставляла соседние три пустыми до самого низа.
   ============================================================================ */
.objwrap { padding-top: 18px; padding-bottom: 24px; }
.objgrid { display: grid; gap: 1px; background: var(--line);
           grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
           border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.objsec { background: var(--bg2); padding: 14px 14px 10px; min-width: 0; }
.objsec h4 { margin: 0 0 10px; font-size: 12px; font-weight: 700;
             letter-spacing: .12em; text-transform: uppercase; color: var(--ink2); }
/*  Полоса владения — та же тройка цветов, что у полосы на главной: красный,
    ничейный, синий. Второй набор цветов сторон не заводим ни при каких
    условиях: цвет стороны — это язык карты.  */
.obar { display: flex; height: 4px; border-radius: 3px; overflow: hidden;
        background: var(--panel2); margin-bottom: 10px; }
.obar i { display: block; height: 100%; }
.obar .b { background: var(--blue); }
.obar .r { background: var(--red); }
.obar .n { background: var(--line2); }
/*  ЧЕТЫРЕ ЧИСЛА В ДВА РЯДА, А НЕ В ОДИН. В один ряд подпись «спорные»
    (по-английски «contested») не влезала в колонку шириной 230 и обрезалась
    многоточием до «CONTES…» — замер на снимке. Подпись, которую нельзя
    прочесть, не подпись; два ряда дают каждой вдвое больше места и не стоят
    почти ничего по высоте.  */
.onums { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 10px;
         margin-bottom: 10px; }
.onums div { min-width: 0; }
.onums i { display: block; font-style: normal; font-size: 9.5px; color: var(--muted);
           letter-spacing: .08em; text-transform: uppercase;
           white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.onums b { font-size: 15px; font-weight: 700; }
.onums small { color: var(--muted); font-size: 10.5px; margin-left: 3px; }
.ocnt { border-top: 1px solid var(--line); padding-top: 8px; margin-bottom: 8px; }
.okv { display: flex; align-items: baseline; gap: 6px; font-size: 11.5px;
       color: var(--ink3); padding: 2px 0; }
.okv span { flex: 1 1 auto; min-width: 0; overflow: hidden;
            text-overflow: ellipsis; white-space: nowrap; }
.okv b { color: var(--ink2); }
.okv i { font-style: normal; color: var(--muted); font-size: 10.5px; }
.olist { border-top: 1px solid var(--line); padding-top: 8px;
         max-height: 340px; overflow-y: auto; }
.okind { font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
         color: var(--muted); margin: 8px 0 4px; }
.okind:first-child { margin-top: 0; }
.okind b { color: var(--ink3); font-weight: 700; }
.orow { display: flex; align-items: center; gap: 7px; padding: 3px 6px 3px 2px;
        border-radius: 6px; color: var(--ink2); font-size: 12.5px; cursor: pointer; }
.orow span { min-width: 0; overflow: hidden; text-overflow: ellipsis;
             white-space: nowrap; }
.orow:hover { background: var(--panel); color: var(--ink); text-decoration: none; }
.odot { width: 7px; height: 7px; border-radius: 50%; flex: none;
        background: var(--line2); }
.odot.red { background: var(--red); }
.odot.blue { background: var(--blue); }

.icmap-zoom button {
  width: 30px; height: 30px; background: rgba(20,23,29,.9); color: var(--ink);
  border: 1px solid var(--line2); border-radius: 8px; cursor: pointer;
  font: 16px/1 inherit; font-family: inherit;
}
.icmap-layers select { background: rgba(20,23,29,.92); color: var(--ink);
  border: 1px solid var(--line2); border-radius: 8px; padding: 7px 10px;
  font-size: 12px; }
.icmap-layers select:hover { border-color: var(--accent); }
.icmap-tip { background: rgba(13,16,21,.96); border: 1px solid var(--line2);
  border-radius: 9px; padding: 9px 11px; font-size: 12.5px; color: var(--ink2); }

.tip {
  position: fixed; z-index: 300; pointer-events: none; opacity: 0;
  background: rgba(13,16,21,.97); border: 1px solid var(--line2);
  border-radius: 9px; padding: 9px 11px; font-size: 12.5px; max-width: 320px;
  transition: opacity .12s;
}

/* ---------- узкий экран ---------- */
@media (max-width: 1000px) {
  .servers, .dest, .maplay, .foot-grid { grid-template-columns: 1fr; }
  .top { height: auto; padding: 10px 16px; flex-wrap: wrap; }
  /* ------------------------------------------------------------------------
     ПОЛОСА СВЯЗИ НЕ ТОЛКАЕТ СТРАНИЦУ ВБОК.
     Замер на телефоне (390 px): ширина документа 406 — страница уезжала вбок
     пальцем на КАЖДОЙ странице, и ровно на левое поле шапки. Виновата эта
     полоса: у неё языки, ползунок схемы и надпись «данным 48 минут» в одну
     строку, а у элемента в раскладке по умолчанию `min-width: auto` — сжаться
     ниже своего содержимого он не может.
     Разрешаем ей сжиматься и переносить своё содержимое на вторую строку.
     Надпись о свежести данных НЕ РЕЖЕМ многоточием: это единственное место,
     где сайт признаётся, что данные несвежие, и обрезать её значит спрятать
     именно то, ради чего она есть.
     ------------------------------------------------------------------------ */
  .live { min-width: 0; flex: 1 1 100%; flex-wrap: wrap; row-gap: 4px;
          white-space: normal; margin-left: 0; }
  .live > span { max-width: 100%; }
  .nav { overflow-x: auto; max-width: 100%; }
  .nav::-webkit-scrollbar { height: 0; }
  .live { margin-left: 0; }
  .slide-in { padding-bottom: 64px; }
}
@media (max-width: 640px) {
  .wrap { padding: 0 16px; }
  .dest { grid-template-columns: 1fr; }
}

/* ---------- ЗНАК СТУДИИ ПОВЕРХ РОЛИКА ----------
   Щит, которым закрывается отметка YouTube (круг с полосками). Живёт в том же
   гнезде, что и рамка, и лежит поверх неё.

   ЩЁЛЧКИ ЕГО НЕ ЗАМЕЧАЮТ (`pointer-events: none`) — иначе он забрал бы себе
   нажатия, а под ним у баннера кнопки «Открыть живую карту» и «Как играть».

   ТЁМНОЕ ПЯТНО ПОД ЗНАКОМ не для красоты: логотип светлый, а кадр ролика
   бывает любым, и на светлом небе знак пропал бы ровно тогда, когда он
   нужен. Пятно круглое и сходит на нет — краёв не видно.

   БЫСТРО ПОЯВЛЯЕТСЯ, МЕДЛЕННО УХОДИТ. Появление .18 с: он обязан успеть
   закрыть отметку, а она рисуется мгновенно. Уход .55 с: медленное
   растворение читается как заставка студии, быстрое — как мигание. */
.vstamp {
  position: absolute; inset: 0; z-index: 4;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; transition: opacity .55s ease;
  /*  Два слоя подложки. Круглое пятно — под сам знак, чтобы он не пропал на
      светлом кадре; ровная плёнка поверх всего кадра — чтобы за эти две
      секунды не спорили друг с другом знак студии и заголовок страницы:
      кадр приглушён, оба читаются. Плёнка слабая (.2), кадр из-под неё
      виден и продолжает играть.  */
  background: radial-gradient(closest-side, rgba(0,0,0,.55), rgba(0,0,0,0) 78%),
              rgba(0,0,0,.2);
}
.vstamp.on { opacity: 1; transition: opacity .18s ease; }
/*  РАЗМЕР ЗНАКА — ОДНА ДОЛЯ ОТ ШИРИНЫ БАННЕРА, БЕЗ ПОТОЛКА В ПИКСЕЛЯХ.

    ЗАКАЗЧИК 6 сентября, со снимка внутренней страницы: «сделай масштабы
    логотипа и видеозаписи как на home». И он прав: доля стояла 30%, но
    сверху лежал потолок в 300 px — и потолок УПИРАЛСЯ первым. Знак выходил
    ровно 300 px на любом баннере, а баннеры разной ширины: на главной
    (1366 px) это 22% ширины, на внутренней (1132) — уже 27%. Одно и то же
    число давало РАЗНЫЙ масштаб; на узком баннере знак выглядел больше.

    Поэтому потолок снят, а доля взята та, что получалась на главной и была
    принята заказчиком, — 22%. Теперь знак занимает одну и ту же часть кадра
    на всех страницах и растёт вместе с окном.

    Потолок по высоте (72%) оставлен: он сторожит короб, который однажды
    окажется очень широким и низким, — там знак иначе вылез бы за края. */
.vstamp img {
  width: 22%; max-height: 72%;
  object-fit: contain;
  filter: drop-shadow(0 2px 18px rgba(0,0,0,.55));
}
/*  В маленькой карточке сбоку доля другая: 30% там — это 114 px, надпись
    студии под самолётом уже не читается. */
.sidevid .vstamp img { width: 62%; }

/* ---------- ролик первого экрана ----------
   ЗАКАЗЧИК 6 сентября, глядя на свой экран: «нужно вернуть нормальный не
   обрезанный формат и центрировать». На снимке было видно, во что превращался
   ролик: короб баннера шире 16:9, ролик растягивался по ширине, чтобы закрыть
   его без полей, и от кадра оставалась середина — крупным планом бомба во
   весь экран. Плюс прежнее увеличение на 30% от нижней кромки. Считалось это
   «покрытием», выглядело — увеличительным стеклом.

   ЧТО ТЕПЕРЬ. Ролик показывается ЦЕЛИКОМ и по середине: 16:9 как есть,
   ничего не срезано. Свободные места по краям НЕ ЧЁРНЫЕ — под роликом лежит
   кадр-заставка, тот самый баннер SARMAT, и он виден по бокам. Это и есть
   разница с «полосами», которые заказчик отверг раньше: полосы — пустота,
   здесь — картинка.

   ТРИ ПРАВИЛА, И ГРАНИЦЫ МЕЖДУ НИМИ НЕ СЛУЧАЙНЫ. Короб баннера 2.4:1, но не
   ниже 400 px — значит до ширины 960 px он ВЫШЕ своей соразмерности, а
   дальше ровно по ней. Ролик обязан влезть в короб ЦЕЛИКОМ, а упирается он
   то в высоту, то в ширину:
     • шире 960: короб 2.4:1, ролик упирается в высоту — 100% высоты и
       74.08% ширины короба (это те же 16:9: 100 / 2.4 × 16 / 9);
     • от 711 до 960: короб ровно 400 px в высоту, ролик снова упирается в
       высоту, но она уже не зависит от ширины окна — числа постоянные,
       711 × 400;
     • уже 711: ролик упирается в ширину окна — 100vw × 56.25vw.
   На обеих границах соседние правила дают одно и то же (960 × 400 → 711 × 400
   и 711 × 400 → 711 × 400), поэтому на переходе ничего не дёргается.

   ЗДЕСЬ Я УЖЕ ОШИБСЯ ОДИН РАЗ, И ОШИБКУ НАШЛА ПРОБА. Было два правила с
   границей на 960: между 711 и 960 ролик считался «по ширине окна» и
   получался выше короба (800 × 450 при коробе 800 × 400) — то есть снова
   обрезанным, ровно тем, что заказчик и запретил. Проба 06 меряет рамку
   заглушкой и это поймала.  */
.slide-media [data-bv] { position: absolute; inset: 0; overflow: hidden; }
.slide-media [data-bv] video {
  /* ----------------------------------------------------------------------
     РОЛИК ЗАПОЛНЯЕТ КОРОБ, А НЕ ВПИСЫВАЕТСЯ В НЕГО (заказ 9 сентября: «на
     server guide баннер работает идеально, сделай так же на главной»).

     ЗАМЕР, КОТОРЫЙ ВСЁ ОБЪЯСНИЛ. Короба у двух баннеров разные, а ролик один:

         главная      1440 x 600   соразмерность 2.40
         руководство  1132 x 637   соразмерность 1.78
         ролик        1920 x 1080  соразмерность 1.78

     У руководства короб совпадает с роликом — при `contain` он ложится ровно,
     и потому «работает идеально». У главной короб шире (её баннер намеренно
     широкий, 2592/1080, и под него снят отдельный широкий кадр): вписанный
     ролик занимал 1067 px из 1440, и по бокам оставалось по 186 px ЧЕРНОТЫ.
     Разница была не в работе ролика, а в геометрии — потому и не бросалась
     в глаза как поломка.

     ПОЧЕМУ `cover`, А НЕ ДРУГАЯ СОРАЗМЕРНОСТЬ КОРОБА. Ширину главного баннера
     заказчик выбирал отдельно и под неё готовил кадр 2.4:1; менять её ради
     ролика — переделывать его решение. `cover` срезает у ролика верх и низ
     поровну (около четверти высоты) и заполняет короб целиком.

     И ЭТО ЖЕ УБИРАЕТ РЫВОК ПРИ ПОДМЕНЕ. Кадр-заставка показывается через
     `cover` (правило выше), а ролик показывался через `contain`: в миг
     передачи эстафеты картинка заметно «отскакивала». Теперь оба заполняют
     короб одинаково.

     Прежний довод за `contain` — «чтобы свой файл и YouTube выглядели
     одинаково» — с 9 сентября недействителен: роликов YouTube на сайте не
     осталось ни одного, а у рамки YouTube своя разметка ниже.
     ---------------------------------------------------------------------- */
  width: 100%; height: 100%; object-fit: cover;
}
.slide-media [data-bv] iframe {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  /*  КРУПНЕЕ НА 44% ОТ ВПИСАННОГО (два захода 6 сентября: «видео увеличь на
      20%», затем «все видео ещё на 20%» — то есть 1.2 × 1.2 = 1.44).
      Числа домножены в КАЖДОЙ паре, а не приписан `scale`: множитель поверх
      готовых размеров пришлось бы держать в голове при следующей правке, а
      пары выше и так посчитаны и объяснены.
        было 100% × 74.08%  ->  ×1.2  ->  120% × 88.90%
                             ->  ×1.44 -> 144% × 106.68%
      Соотношение 16:9 при этом сохраняется — обе стороны растут одинаково,
      значит чёрных полос YouTube по-прежнему не будет.

      ЧТО ПРИ ЭТОМ ОБРЕЗАЕТСЯ. Ролик стал выше короба почти в полтора раза, и лишнее
      уходит ПОРОВНУ вверх и вниз: рамка стоит по центру. Это не тот срез, от
      которого мы уходили: тогда верх исчезал целиком, потому что рамка была
      прижата к низу.  */
  height: calc(100% * var(--vzoom)); width: calc(74.08% * var(--vzoom));
  border: 0; pointer-events: none;          /* щелчки уходят странице, а не YouTube */
}
@media (max-width: 959px) {
  .slide-media [data-bv] iframe { width: calc(711.12px * var(--vzoom));
                                  height: calc(400px * var(--vzoom)); }
}
@media (max-width: 711px) {
  .slide-media [data-bv] iframe { width: calc(100vw * var(--vzoom));
                                  height: calc(56.25vw * var(--vzoom)); }
}

.slide-media img { transition: opacity .4s; }

/* ============================================================================
   БЛОКИ СТРАНИЦЫ КАРТЫ — раскладка снята с образца:
   левая колонка со сведениями и составом, карта во всю оставшуюся ширину,
   под ней «общее положение» и лента, ещё ниже — секторы карточками.
   ========================================================================= */
/*  ТРИ КОЛОНКИ: панель — карта — панель (решение заказчика 7 сентября:
    «делаем ещё одну вертикальную панель, туда переносим функционал
    управления своими юнитами»).

    ПОЧЕМУ ИМЕННО ТРЕТЬЯ КОЛОНКА, А НЕ ЕЩЁ ОДИН БЛОК СЛЕВА. Слева лежит то,
    что ЧИТАЮТ: обстановка, слои, сведения о кампании. Справа теперь то, чем
    ДЕЙСТВУЮТ: свои группы, заказ, команда. Разные руки — разные стороны, и
    карта между ними не сжимается второй раз.

    ШИРИНА ТА ЖЕ, 372 px: панели одинаковые не для красоты, а чтобы карта
    оставалась по центру экрана — иначе взгляд всё время сползает.  */
.maplay { grid-template-columns: 372px 1fr 372px; }
.side { border-left: 0; border-right: 1px solid var(--line); }
.side.right { border-right: 0; border-left: 1px solid var(--line); }
/*  Кнопка «Панель» прячет ОБЕ панели: она про «дайте карту во весь экран», а
    не про левую колонку. */
@media (max-width: 1360px) {
  /*  До 1360 три колонки не помещаются: карте остаётся меньше её же панелей.
      Правая уходит ПОД карту целой колонкой — там она читается как продолжение
      страницы, а не как обрезок. */
  .maplay { grid-template-columns: 372px 1fr; }
  .side.right { grid-column: 1 / -1; border-left: 0;
                border-top: 1px solid var(--line); max-height: none; }
}
@media (max-width: 1000px) {
  .maplay { grid-template-columns: 1fr; }
  .side { border-right: 0; border-bottom: 1px solid var(--line); }
  .side.right { border-top: 0; }
}

.infogrid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px;
            margin-bottom: 14px; }
.infogrid i { display: block; font-style: normal; font-size: 10px;
              letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.infogrid b { font-size: 15px; font-weight: 600; }

.plrow { display: flex; justify-content: space-between; gap: 10px; align-items: baseline;
         padding: 5px 0; border-bottom: 1px solid #1c2028; font-size: 13.5px; }
.plrow i { font-style: normal; color: var(--muted); font-size: 12px; }
.plgrp { margin-bottom: 12px; }
.plhead { font-size: 10.5px; letter-spacing: .18em; margin-bottom: 4px; font-weight: 600; }

.twocol { display: grid; grid-template-columns: 4fr 6fr; gap: 18px; }
@media (max-width: 900px) { .twocol { grid-template-columns: 1fr; } }

.sectors { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
           gap: 14px; }
.seccard { background: var(--panel); border: 1px solid var(--line2);
           border-radius: var(--r-card); padding: 16px 18px; }
.sechead { font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
           color: var(--muted); margin-bottom: 10px; font-weight: 600; }
.secbar { display: flex; height: 6px; border-radius: 3px; overflow: hidden;
          background: #1b1f27; margin-bottom: 12px; }
.secbar i { display: block; height: 100%; }
.secbar .r { background: var(--side-red); }
.secbar .b { background: var(--side-blue); }
.secnums { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
           margin-bottom: 8px; }
.secnums i { display: block; font-style: normal; font-size: 10px; letter-spacing: .14em;
             text-transform: uppercase; color: var(--muted); }
.secnums b { font-size: 20px; font-weight: 700; }
.secnums small { display: block; color: var(--muted2); font-size: 11px; }

/* ============================================================================
   МАЛЫЙ ВЕРТИКАЛЬНЫЙ РОЛИК У ПРАВОГО КРАЯ.
   Стоит на страницах сводки, хода кампании, заказов и руководства. Липнет к
   правому краю окна с отступом и едет вместе со страницей.

   ПОЧЕМУ ОН ПРЯЧЕТСЯ НА УЗКОМ ЭКРАНЕ, А НЕ ПОДЖИМАЕТСЯ. Полоса содержимого
   1180 плюс карточка 190 плюс отступы — это 1440. На меньшем экране карточка
   легла бы поверх таблиц, и цифры кампании оказались бы под роликом. Прятать
   украшение честнее, чем закрывать им данные.
   ========================================================================= */
.sidevid {
  float: right; width: 190px; aspect-ratio: 9 / 16;
  margin: 0 0 18px 24px;                 /* отступ от текста — те самые «три пробела» */
  position: relative; border: 1px solid var(--line2); border-radius: var(--r-card);
  overflow: hidden; background: #000;
}
.sidevid [data-bv] { position: absolute; inset: 0; overflow: hidden; }
.sidevid img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sidevid video { width: 100%; height: 100%; object-fit: cover; }
.sidevid iframe {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: calc(190px * var(--vzoom)); height: calc(107px * var(--vzoom));
  min-width: calc(601px * var(--vzoom));       /* 16:9 от ширины карточки */
  min-height: calc(338px * var(--vzoom));      /* и 16:9 от её высоты */
  border: 0; pointer-events: none;
}
/* РАЗБОР: здесь стояли единицы контейнера (cqw/cqh) — и вышло ХУЖЕ, чем
   было. Задумка была «пусть рамка считает покрытие от самой карточки»;
   на деле высотная часть не посчиталась, `max()` взял ширинную, и рамка
   встала ровно по карточке. Рамка YouTube не умеет object-fit: получив
   не-16:9 короб, она сама вписывает в него ролик и дорисовывает ЧЁРНЫЕ
   ПОЛОСЫ. Их-то заказчик и увидел вместо кадра во всю карточку.
   Возвращены точные числа выше: карточка фиксированной ширины, и считать
   тут нечего.

   С 6 сентября к этим числам применяется общий множитель `--vzoom`: заказчик
   попросил правило увеличения, действующее на ВСЕ ролики YouTube. У карточки
   ролик и так закрывал её целиком, поэтому увеличение здесь означает не
   «больше видно», а «крупнее середина»: срезается больше по краям, поровну со
   всех сторон. Это осознанная плата за единое правило — иначе на сайте снова
   было бы два разных масштаба. */
/* =========================================================================
   КРУПНАЯ КАРТОЧКА (`.sidevid.big`) — решение заказчика по странице заказов:
   «сделай в 4 раза больше видео в этом вкладке».
   ВЧЕТВЕРО — ЭТО ПО ПЛОЩАДИ, то есть вдвое по каждой стороне: 190 → 380.
   Вчетверо по ширине дало бы 760 px из 1132 px полосы, и таблице цен
   осталось бы 348 px на три колонки — страница про цены перестала бы
   показывать цены. Площадь при этом растёт ровно в четыре раза, а это и
   есть то, что видит глаз.
   Числа рамки пересчитаны от новой ширины по той же арифметике, что и у
   малой карточки, и по той же причине: рамка YouTube не умеет object-fit,
   и не-16:9 короб она сама заполнит ЧЁРНЫМИ ПОЛОСАМИ.
     ширина 380 → 16:9 по ширине  = 380 × 214
     высота 380×16/9 = 675.6 → 16:9 по высоте = 1201 × 676
   ========================================================================= */
/*  ЕЩЁ НА 30% (решение заказчика, 4 сентября): 380 → 494 по ширине.
    Считаем от ШИРИНЫ, а не от площади: «в четыре раза» было сказано про
    площадь и так и посчитано, а «на 30%» — обычная прибавка к размеру
    карточки. Числа рамки пересчитаны по той же арифметике и по той же
    причине, что и выше: не-16:9 короб YouTube сам заполнит чёрными
    полосами, и заказчик увидит их вместо кадра.
      ширина 494 → 16:9 по ширине = 494 × 278
      высота 494×16/9 = 878 → 16:9 по высоте = 1562 × 879
    Полоса содержимого 1132: таблице остаётся 494 меньше — 614 против 728.
    Три колонки цен в них помещаются; проба 03 сторожит, что таблица
    осталась читаемой, а не уехала под карточку. */
/*  СУЖЕНО ОБРАТНО ДО 380 (решение заказчика 6 сентября: «сузить окно видео
    и добавить такое же ниже»). Ширину взял не новую, а ту, что страница уже
    носила: для неё арифметика рамки посчитана и объяснена выше, и брать
    произвольное число значило бы считать заново то, что уже посчитано.
    Карточек теперь ДВЕ, одна под другой, — вместе они занимают по высоте
    вдвое больше, и лишние 114 px ширины забрала бы таблица цен. */
/*  ОКНО СТАЛО КВАДРАТНЫМ (решение заказчика 6 сентября: «должны быть
    квадратные окна с видео»). Общее правило `.sidevid` держит 9:16 —
    вертикальную полосу, — поэтому соотношение переписываем здесь, у своего
    класса, а не правим общее: малые ролики на других страницах остаются
    вертикальными.
    Числа рамки пересчитаны по той же арифметике и по той же причине, что и
    выше: рамка YouTube не умеет object-fit, и не-16:9 короб она сама
    заполнит ЧЁРНЫМИ ПОЛОСАМИ.
      сторона 380 → 16:9 по ширине = 380 × 214
      высота  380 → 16:9 по высоте = 676 × 380
    Берётся большее из двух (min-width / min-height), то есть 676 × 380:
    ролик покрывает квадрат целиком, лишнее уходит за края. */
.sidevid.big { width: 380px; aspect-ratio: 1 / 1; }
.sidevid.big iframe {
  width: calc(380px * var(--vzoom)); height: calc(214px * var(--vzoom));
  min-width: calc(676px * var(--vzoom)); min-height: calc(380px * var(--vzoom));
}

/*  ВТОРАЯ КАРТОЧКА ВСТАЁТ ПОД ПЕРВОЙ, А НЕ РЯДОМ.
    Обе прижаты вправо `float: right`, а плавающие блоки становятся в РЯД,
    пока есть место по горизонтали: две по 380 в полосе 1132 сели бы бок о
    бок, и «ниже» не получилось бы. `clear: right` заставляет вторую начаться
    ниже первой. Отдельным классом, а не правилом для «второй в родителе»:
    порядок карточек на странице может измениться, а смысл «эта — под
    предыдущей» останется. */
.sidevid.below { clear: right; }

/*  КРУПНАЯ КАРТОЧКА НА ТЕЛЕФОНЕ. Общее правило узкого экрана делает `.sidevid`
    шириной во всю полосу, но `.sidevid.big` весомее (два класса против одного)
    и стоит ниже — на 390 px карточка оставалась 494 px и выносила страницу на
    510. Поэтому сброс стоит ЗДЕСЬ, сразу за объявлением, а не в общем блоке
    узкого экрана выше: правило, проигрывающее по весу, выглядит написанным и
    ничего не делает. */
@media (max-width: 1000px) {
  /*  Квадрат остаётся квадратом и на узком, но во всю полосу он занял бы
      целый экран (на планшете 952 × 952) — поэтому ширина ограничена и окно
      стоит посередине.
      РАМКУ СЧИТАЕМ ДОЛЯМИ ОТ ОКНА, А НЕ ПИКСЕЛЯМИ: сторона здесь зависит от
      экрана, и точного числа для неё нет. 16:9, покрывающие квадрат, — это
      177.78% ширины на 100% высоты. Это ОБЫЧНЫЕ ПРОЦЕНТЫ от родителя, а не
      единицы контейнера (cqw/cqh), на которых этот же расчёт однажды уже
      сорвался: те не посчитались вовсе, и рамка встала по коробу с чёрными
      полосами. Проценты от позиционированного родителя считаются всегда.
      Прежние min-width/min-height в пикселях здесь надо СНЯТЬ: иначе на
      телефоне рамка осталась бы 676 px шириной при окне 358. */
  .sidevid.big { float: none; width: 100%; max-width: 420px;
                 aspect-ratio: 1 / 1; margin: 0 auto 18px; }
  .sidevid.big iframe { min-width: 0; min-height: 0;
                        width: calc(177.78% * var(--vzoom));
                        height: calc(100% * var(--vzoom)); }
  .tight { margin-right: 0; }
}

/* «Таблицу сожми на 30 пробелов». Пробел на этой странице — 8 px (тем же
   счётом отмерян отступ карточки: «те самые три пробела» = 24 px), значит
   ужать надо на 240 px. Сто девяносто из них таблица отдаёт сама, когда
   карточка выросла со 190 до 380; оставшиеся 50 — этот отступ.
   Отступ висит СПРАВА и только на таблицах: заголовки и текст держат левый
   край страницы, иначе ужимание читалось бы как случайно съехавший блок. */
.tight { margin-right: 50px; }
@media (max-width: 820px) { .tight { margin-right: 0; } }

.sidevid .edit-bar {
  position: absolute; left: 6px; right: 6px; bottom: 6px; margin: 0;
  flex-direction: column; align-items: stretch;
  background: rgba(0,0,0,.62); border-color: rgba(255,255,255,.28);
}
.sidevid .edit-bar .tag { display: none; }
.sidevid .edit-bar button { padding: 4px 6px; font-size: 10.5px; }
/* На узком экране карточка уходит из обтекания и встаёт над содержимым:
   таблицы кампании важнее украшения и ужиматься под него не должны. */
@media (max-width: 820px) {
  .sidevid { float: none; width: 100%; aspect-ratio: 16 / 9; margin: 0 0 18px; }
  /*  ЗАМЕР ПОЙМАЛ МОЮ ОШИБКУ: здесь я поставил 177.78% ширины — долю для
      КВАДРАТНОГО короба. Но на телефоне малая карточка не квадрат, а 16:9
      (общее правило выше), и рамка выходила 911 × 287 при соотношении 3.17
      вместо 1.78 — то есть YouTube дорисовал бы чёрные полосы сверху и
      снизу. У короба 16:9 покрытие даёт сам короб: обе стороны по 100%,
      умноженные на общий множитель.  */
  .sidevid iframe { min-width: 0; min-height: 0;
                    width: calc(100% * var(--vzoom));
                    height: calc(100% * var(--vzoom)); }
}

/* Тот же первый экран, что на главной, но внутри страницы: заголовок,
   описание, кнопки и ролик под ними. */
.pagehero { position: relative; min-height: 62vh; display: flex;
            align-items: flex-end; overflow: hidden; background: #000;
            border-radius: var(--r-card); margin-bottom: 30px; }
.pagehero .slide-media { position: absolute; inset: 0; }
.pagehero .slide-media img[data-bi] { width: 100%; height: 100%; object-fit: cover; }

/* ---------------------------------------------------------------------------
   КАДР-ЗАСТАВКА МЕЛЬЧЕ НА 30% — решение заказчика 6 сентября: «картинку перед
   видео в каждом блоке уменьши на 30%».

   ТРОГАЕМ ТОЛЬКО КАРТИНКУ, НЕ РОЛИК. Ролику увеличение на 30% заказчик задал
   отдельно и раньше, и оно остаётся: `.slide > .slide-media` на главной и
   `scale(1.3)` у рамки во внутренних баннерах. Поэтому правило висит на
   `img[data-bi]`, а не на слое `.slide-media`, который несёт обоих.

   ВМЕСТЕ С УМЕНЬШЕНИЕМ — `contain` ВМЕСТО `cover`, и это не своевольство.
   При `cover` картинка обрезается рамкой, и уменьшение показало бы ТУ ЖЕ
   обрезанную середину, только мельче: подпись студии внизу как не помещалась,
   так и не помещалась бы. С `contain` в рамку входит весь кадр целиком —
   именно этого уменьшение и добивается.

   ПОРЯДОК ВАЖЕН: правило стоит ПОСЛЕ `.pagehero .slide-media img`. Вес у них
   одинаковый, и решает порядок; поставь мы его выше — на внутренних баннерах
   оно молча ничего бы не делало.
   --------------------------------------------------------------------------- */
/*  КАДР ПО СЕРЕДИНЕ, А НЕ ПРИЖАТ К НИЗУ (6 сентября, вместе с отменой среза
    сверху).

    Прижатие `50% 100%` жило здесь с решения «отрезать сверху 20%»: оно
    оставляло на месте нижнюю кромку и выбрасывало верх. Теперь короб
    соразмерен картинке, и на главной обрезать нечего — правило работает
    только там, где короб ВЫШЕ картинки (телефон) или НИЖЕ (внутренний
    баннер руководства, он 16:9). В обоих случаях середина честнее края:
    у прижатого к низу кадра на телефоне пропало бы небо, а во внутреннем
    баннере — верх машины.

    Оставляем `cover`: `contain` уже пробовали, и заказчик отверг —
    уменьшенная картинка висела островом в тёмных полях («выглядит плохо»).  */
.slide-media img[data-bi] {
  object-position: 50% 50%;
}
/* ---------------------------------------------------------------------------
   ВНУТРЕННИЙ БАННЕР: КОРОБ САМ 16:9, И ТОГДА СЧИТАТЬ НЕЧЕГО.

   ЧТО БЫЛО И ПОЧЕМУ ЭТО НЕ РАБОТАЛО. Сперва рамка мерялась по ЭКРАНУ (100vw
   и не меньше 100vh) — в блоке высотой 62vh она выходила вдвое больше окна,
   и зритель видел сильно приближенную середину кадра. Потом я попробовал
   единицы контейнера — и получил чёрные полосы сверху и снизу: рамка встала
   ровно по коробу, а короб был не 16:9, и YouTube вписал ролик внутрь сам.

   ЧТО ТЕПЕРЬ И ПОЧЕМУ ЭТО ПРОЩЕ. Короб получает соотношение 16:9 —
   ровно то, в котором приходит ролик. Тогда рамка «во всю ширину и во всю
   высоту» подходит без остатка: ни полос, ни расчётов, ни зависимости от
   поддержки новых единиц. Высота блока перестаёт зависеть от высоты окна и
   зависит от ширины страницы — для баннера это и правильнее.

   ЗУМ — ТОТ ЖЕ, ЧТО НА ГЛАВНОЙ (6 сентября: «масштабы логотипа и видеозаписи
   как на home»). Было 1.3 от прежнего решения «сделай зум видео на 30%»,
   стало 1.44 — ровно столько же, на сколько увеличен ролик первого экрана
   после двух прибавок по 20%.
   Два разных множителя на двух баннерах — это две правды об одном и том же:
   человек, переходя со страницы на страницу, видит, что кадр «дышит», и не
   может понять почему.

   Кадр увеличивается ОТ ЦЕНТРА, лишнее срезает `overflow: hidden` самого
   блока, — значит уходит поровну со всех сторон. Приближение касается только
   ролика: фотография-заставка и так берётся по `cover`.
   ------------------------------------------------------------------------- */
.pagehero { aspect-ratio: 16 / 9; min-height: 0; }
.pagehero .slide-media [data-bv] iframe {
  position: absolute; top: 50%; left: 50%;
  width: 100%; height: 100%;
  min-width: 0; min-height: 0;
  transform: translate(-50%, -50%) scale(var(--vzoom));
  transform-origin: center center;
}
.pagehero::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,.35) 0%, rgba(0,0,0,0) 40%,
                                      rgba(0,0,0,.8) 100%);
}
.pagehero .slide-in { position: relative; z-index: 2; width: 100%;
                      padding: 0 28px 28px; }

/* ---------------------------------------------------------------------------
   НАДПИСЬ И КНОПКА БАННЕРА — В ПРАВОМ НИЖНЕМ УГЛУ (заказ 9 сентября).

   ПОЧЕМУ ПРАВИЛО ОДНО И БЕЗ СПИСКА СТРАНИЦ. Заказчик: «на всех страницах,
   кроме главной». Класс `.pagehero` носят ровно восемь внутренних страниц, а
   первый экран главной устроен своим классом `.slide` — то есть «все, кроме
   главной» уже описано самим классом. Перечисли мы страницы поимённо, девятая
   завтра приехала бы со старой раскладкой, и никто бы не понял почему.

   ПРИЖАТО ВНИЗ УЖЕ САМИМ БАННЕРОМ (`align-items: flex-end` выше), поэтому
   здесь только «вправо»: колонка отжимается `margin-left: auto`, текст
   равняется по правому краю — вместе с кнопкой, она в потоке строки.

   ШИРИНА ОГРАНИЧЕНА. Без ограничения колонка осталась бы во всю ширину
   баннера, и «в углу» оказалась бы только кнопка, а строки описания тянулись
   бы от левого края — то есть заказ выполнен наполовину и выглядит небрежно.

   НА ТЕЛЕФОНЕ УГОЛ НЕ ДЕЛАЕМ. Ширина там 390 px: колонка в углу превратилась
   бы в узкий столбец по два слова в строке, а описание, равненное по правому
   краю, читается заметно хуже. Ниже 760 px остаётся прежняя раскладка —
   это осознанная оговорка, а не забытый случай.
   --------------------------------------------------------------------------- */
@media (min-width: 760px) {
  .pagehero .slide-in { width: auto; max-width: 560px;
                        margin-left: auto; text-align: right; }
  /*  КНОПКУ РАВНЯЕТ НЕ `text-align`, А `justify-content`, и это разбор
      9 сентября: заказчик прислал снимок, где надпись стоит справа, а
      кнопка «LIVE MAP» осталась слева под ней.

      ПОЧЕМУ ТАК ВЫШЛО. Ряд кнопок носит класс `.row`, а он `display: flex`.
      Выравнивание строки (`text-align`) распоряжается ТЕКСТОМ внутри
      строчных элементов и на детей флексбокса не действует вовсе: их
      расставляет `justify-content`. Правило «поставить в правый нижний
      угол» я написал одним `text-align` и на кнопку посмотрел мельком —
      она и осталась у левого края колонки.  */
  .pagehero .slide-in [data-bl] { justify-content: flex-end; }
}
.pagehero > .edit-bar { position: absolute; top: 14px; right: 16px; z-index: 5;
                        margin: 0; }
