/* ==========================================================================
   Небольшие дополнения, которых нет в вёрстке 2026 года.

   Всё, что здесь описано, появилось уже на WordPress: богатая страница
   проекта (награды, авторы, новости о проекте), пометка архива и сам архив.
   Файл темы — в цепочку «прототипы -> шаблоны UMI» он не входит и на UMI не
   нужен.

   Цвета берутся только из существующих переменных: своей палитры здесь нет и
   быть не должно, иначе тёмная тема разъедется.
   ========================================================================== */

/* ==========================================================================
   САМЫЙ БЛЕДНЫЙ СЕРЫЙ БЫЛ СЛИШКОМ БЛЕДНЫМ

   Измерено 25.08.2026 прямо на живых страницах, обе темы:

       светлая  #8b8f9a на белом  — 3,23 : 1
       тёмная   #676b76 на #171a21 — 3,27 : 1

   Норма для обычного текста — 4,5 : 1 (WCAG AA). Этим цветом набраны не
   украшения, а содержание: дата новости, номер карточки, «+1» в списке тегов,
   заголовок мобильного меню. То есть человек с обычным зрением на телефоне на
   солнце дату просто не прочтёт.

   Правим здесь, а не в общем файле: общий приезжает из шаблонов UMI и
   перезаписывается синхронизацией. Новые значения подобраны так, чтобы остаться
   тем же серым, только на два тона темнее/светлее:

       светлая  #676a72 — 5,41 на белом, 4,58 на подложке
       тёмная   #7d828f — 4,53 на карточке, 5,02 на фоне страницы

   Порядок объявлений повторяет общий файл: сначала светлая в :root, потом
   тёмная — и в медиазапросе, и по явному переключателю. Цвет, объявленный
   только внутри медиазапроса, ломает светлую тему.
   ========================================================================== */
:root { --ink-faint: #676a72; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --ink-faint: #7d828f; }
}
:root[data-theme="dark"] { --ink-faint: #7d828f; }

/* ==========================================================================
   ИСПРАВЛЕНИЯ РАСКЛАДКИ
   ========================================================================== */

/* Серая полоса между заставкой и слайдером.

   Это коллизия имён в общих стилях: `.home-hero` описан и в home.css (сам
   слайдер), и в pages.css — там он значит другое и добавляет
   padding-top: clamp(44px, 8vw, 104px). На широком экране это сто пикселей
   фона страницы между белой заставкой и полноэкранным кадром.

   Правим здесь, а не в общем файле: он общий с UMI, а UMI договорились не
   трогать. */
main.home > .home-hero {
  padding-top: 0;
  padding-bottom: 0;
}

/* Пропорции слайдера на широких мониторах.

   Было `height: min(82vh, 780px)`: на мониторе 2560×1440 это полоса 2560×780,
   то есть 3,3:1 — архитектура в такой щели не читается. Потолок в пикселях
   убираем и оставляем долю экрана: кадр остаётся высоким на любой ширине, а на
   ноутбуке ничего не меняется, потому что там ограничение всё равно по высоте
   окна. */
@media (min-width: 1200px) {
  .home-hero-stage { height: min(88vh, 62vw); }
}

/* Воздух над хлебными крошками — ОДИН на все типы страниц.

   У `.cat-hero` он свой: clamp(36px, 7vw, 76px). Первый заход дал «статейным»
   страницам другое значение, и начало страниц стало скакать по высоте при
   переходе между разделом и новостью. Значение должно быть буквально то же
   самое, поэтому оно вынесено в переменную и используется обоими правилами. */
:root { --abtb-page-top: clamp(36px, 7vw, 76px); }

main.article-page > .container:first-child,
main.article-page > .article-head:first-child,
main.home-page > .container:first-child {
  padding-top: var(--abtb-page-top);
}

/* И сам `.cat-hero` приводим к той же переменной: так значение остаётся одно,
   даже если однажды его захочется поменять. */
main .cat-hero { padding-top: var(--abtb-page-top); }

/* Подвал, отклеивающийся от низа.

   На короткой странице (пустой поиск, страница без текста) содержимого не
   хватает на высоту экрана, и подвал повисает посередине. Обычная колонка на
   всю высоту окна ставит его на место, а на длинных страницах ничего не
   меняет. */
body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body > main { flex: 1 0 auto; }
body > .site-footer { flex: none; }

/* Карта на «Контактах» показывается сразу, поэтому заглушке-кнопке здесь
   делать нечего, а самому виджету нужна нормальная высота. */
.contacts-map .map-embed { min-height: clamp(320px, 42vw, 520px); }
.contacts-map .map-embed iframe {
  width: 100%;
  height: 100%;
  min-height: clamp(320px, 42vw, 520px);
  border: 0;
  display: block;
  border-radius: 16px;
}

/* Пометка «из архива» — спокойная строка, а не предупреждение: проект не
   ошибка, он просто из другого времени. То же самое у новости, поэтому
   селектор общий: заводить вторую копию тех же восьми строк незачем. */
.project-archived,
.article-archived {
  margin: 14px 0 0;
  font-size: 14px;
  color: var(--ink-soft);
}
.project-archived::before,
.article-archived::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--line);
  vertical-align: middle;
}

/* Награды — список, а не абзац: их читают глазами по одной. */
.project-awards {
  margin-top: clamp(24px, 3vw, 36px);
  max-width: 720px;
}
.project-awards h2 {
  margin: 0 0 10px;
  font-size: clamp(17px, 1.8vw, 20px);
}
.project-awards ul {
  margin: 0;
  padding-left: 20px;
  color: var(--ink-soft);
}
.project-awards li {
  margin-bottom: 6px;
  line-height: 1.55;
}

/* Авторы и новости о проекте: те же карточки, что на главной, только с
   отбивкой сверху — секции идут подряд и без неё слипаются. */
.project-authors,
.project-news {
  margin-top: clamp(32px, 5vw, 64px);
}

/* Сотрудник на странице проекта — ссылка, поэтому убираем подчёркивание,
   которое иначе тянется через всю подпись. */
.project-authors .home-person {
  text-decoration: none;
  color: inherit;
}

/* Архив: список, а не сетка. Сюда приходят искать конкретное. */
.archive-list {
  margin: 0 0 clamp(28px, 4vw, 44px);
  padding: 0;
  list-style: none;
  columns: 2;
  column-gap: clamp(20px, 3vw, 40px);
}
@media (max-width: 720px) {
  .archive-list { columns: 1; }
}
.archive-list li {
  break-inside: avoid;
  margin: 0 0 10px;
  display: flex;
  gap: 10px;
  align-items: baseline;
  justify-content: space-between;
  border-bottom: 1px solid var(--line);
  padding-bottom: 8px;
}
.archive-list a {
  color: var(--ink);
  text-decoration: none;
}
.archive-list a:hover { color: var(--accent); }
.archive-year {
  flex: none;
  font-size: 13px;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

/* Год или стадия у темы проекта: приписка к заголовку, а не второй заголовок.
   Тем на странице бывает три-четыре подряд (концепция, проект, стройка), и
   если каждая стадия начнёт спорить с названием по весу, страница развалится
   на четыре одинаково громких куска. */
.photo-section-stage {
  margin-left: 12px;
  font-size: max(13px, .62em);
  font-weight: 400;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* ==========================================================================
   КАРТОЧКИ НА ТЕЛЕФОНЕ ПОЯВЛЯЮТСЯ СРАЗУ

   В вёрстке карточка выезжает снизу с прозрачностью, а её преобразование
   написано через `perspective(1000px) rotateX() rotateY()` — ради наклона за
   курсором. Наклон этот мышиный: он живёт на `mousemove`, и пальцем его не
   вызвать никогда.

   Зато трёхмерное преобразование обходится дорого и без наклона: каждая
   анимируемая карточка получает собственный слой, а их на странице раздела
   двадцать четыре, и появляются они пачкой — ровно в тот момент, когда доходит
   очередь до первой карточки при прокрутке.

   На узком экране показываем их сразу: анимации нет, слоёв нет, прокрутка
   ровная. На настольном всё остаётся как было — там и наклон работает, и сил
   хватает.
   ========================================================================== */
@media (max-width: 900px) {
  .project-card,
  .project-card.in-view {
    opacity: 1;
    transform: none;
    transition: box-shadow .3s ease, border-color .3s ease;
  }
}

/* ==========================================================================
   РАЗМЫТИЕ ПОД ШАПКОЙ — НЕ ДЛЯ ТЕЛЕФОНА

   Шапка липкая и полупрозрачная: `backdrop-filter: blur(14px) saturate(160%)`.
   Это значит, что при КАЖДОМ кадре прокрутки телефон заново размывает то, что
   проезжает под шапкой, — во всю её ширину. На настольной видеокарте это ничего
   не стоит, на телефоне и планшете это самая дорогая вещь на странице и первый
   подозреваемый в «дрожи» при прокрутке.

   Ниже 900 px размытие выключаем, а фон делаем почти непрозрачным: шапка и
   так читается как отдельный слой, только теперь бесплатно. Само стекло
   остаётся там, где на него есть силы, — на настольных экранах.
   ========================================================================== */
@media (max-width: 900px) {
  header.site-header {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: color-mix(in srgb, var(--surface) 94%, transparent);
  }
}

/* ==========================================================================
   «УВЕЛИЧЕННЫЕ» КАРТОЧКИ НА ТЕЛЕФОНЕ БЫЛИ УВЕЛИЧЕНЫ ТОЛЬКО ШРИФТОМ

   Широкая и крупная карточки занимают два столбца — но только от 600 px.
   Ниже этого они складываются в один столбец и становятся обычными по размеру,
   а кегль названия остаётся большим: 25 и 28 px вместо 20, и строк под него
   отведено две вместо трёх. В одинаковой по ширине карточке это выглядит
   случайной ошибкой, а длинные названия (а они тут почти все длинные)
   обрезаются на середине слова.

   Поэтому на узком экране возвращаем им ровно то же начертание, что у соседей:
   раз карточка не увеличена, то и название не должно быть.

   599.98 — не новая точка перелома, а обратная сторона той же: правило про два
   столбца включается с 600 px, и здесь описано всё, что до неё.
   ========================================================================== */
@media (max-width: 599.98px) {
  .project-card.wide .card-name,
  .project-card.large .card-name {
    font-size: 20px;
    -webkit-line-clamp: 3;
  }
}

/* ==========================================================================
   ПАЛЬЦЕМ ПОПАДАТЬ

   Замерено на телефоне 375 px: тридцать ссылок и кнопок ниже 24 px по высоте —
   это минимум, который просит WCAG 2.5.8, и он же примерно соответствует
   подушечке пальца. Хуже всех точки слайдера: 26×4 px, то есть промахнуться
   легче, чем попасть.

   Увеличиваем ПОЛЕ ПОПАДАНИЯ, а не рисунок: у ссылок подвала отступ съедает
   прежний зазор между строками, поэтому подвал не становится длиннее ни на
   пиксель, а у точек слайдера отступ компенсирован отрицательным полем и
   `background-clip: content-box` — полоска остаётся тонкой, как задумано.
   ========================================================================== */
@media (max-width: 600px) {
  /* Было: строка 22 px и отступ снизу 10 px. Стало: строка 32 px и тот же шаг. */
  .footer-col a {
    margin-bottom: 0;
    padding-block: 5px;
  }
  .footer-social a,
  .mobile-nav-social a {
    padding-block: 6px;
  }
  .home-section-more { padding-block: 6px; }
  .home-splash-foot a { padding-block: 6px; }
}

@media (max-width: 640px) {
  .home-hero-dot {
    /* border-box съел бы высоту: 4 px «вместе с отступами» — это ноль
       содержимого. Здесь считаем от содержимого. */
    box-sizing: content-box;
    padding: 12px 0;
    margin: -12px 0;
    background-clip: content-box;
  }
}

/* ==========================================================================
   ЗАСТАВКА НА ТЕЛЕФОНЕ ДЁРГАЛАСЬ ПРИ ПРОКРУТКЕ

   `.home-splash` в общем файле задана как `min-height: 100dvh`. Буква d здесь —
   dynamic: эта единица меняется, ПОКА ИДЁТ ПРОКРУТКА, потому что в телефоне при
   прокрутке уезжает адресная строка и видимая высота растёт. Значит, заставка
   на ходу становится выше, а всё, что под ней — слайдер, разделы, — уезжает
   вниз навстречу пальцу. Отсюда ощущение, что страница сопротивляется.

   `svh` — та же высота, но СТАБИЛЬНАЯ: она считается по видимой области с
   показанной адресной строкой и во время прокрутки не меняется ни на пиксель.
   Заставка при спрятанной строке оказывается чуть ниже полного экрана — и это
   ровно та цена, за которую страница перестаёт прыгать.

   На настольном браузере ничего не меняется: там все три единицы равны.

   Другие два места с `dvh` трогать не надо. Мобильное меню — накладка поверх
   страницы, и пока она открыта, прокрутка заблокирована, адресная строка стоит.
   `body` длиннее экрана на любой настоящей странице, а на короткой прокрутки
   нет вовсе.
   ========================================================================== */
.home-splash {
  min-height: 100vh;    /* запасной вариант для браузеров без новых единиц */
  /* lvh — высота при СПРЯТАННОЙ адресной строке, то есть самая большая. Она,
     как и svh, статична: во время прокрутки не меняется, поэтому дёрганья нет.
     Зато заставка занимает экран целиком, а не «чуть короче»: с svh при
     спрятанной строке снизу вылезала полоска следующего блока. */
  min-height: 100lvh;
  /* Нижняя строка заставки — почта, копирайт и стрелка «дальше» — при полной
     высоте оказалась бы ПОД адресной строкой в первый момент, пока та ещё
     показана. Поднимаем её ровно на высоту этой строки: разница между большой
     и маленькой высотой — величина постоянная для устройства, она не скачет. */
  padding-bottom: calc(100lvh - 100svh);
}

/* ==========================================================================
   КРОШКИ НА ТЕЛЕФОНЕ

   `.breadcrumb` — это flex без переноса. На широком экране всё помещается, на
   телефоне нет: у проекта цепочка «АБТБ / Проекты / Общественные здания / АГК
   Государственного центра современного искусства (ГЦСИ)». Измерено на живой
   странице при ширине окна 407 px: содержимому нужен 391 px в поле 343 px,
   строки сжимаются и переносятся ВНУТРИ звеньев — крошки занимают пять строк и
   выглядят кашей, а там, где сжиматься некуда, вылезают за экран и включают
   горизонтальную прокрутку всей страницы.

   Делаем две вещи.

   1. Убираем ПОСЛЕДНЕЕ звено — название текущей страницы. Оно и так написано
      заголовком в двадцати пикселях ниже, причём целиком и крупно, а в крошках
      занимает больше места, чем весь путь до него. Остаются ровно те два
      звена, ради которых крошки и существуют: «Проекты» и раздел — по ним
      уходят смотреть соседние работы. Разделитель перед убранным звеном тоже
      прячется, иначе остаётся висящая косая черта.

      Только там, где после «АБТБ» есть хотя бы два звена (`is-deep`): на
      «АБТБ / Контакты» прятать нечего, иначе от крошек останется одно слово.

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

   Разметка при этом остаётся полной: BreadcrumbList для поисковика собирается
   отдельно и получает цепочку целиком.
   ========================================================================== */
@media (max-width: 600px) {
  .breadcrumb {
    flex-wrap: wrap;
    row-gap: 2px;
  }
  .breadcrumb.is-deep > .current,
  .breadcrumb.is-deep > .sep-last {
    display: none;
  }
}

/* ==========================================================================
   КОЛЛАЖ «ОБРАЗОВАНИЯ»: ВЫСОТА ИЗ АТРИБУТА ПОБЕЖДАЛА ПРОПОРЦИЮ

   На прототипе и на UMI коллаж выкладывается правильно, на WordPress кадры
   вытягивались в вертикальные полосы. Разница ровно одна, и она не в стилях.

   `wp_get_attachment_image()` печатает `width="900" height="675"` — это хорошо
   и нужно: браузер резервирует место и страница не прыгает при загрузке. Но
   атрибут height — это presentational hint, то есть настоящее правило
   `height: 675px`. Пока автор не задал высоту сам, побеждает оно, а
   `aspect-ratio: 5 / 4` при двух определённых сторонах не делает НИЧЕГО.
   В прототипе картинки вставлены без атрибутов, поэтому там всё сходилось.

   Измерено на живой главной 25.08.2026: кадр 5/4 рисовался 253×675 (0,38
   вместо 1,25), высокий — 253×1200 вместо 253×413. После `height: auto`
   пропорции стали 1,25 и 0,61, а три колонки — 421, 413 и 421 px, то есть
   ровно то, ради чего коллаж и придуман.

   Правим здесь: `abtb-2026-home.css` общий с UMI и перезаписывается
   синхронизацией, а на UMI этой беды нет.
   ========================================================================== */
.home-collage img { height: auto; }

/* Колонок столько, сколько их на самом деле.

   Сетка описана на три колонки, поэтому тема из двух фотографий занимала две
   трети ширины, а из одной — треть, и блок выглядел обрезанным. Разметка
   сообщает число в data-cols; ниже — только те случаи, где оно меньше трёх.
   Селектор с атрибутом специфичнее голого класса, поэтому порядок файлов роли
   не играет. На узких экранах лишние колонки по-прежнему скрыты общим файлом. */
@media (min-width: 620px) {
  .home-collage[data-cols="1"] { grid-template-columns: minmax(0, 1fr); }
  .home-collage[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   ГАЛЕРЕЯ ИЗ РЕДАКТОРА

   Страницу «Образование» клиент собирает блоками, и блок «Галерея» с
   включённой обрезкой всё равно выкладывался рваным: снимки 1024×653 и
   768×1024 стояли рядом разной высоты. Стилей ядра, которые это выравнивают,
   на странице нет — WordPress подключает только часть общего файла блоков.

   Восстанавливаем ровно то поведение, которое обещает галочка «Обрезать»: в
   пределах ряда все снимки одной высоты, кадр обрезается, а не сплющивается.
   Ничего своего сверх этого — раскладку и промежутки задаёт сам блок.

   Скругление и подпись — чтобы блочная галерея не выглядела чужой рядом с
   собственными сетками сайта: те же 14 px, что у карточек.
   ========================================================================== */
.wp-block-gallery.is-cropped .wp-block-image {
  display: flex;
  /* Именно column. Без направления это row, и подпись встала бы СБОКУ от
     снимка — так же, как в ядре, где эта строка тоже есть. */
  flex-direction: column;
  justify-content: center;
}
.wp-block-gallery.is-cropped .wp-block-image img {
  flex: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.page-body .wp-block-image img,
.news-article-body .wp-block-image img {
  border-radius: 14px;
  display: block;
}
.page-body .wp-block-image figcaption,
.news-article-body .wp-block-image figcaption {
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink-soft);
}

/* Дорога в архив новостей — в самом низу ленты и только на последней её
   странице. Тихая строка, а не кнопка: это боковой ход, а не продолжение
   чтения. */
.news-archive-link {
  margin: clamp(24px, 4vw, 48px) 0 0;
  text-align: center;
}
.news-archive-link a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 15px;
}
.news-archive-link a:hover { color: var(--accent); }

/* ==========================================================================
   ОГЛАВЛЕНИЕ: сетка, в которой фотографий нет и не будет.

   Так выглядят «Информация» (Бюро, Контакты, Новости) и любой раздел, у чьих
   страниц обложек не предвидится. Класс ставит шаблон (page.php), когда ни у
   одного ребёнка нет обложки.

   ПОЧЕМУ ОТДЕЛЬНЫЙ ВИД, А НЕ ПОДКРАШЕННАЯ КАРТОЧКА. Прежняя текстовая карточка
   повторяла пропорцию снимка — 3:4 с пустым верхом, — и пустота читалась как
   «картинка не загрузилась». Ждать при этом нечего. Значит, дело не в оформлении
   пустоты, а в том, что пустоты быть не должно: карточка перестаёт притворяться
   снимком и становится тем, чем является, — строкой оглавления. Высота по
   содержанию, крупный номер как в печатном каталоге, заголовок в полную силу.

   Иерархия строится размером и пробелом, той же логикой, по какой на сайте одна
   гарнитура вместо пары.
   ========================================================================== */

.project-grid.text-grid {
  /* Ряды по содержанию: выравнивать их по высоте снимка больше незачем. */
  grid-auto-rows: auto;
  align-items: stretch;
}

.text-grid .project-card,
.text-grid .project-card.is-textual {
  aspect-ratio: auto;
  height: auto;
  min-height: clamp(210px, 24vw, 270px);
  border: 1px solid var(--line);
  /* Тот же радиус, что у карточек со снимками и у самой карты: скругление на
     этом сайте — общий приём, а не украшение отдельного блока. */
  border-radius: 20px;
  background: var(--surface);
  transition: border-color .2s ease, transform .25s cubic-bezier(.2,.8,.2,1);
}

.text-grid .project-card:hover {
  border-color: var(--accent);
  transform: translateY(-2px);
}

/* Карточка — сама флекс-контейнер, а панель внутри тянется на её высоту.
   Через height:100% это не работает: у карточки высота АВТОМАТИЧЕСКАЯ, процент
   от неопределённой высоты разрешается в auto, и «Перейти» с margin-top:auto
   прилипало бы к тексту вместо нижнего края. */
.text-grid .project-card { display: flex; }

/* Панель заполняет карточку целиком и раскладывает содержимое сверху вниз:
   номер, заголовок, описание, «Перейти» прижато к низу. */
.text-grid .card-textual {
  position: static;
  inset: auto;
  flex: 1 1 auto;
  height: auto;
  padding: clamp(20px, 2.4vw, 30px);
  background: none;
  gap: 0;
}

/* Номер — крупный, как в печатном оглавлении: он и держит верх карточки,
   и говорит, сколько здесь разделов. */
.text-grid .card-textual-index {
  font-family: 'Roboto', 'Helvetica Neue', Arial, sans-serif;
  font-size: clamp(38px, 5vw, 58px);
  font-weight: 700;
  line-height: .9;
  letter-spacing: -0.04em;
  color: var(--accent);
  opacity: .2;
  margin-bottom: clamp(14px, 2vw, 22px);
  transition: opacity .2s ease;
}

.text-grid .project-card:hover .card-textual-index { opacity: .42; }

/* Заголовок и описание встают сразу под номером, а не прижимаются к низу:
   прижимать их вниз имело смысл, когда сверху стояла фотография. */
.text-grid .card-textual-body {
  margin-top: 0;
}

.text-grid .card-textual-name {
  font-size: clamp(23px, 2.4vw, 30px);
  -webkit-line-clamp: 2;
  margin-bottom: 10px;
}

.text-grid .card-textual-desc {
  -webkit-line-clamp: 4;
  max-width: 40ch;
}

/* «Перейти» — к нижнему краю, одной линией по всем карточкам ряда. */
.text-grid .card-textual-go {
  margin-top: auto;
  padding-top: clamp(16px, 2vw, 22px);
}

/* Один в ряд на телефоне карточке уже не нужен высокий минимум. */
@media (max-width: 599px) {
  .text-grid .project-card,
  .text-grid .project-card.is-textual { min-height: 0; }
}

/* ==========================================================================
   КОНТАКТЫ: карта рядом с карточкой.

   На широком экране страница состояла из узкой карточки, половины экрана
   пустоты справа и полосы карты внизу. Пустота была не задумкой, а следствием:
   правая колонка предназначена тексту страницы, а текста на «Контактах» нет —
   в нём лежал только виджет карты, который шаблон оттуда и вынимает.

   Значит, колонку должна занять карта. Класс ставит шаблон, когда текста нет;
   если текст появится, вернётся прежняя раскладка — ему нужно место рядом с
   контактами, а карте ширина.
   ========================================================================== */

.contacts-map.beside {
  margin-top: 0;
  max-width: none;
}

.contacts-map.beside .map-embed {
  height: 100%;
  min-height: clamp(360px, 46vw, 560px);
  aspect-ratio: auto;
}

.contacts-map.beside .map-embed iframe {
  height: 100%;
  min-height: clamp(360px, 46vw, 560px);
}

/* Рамка вокруг карты — как у карточек: тот же радиус, та же линия. Без неё
   виджет висит в странице прямоугольным чужеродным куском. */
.contacts-map .map-embed {
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface);
}

.contacts-map .map-embed iframe {
  border-radius: 20px;
}

/* В тёмной теме карта светится белым прямоугольником на всю колонку. Виджет
   своей темы не имеет, поэтому гасим его фильтром: инверсия с обратным
   поворотом тона оставляет воду синей, а зелень зелёной — просто на тёмном.
   Значения подобраны так, чтобы подписи оставались читаемыми.

   Фильтр не снимается по наведению, хотя соблазн был: карта под курсором
   вспыхивала бы белым прямоугольником посреди тёмной страницы. Ровный вид
   важнее пары процентов точности цвета. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .contacts-map .map-embed iframe {
    filter: invert(0.9) hue-rotate(180deg) saturate(0.75) brightness(1.05) contrast(0.95);
  }
}

:root[data-theme="dark"] .contacts-map .map-embed iframe {
  filter: invert(0.9) hue-rotate(180deg) saturate(0.75) brightness(1.05) contrast(0.95);
}


/* ==========================================================================
   ПОДВАЛ: заголовки колонок — ссылки.

   «Проекты», «Бюро» и «Контакты» это сами разделы, а не подписи к спискам,
   и по ним щёлкают. Вид не меняется: заголовок остаётся заголовком, ссылкой
   он становится только по поведению.
   ========================================================================== */

.footer-col h5 a {
  color: inherit;
  text-decoration: none;
  transition: color .18s ease;
}

.footer-col h5 a:hover,
.footer-col h5 a:focus-visible {
  color: #fff;
}

/* ==========================================================================
   СТОЛКНОВЕНИЕ ИМЁН С КЛАССАМИ <body> ОТ WORDPRESS.

   WordPress вешает на <body> служебные классы: на странице поиска — `search` и
   `search-results`, на первой — `home`, и так далее. В общей вёрстке 2026 года
   такие же имена уже заняты собственными блоками, и на UMI это никого не
   задевало: там <body> ничего подобного не носит.

   Что из этого вышло: `.search-results { max-width: 1120px }` применилось к
   САМОМУ <body>. Страница поиска схлопывалась до 1120 px и прижималась к левому
   краю — у body нет автоматических полей, центрировать его нечем. Выглядело как
   «страница без широкой версии», хотя разметка была правильная, а виноват был
   один селектор, случайно попавший не в тот элемент.

   Гасим здесь, а не в общем файле: abtb-2026-*.css отдаёт и живой сайт на UMI,
   и их перезаписывает tools/theme-assets.py. Селектор с `body` заведомо
   специфичнее голого класса, так что порядок файлов роли не играет.

   Список проверяется инструментом: `python tools/theme-assets.py` сверяет
   классы <body> WordPress с общей вёрсткой и требует гашения для каждого
   совпадения.
   ========================================================================== */

body.search-results {
  max-width: none;
  padding-bottom: 0;
}

/* `.home` — это блок первой страницы, а не сама первая страница. На <body>
   лишний нижний отступ уезжал ПОД подвал. */
body.home {
  padding-bottom: 0;
}

/* ==========================================================================
   КРОШКИ ПО ЛЕВОМУ КРАЮ ЗАГОЛОВКА.

   Цепочка лежит в обычном контейнере (1360 px), а заголовок статьи ограничен
   1120 — и на экранах шире ~1440 крошки начинались на 120 px левее того
   заголовка, к которому относятся. На узких экранах ни один из пределов не
   достигается, поэтому годами не бросалось в глаза.

   Только `.article-page`: у главной первый контейнер живёт по своим правилам,
   и сужать его нельзя.
   ========================================================================== */

main.article-page > .container:first-child {
  max-width: 1120px;
}

/* ==========================================================================
   СТРАНИЦА СОТРУДНИКА: портрет и данные рядом.

   Было: широкая полоса портрета во всю страницу, под ней имя и должность.
   Портреты снимали и кадрировали ПОД КВАДРАТ — это видно по сетке на
   «Сотрудниках» и на главной, — поэтому растянутый кадр обрезал человека по
   глаза, а данные уезжали вниз, оставляя широкий экран пустым.

   Стало: квадрат слева, данные справа, текст под ними на читаемой мере.
   Пропорция и скругление те же, что у карточки в сетке, — человек выглядит
   одинаково везде, где показан.
   ========================================================================== */

.person-top {
  max-width: 1120px;
  display: grid;
  gap: clamp(24px, 4vw, 48px);
  align-items: start;
}

@media (min-width: 860px) {
  .person-top { grid-template-columns: minmax(0, 340px) minmax(0, 1fr); }
}

/* Без портрета колонка одна: пустой квадрат-заглушка на собственной странице
   человека выглядит хуже, чем его отсутствие. */
.person-top.no-portrait { grid-template-columns: minmax(0, 1fr); }

.person-portrait {
  margin: 0;
  aspect-ratio: 1 / 1;
  border-radius: 24px;
  overflow: hidden;
  background: var(--paper);
}

.person-portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Пока колонка одна, квадрат нельзя пускать во всю ширину: на планшете это
   699×699 — портрет во весь экран, а имя и текст уезжают за нижний край.
   На телефоне предел не достигается, там квадрат и так по ширине колонки. */
@media (max-width: 859px) {
  .person-portrait { max-width: 360px; }
}

/* В сетке портреты обесцвечены — это приём для ряда одинаковых карточек.
   Здесь человек один и он предмет страницы: цвет остаётся. */

.person-meta > .article-title { margin-top: 0; }
.person-meta .project-facts { margin-top: clamp(16px, 2vw, 22px); }

.person-body {
  margin-top: clamp(28px, 4vw, 44px);
}

.person-page .project-grid { padding-top: clamp(20px, 3vw, 34px); }

/* ==========================================================================
   ГЛАВНАЯ: сколько новостей помещается, столько и показываем.

   Сетка новостей рассчитана на четыре колонки, а запрос отдавал три записи —
   на широком экране четвёртая ячейка оставалась пустой. Сервер ширины не знает,
   поэтому запрос берёт ЧЕТЫРЕ, а сколько из них видно, решает экран: четыре на
   самом широком, три, две, одна на телефоне.

   Колонки задаём явно, а не auto-fill: число колонок и число видимых карточек
   обязаны совпадать, иначе снова появится либо пустая ячейка, либо карточка,
   висящая одна во втором ряду.
   ========================================================================== */

.home-news-grid { grid-template-columns: 1fr; }
.home-news-grid .news-card:nth-child(n + 2) { display: none; }

@media (min-width: 640px) {
  .home-news-grid { grid-template-columns: repeat(2, 1fr); }
  .home-news-grid .news-card:nth-child(2) { display: flex; }
}

@media (min-width: 1000px) {
  .home-news-grid { grid-template-columns: repeat(3, 1fr); }
  .home-news-grid .news-card:nth-child(3) { display: flex; }
}

@media (min-width: 1320px) {
  .home-news-grid { grid-template-columns: repeat(4, 1fr); }
  .home-news-grid .news-card:nth-child(4) { display: flex; }
}

/* «О бюро» был единственным блоком главной, ограниченным 1120 px, — на широком
   экране его заголовок и ссылка «Подробнее» стояли левее всех соседних. Ширину
   держит теперь сам текст (62ch), как и положено: читаемую меру задаёт строка,
   а не контейнер.

   Значение — то же, что у `.container` в abtb-2026-trendy.css. Не `none`:
   `.home-about` стоит на том же элементе, что и `.container`, и написав `none`
   я снял ограничение вообще — блок растянулся во всю ширину окна, чего с ним
   не случалось и до правки. */
.home-about { max-width: 1360px; }

/* ==========================================================================
   ПОДСКАЗКА ПОД ПОЛЕМ ПОИСКА В ШАПКЕ.

   Появляется, как только в поле что-то набрано, и говорит две вещи: сколько
   нашлось на этой странице и что можно поискать по всему сайту. Раньше лупа
   вне листинга проектов вела на /search/ — адрес поиска в UMI, которого в
   WordPress нет: каждый щелчок оканчивался страницей 404.

   Панель рисуется скриптом (он общий с UMI), а правила — здесь: сама подсказка
   появилась уже на WordPress.
   ========================================================================== */

.header-search { position: relative; }

.header-search-hint {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 280px;
  padding: 9px 13px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .14);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-soft);
  z-index: 60;
}

.header-search-hint a {
  color: var(--accent);
  font-weight: 600;
  white-space: nowrap;
}

/* На телефоне открытое поле занимает почти всю шапку, и подсказка, прижатая к
   его правому краю, уезжала левым краем за экран (замерено: -19 px). Поэтому
   здесь она равняется по ЛЕВОМУ краю поля и не может стать шире экрана. */
@media (max-width: 600px) {
  .header-search-hint {
    left: 0;
    right: auto;
    min-width: 0;
    width: max-content;
    max-width: calc(100vw - 32px);
  }
}

/* ==========================================================================
   СТРАНИЦА ПРОЕКТА.

   Три вещи, каждая — не про красоту, а про то, что мешало читать.
   ========================================================================== */

/* 1. Фотографии шли на 40 px шире заголовка над ними.

   `.photo-section` задаёт `padding: сверху 0 снизу` — и обнуляет боковые поля,
   которые ставит `.container`. Секция при этом та же ширины, что и остальные,
   поэтому «на глаз» казалось, что уехал заголовок, а не фотографии. Возвращаем
   боковые поля, оставляя вертикальные. */
.photo-section.container {
  padding-left: clamp(16px, 4vw, 40px);
  padding-right: clamp(16px, 4vw, 40px);
}

/* Темы идут секциями подряд: концепция, проект, стройка. Тонкая линия сверху
   отделяет одну стадию от другой, не превращая каждую в отдельный экран —
   это по-прежнему одна страница одного объекта. Первой секции линия не нужна:
   над ней и так шапка проекта. */
.photo-section + .photo-section {
  border-top: 1px solid var(--line);
  padding-top: clamp(24px, 4vw, 44px);
}

/* 2. Данные проекта в одну строку.

   Шесть фактов подряд читались как сплошная лента, а подписи (10,5 px, разрядка,
   капитель, `--ink-faint`) почти сливались с фоном: контраст 3,6:1 при норме
   4,5:1 для мелкого текста. Теперь это колонки «подпись сверху, значение снизу»,
   подпись читаемого цвета, а над блоком — линия, отделяющая данные от заголовка. */
.project-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px 28px;
  margin: 6px 0 30px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
}

.project-facts .fact {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}

.project-facts .fact-label {
  font-size: 11px;
  letter-spacing: .07em;
  color: var(--ink-soft);
}

.project-facts .fact-value {
  font-size: 15px;
  line-height: 1.35;
}

/* Теги занимают строку целиком: в колонке шириной с «Заказчика» они переносятся
   по одному в строку и выглядят обрывками. */
.project-facts .fact-wide { grid-column: 1 / -1; }

/* 3. Теги стали ссылками — значит должны и вести себя как ссылки. */
.project-facts .fact-tags a {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: 100px;
  transition: border-color .18s ease, background-color .18s ease;
}

.project-facts .fact-tags a:hover,
.project-facts .fact-tags a:focus-visible {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* 4. Последний блок прилипал к подвалу.

   Нижний отступ был только у секции с фотографиями; когда после неё шли
   «Над проектом работали» и «Новости о проекте», последняя упиралась в подвал
   вплотную. Отступ вешаем на последнюю секцию, какой бы она ни была. */
main.project-page > section:last-of-type {
  padding-bottom: clamp(56px, 9vw, 104px);
}


/* ==========================================================================
   ИНИЦИАЛЫ ВМЕСТО ПОРТРЕТА.

   Половина заведённых сотрудников без фотографии, и это надолго: снимки
   приносят по одному. Вёрстка 2026 года заглушку предусматривала — правила
   `.home-person-initials` в теме лежали с самого переноса, — но разметку её не
   печатал ни один шаблон, и карточка без фото оставалась просто именем. Ряд
   таких карточек читается как поломка, а не как «портрет ещё не принесли».

   Здесь только цвет плитки: в исходных правилах фон заглушки равен фону
   страницы, и квадрат выглядит дырой. Даём ему поверхность карточки и
   волосяную рамку — ту же, что у карточек-оглавления, где пустота тоже
   намеренная.

   Класс ставит шаблон, а не `:has()` — по тому же правилу, что и у сетки
   оглавления: условие известно при отрисовке, значит и решаться должно там.
   ========================================================================== */

.home-person-photo.is-initials {
  /* Плитка тонирована акцентом, а не нейтральна: полсотни ярко-синих монограмм
     на сером фоне кричат поодиночке, а на своём тоне читаются как один приём. */
  background: var(--accent-soft);
  border: 1px solid var(--line);

  /* Размер букв считается от ПЛИТКИ, а не от окна: одна и та же карточка бывает
     178 px на «Сотрудниках» и заметно мельче в блоке авторов проекта, и от
     ширины экрана это не зависит никак. */
  container-type: inline-size;
}

.home-person-initials {
  background: transparent;
  color: var(--accent);
  font-weight: 700;
  letter-spacing: .02em;

  /* Запасное значение для браузеров без контейнерных единиц: объявление с
     неизвестной единицей отбрасывается целиком, и остаётся clamp выше. */
  font-size: clamp(34px, 5vw, 54px);
  font-size: 34cqi;
}
/* ==========================================================================
   ДОКУМЕНТЫ И ПРЕЗЕНТАЦИИ

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

   Две отдельные ссылки, а не кнопка с меню: «Смотреть» и «Скачать» — разные
   намерения, и обе должны быть НАСТОЯЩИМИ ссылками на файл. Без JavaScript,
   в режиме чтения и у поискового робота карточка остаётся рабочей.
   ========================================================================== */
.doc-list { display: flex; flex-direction: column; gap: 10px; }

.doc-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.doc-card {
  flex: 1 1 22rem;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  text-decoration: none;
  color: inherit;
  transition: border-color .18s ease, box-shadow .18s ease;
}

.doc-card:hover { border-color: var(--accent); }
.doc-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.doc-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
}
.doc-icon svg { width: 20px; height: 20px; }

.doc-body { flex: 1 1 auto; min-width: 0; }
.doc-title {
  display: block;
  font-weight: 600;
  line-height: 1.3;
  /* Название презентации бывает длинным, а карточка стоит в ряд со второй
     ссылкой — перенос по словам, а не многоточие: имя файла важнее ровного
     края. */
  overflow-wrap: anywhere;
}
.doc-facts {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.doc-actions { flex: none; }
.doc-open {
  display: inline-block;
  padding: 7px 16px;
  border-radius: 100px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 14px;
  font-weight: 600;
}

.doc-download {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 16px;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
  text-decoration: none;
}
.doc-download svg { width: 16px; height: 16px; }
.doc-download:hover { border-color: var(--accent); color: var(--accent); }
.doc-download:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Блок документов внутри темы проекта отбивается от снимков, но не заводит
   собственного заголовка: заголовок стадии уже стоит выше. */
.photo-section .doc-list { margin-top: 22px; }
.project-docs, .page-docs { margin-bottom: clamp(36px, 6vw, 72px); }

/* Портфолио в подвале — рядом с поиском, тем же ростом. */
.footer-portfolio {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--footer-ink);
  text-decoration: none;
  font-weight: 600;
}
.footer-portfolio svg { width: 18px; height: 18px; }
.footer-portfolio:hover { color: var(--accent); }
.footer-portfolio:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.footer-portfolio-size { font-weight: 400; color: var(--footer-ink-soft); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------- накладка просмотра

   Показывается только на широком экране: на телефоне PDF во фрейме
   отображается плохо, и там ссылка просто открывает файл родной читалкой.
   Решение принимает скрипт по ширине окна — здесь только вид.

   `dvh` тут уместен ровно потому, что под накладкой прокрутка заблокирована:
   адресная строка стоит, и единица не меняется на ходу. В потоке страницы
   он дёргал бы вёрстку — см. заставку главной. */
.doc-viewer {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  flex-direction: column;
  background: color-mix(in srgb, #0a0d16 92%, transparent);
}
.doc-viewer[hidden] { display: none; }

.doc-viewer-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px clamp(12px, 3vw, 24px);
  color: #fff;
}
.doc-viewer-title {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.doc-viewer-get {
  flex: none;
  padding: 7px 16px;
  border-radius: 100px;
  background: rgba(255, 255, 255, .14);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.doc-viewer-get:hover { background: rgba(255, 255, 255, .24); }
.doc-viewer-close {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .14);
  color: #fff;
  cursor: pointer;
}
.doc-viewer-close:hover { background: rgba(255, 255, 255, .24); }
.doc-viewer-get:focus-visible,
.doc-viewer-close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.doc-viewer-close svg { width: 18px; height: 18px; }

.doc-viewer-frame {
  flex: 1 1 auto;
  width: 100%;
  border: 0;
  background: #fff;
}

@media (max-width: 600px) {
  .doc-card { flex-basis: 100%; }
  .doc-row { gap: 8px; }
}

/* ==========================================================================
   «ПЕРЕЙТИ К СОДЕРЖАНИЮ»

   Первая ссылка страницы, спрятанная до тех пор, пока в неё не попадёт фокус
   с клавиатуры. Прячем СМЕЩЕНИЕМ, а не `display: none`: спрятанное этими
   способами не фокусируется вовсе, и ссылка не сработала бы никогда.

   Разметка — в header.php, там же объяснено, зачем она.
   ========================================================================== */
.skip-link {
  position: absolute;
  left: 12px;
  top: -100px;
  z-index: 1000;
  padding: 12px 20px;
  border-radius: 0 0 12px 12px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  transition: top .18s ease;
}

.skip-link:focus {
  top: 0;
}

/* Якорь приземления не должен ничего занимать и не должен рисовать свою
   рамку: рамку рисует то, куда человек попал, а не точка перехода. */
#abtb-content {
  display: block;
  height: 0;
  outline: none;
}

/* ==========================================================================
   ВИДИМЫЙ ФОКУС ТАМ, ГДЕ ЕГО НЕ БЫЛО

   Проверено 31.08.2026 перебором подключённых стилей на живой странице:
   правил с `:focus-visible` на сайте тридцать одно, и они закрывают мелкое
   управление — переключатель темы, лупу, кнопку меню, крестик, пагинатор.
   А вот СОДЕРЖАНИЕ они не закрывают: карточка проекта, пункт верхнего меню,
   плитка альбома, карточка человека, крошки, ссылки подвала своего кольца не
   имеют, и человек с клавиатурой видит вместо него браузерное — тонкую
   служебную рамку, у которой на разных фонах разный цвет и разная толщина.

   Хуже одно место: `.toolbar-search input` в общем файле гасит кольцо
   (`outline: none`) и ничего не даёт взамен. У соседей так же, но у них есть
   замена: `.mobile-nav-search:focus-within` и `.catalog-search:focus-within`
   подсвечивают рамку поля. У панели над сеткой замены нет — то есть поиск по
   проектам на всех страницах разделов, на «Проектах» и в «Архиве» при фокусе
   не показывает НИЧЕГО. Это прямое несоответствие WCAG 2.4.7, и оно
   единственное на сайте.

   Кольцо здесь то же самое, каким сайт уже пользуется в тридцати одном месте:
   2 px сплошного `--accent`. Радиус НЕ задаём — браузер сам повторяет
   скругление элемента, а собственное значение испортило бы карточки.
   `outline-offset` отодвигает кольцо от карточки на фон страницы, чтобы оно
   не терялось на тёмной фотографии.
   ========================================================================== */
.main-nav a:focus-visible,
.breadcrumb a:focus-visible,
.project-card:focus-visible,
.photo-item:focus-visible,
.home-person:focus-visible,
.news-card:focus-visible,
.section-all:focus-visible,
.toolbar-filter:focus-visible,
.menu-toggle:focus-visible,
.site-footer a:focus-visible,
.tag-chip:focus-visible,
.card-resize:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Поле поиска над сеткой: кольцо погашено в общем файле, поэтому подсвечиваем
   саму панель поля — ровно так же, как это сделано у мобильного меню. */
.toolbar-search:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 10px;
}

/* Поле в шапке раскрывается по нажатию на лупу и тоже идёт без кольца.
   Подсвечиваем обёртку — она и есть видимая часть. */
.header-search:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 100px;
}

/* Плитка альбома лежит вплотную к соседям, и кольцо снаружи налезало бы на
   них. Ей — кольцо внутрь, по краю самой фотографии. */
.photo-item:focus-visible {
  outline-offset: -3px;
}

/* ==========================================================================
   ПАЛЬЦЕМ ПОПАДАТЬ: ЕЩЁ ДВА МЕСТА

   Замерено на телефоне 375 px после прошлого захода: ниже 24 px (WCAG 2.5.8)
   остались ровно два вида ссылок — логотип в шапке (127×20) и звенья крошек
   (36×22 и 61×22).

   Обе правки не двигают вёрстку ни на пиксель. У логотипа шапка и без того
   заметно выше 24 px, поэтому нижняя граница высоты ничего не меняет. У крошек
   поле компенсировано отрицательным полем: `.breadcrumb` — это flex, и его
   дети слушаются полей, поэтому строка остаётся прежней высоты, а попасть в
   неё пальцем становится можно.
   ========================================================================== */
.logo-mark {
  min-height: 24px;
}

.breadcrumb a {
  padding-block: 5px;
  margin-block: -5px;
}

/* ==========================================================================
   ОЧЕНЬ БОЛЬШИЕ МОНИТОРЫ

   Содержание ограничено `.container` шириной 1360 px. На ноутбуке это верно, а
   на мониторе 2560 px измерено 31.08.2026: содержание занимает 53% ширины,
   карточка проекта — 408 px. Для бюро, у которого работа целиком визуальная,
   это дорого: полметра экрана с каждой стороны заняты полями.

   Колонок при этом НЕ добавляем. В общем файле у сетки написано прямо: дальше
   трёх колонок фотографии становятся мелкими и не читаются. Здесь ровно
   обратное намерение: те же три колонки, но крупнее — 470 и 530 px вместо 408.

   ПОЧЕМУ ПРОСТО `.container`, А НЕ ТОЛЬКО ТЕ, ГДЕ ЛЕЖИТ СЕТКА. Первая попытка
   расширяла именно их — через `:has()`. Получилось хуже: на странице раздела
   заголовок и описание остаются в контейнере 1360, а сетка под ними становится
   1560, и левые края расходятся на сто пикселей. Расхождение читается как
   поломка, а не как приём.

   Расширять всё вместе безопасно, потому что ТЕКСТ на этом сайте меру уже
   знает сам — проверено на живых страницах 31.08.2026:

       .cat-desc            554 px      .project-lead        650 px
       .news-article-body   669 px      .project-awards      720 px
       .article-title       900 px      .article-page .container 1120 px

   То есть шире становятся сетки, альбом, шапка страницы и заголовки — то,
   чему ширина на пользу, — а строка текста остаётся той же длины, что и на
   ноутбуке. Страница у статьи не меняется вовсе: её собственные 1120 px
   специфичнее и побеждают.
   ========================================================================== */
@media (min-width: 1700px) {
  .container {
    max-width: 1560px;
  }

  /* ВЫСОТУ РЯДА АЛЬБОМА ОТСЮДА НЕ ПОДНЯТЬ, и пробовать не стоит.
     Ряды выкладывает скрипт (`abtb-2026-gallery.js`): он меряет ширину сетки и
     пишет ширину и высоту КАЖДОЙ плитке прямо в разметку, а `--row-h` в CSS
     остаётся запасным вариантом для случая без JS. Целевая высота ряда там
     задана числом — `W < 900 ? 240 : 300` — и от ширины монитора не зависит.
     Проверено 31.08.2026 на живой странице: при окне 1800 px плитки получают
     `height: 341px` инлайном, что бы ни стояло в `--row-h`.

     Поэтому на широком экране в ряд помещается БОЛЬШЕ кадров прежнего размера,
     а не столько же, но крупнее. Ведущая фотография при этом растёт вместе с
     контейнером (измерено: 1280 → 1480 px), и это здесь главное.

     Захочется поднять и остальные — менять надо `target` в самом скрипте, а он
     общий с UMI и приезжает через tools/theme-assets.py. Это отдельная правка
     на два сайта, а не строчка в теме. */

  /* Единственный текст без своей меры — призыв «Обсудим проект?» в подвале
     главной. Он набран по центру, и растянутая на полтора метра строка
     читается тяжело: глазу негде зацепиться при возврате на начало. */
  .home-contact-inner {
    max-width: 1120px;
    margin-inline: auto;
  }
}

@media (min-width: 2100px) {
  .container {
    max-width: 1760px;
  }
}

/* ==========================================================================
   ВИДЕО: ГОРИЗОНТАЛЬНОЕ, ВЕРТИКАЛЬНОЕ И РИЛСЫ

   Появилось на WordPress и на UMI не нужно, поэтому живёт здесь, а не в общих
   файлах вёрстки: те приезжают из шаблонов UMI и перезаписываются
   синхронизацией.

   Раскладка нарочно на флексе, а не на `repeat(auto-fit, minmax(...))` с
   пролётами: пролёт заставляет браузер создать колонку в обход минимума, и на
   375 px это уже стоило нам сетки карточек (см. «Пять граблей сетки»). Здесь
   правило простое: горизонтальный ролик занимает строку целиком, вертикальные
   встают рядом, пока хватает места.

   Пропорции приходят инлайном в --ar, как у фотоальбома. Место под плеер
   занято до его загрузки, и страница не дёргается.
   ========================================================================== */

.video-section {
  margin: 48px auto 8px;
}

.video-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  align-items: flex-start;
}

.video-item {
  margin: 0;
  min-width: 0;   /* иначе флекс-элемент отказывается сжиматься ниже кадра */
}

.video-item.video-wide     { flex: 1 1 100%; }
.video-item.video-vertical { flex: 0 1 420px; }

/* Рамка плеера. Фон тёмный НАМЕРЕННО и в обеих темах: пока ролик не начали
   смотреть, здесь стоит обложка — то есть фотография, — и подкладывать под неё
   цвет страницы незачем. Светлая полоса под тёмным кадром выглядела бы щелью. */
.video-frame {
  position: relative;
  aspect-ratio: var(--ar, 1.778);
  background: #0b0d12;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
}

.video-frame > video,
.video-frame > iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  object-fit: cover;
}

/* Заставка встроенного ролика: до нажатия на странице нет ни одного чужого
   скрипта. Кнопка — настоящая <button>, а не div с обработчиком: ей нужен
   фокус с клавиатуры и имя для чтения вслух. */
.video-facade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  display: block;
}

.video-facade img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.video-facade.is-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: linear-gradient(160deg, #1b2233, #0b0d12);
}

.video-blank-title {
  color: #e7eaf2;
  font-size: 18px;
  line-height: 1.4;
  text-align: center;
  max-width: 22ch;
}

/* Кнопка «играть» не берёт цвета из темы, и это осознанно: она всегда лежит
   поверх фотографии, а не поверх фона страницы. Белый круг с синим
   треугольником одинаково читается и в светлой теме, и в тёмной. */
.video-play {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 68px;
  height: 68px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 6px 24px rgba(0, 0, 0, .28);
  cursor: pointer;
  transition: transform .18s ease, background-color .18s ease;
}

.video-play::after {
  content: '';
  position: absolute;
  left: 52%;
  top: 50%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent #003399;
}

.video-facade:hover .video-play,
.video-play:hover {
  background: #fff;
  transform: translate(-50%, -50%) scale(1.06);
}

.video-facade:focus-visible,
.video-play:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

.video-caption {
  margin: 10px 2px 0;
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.45;
}

/* ------------------------------------------------------------------ рилсы */

/* Лента с прилипанием — тот же жест, что в телефоне. Горизонтальная прокрутка
   здесь СВОЯ и намеренная; страница целиком при этом не едет, потому что
   прокручивается сам ряд, а не body. */
.reels-row {
  display: flex;
  gap: 14px;
  margin-top: 28px;
  padding-bottom: 10px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}

.reels-row .video-item {
  flex: 0 0 clamp(220px, 62vw, 290px);
  scroll-snap-align: start;
}

.reels-row .video-frame {
  border-radius: 14px;
}

/* Кнопка звука у рилса: он играет без звука сам, а нажатие включает звук и
   показывает панель проигрывателя. Пока звука нет, кнопка и есть подсказка,
   что ролик можно открыть. */
.reel-play {
  z-index: 2;
  width: 56px;
  height: 56px;
}

.video-frame.is-live .reel-play {
  display: none;
}

/* На телефоне лента доходит до краёв экрана: обрезанная карточка у края —
   это и есть подсказка, что ряд листается. Отступ возвращается полем, чтобы
   первая карточка не прилипала к рамке. */
@media (max-width: 600px) {
  .reels-row {
    margin-inline: calc(clamp(16px, 4vw, 40px) * -1);
    padding-inline: clamp(16px, 4vw, 40px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .video-play,
  .video-facade:hover .video-play {
    transition: none;
    transform: translate(-50%, -50%);
  }
}

/* ------------------------------------------- блок «Видео» в тексте страницы

   Стили блока (в редакторе — «Вертикальное» и «Рилс») вместо шорткода: список
   виден прямо в правой панели и переключается щелчком, а шорткод надо помнить
   наизусть. Ровно та же мысль, что у стилей галереи.                        */

.wp-block-video.is-style-abtb-vertical,
.wp-block-video.is-style-abtb-reel {
  margin-inline: auto;
}

.wp-block-video.is-style-abtb-vertical { max-width: 420px; }
.wp-block-video.is-style-abtb-reel     { max-width: 290px; }

.wp-block-video.is-style-abtb-vertical video,
.wp-block-video.is-style-abtb-reel video {
  width: 100%;
  height: auto;          /* без него aspect-ratio ниже не делает ничего */
  aspect-ratio: 9 / 16;
  object-fit: cover;
  border-radius: 10px;
  background: #0b0d12;
}

.wp-block-video.is-style-abtb-reel video { border-radius: 14px; }


/* ==========================================================================
   ТЕГИ НОВОСТИ СТАЛИ ССЫЛКАМИ

   Страница тега существовала с самого начала и показывает и проекты, и новости
   (`tag.php`), но со страницы СТАТЬИ входа туда не было: тег выглядел ссылкой,
   а был подписью. Правила те же, что у тегов проекта, — приём на сайте один.

   В ЛЕНТЕ новостей теги остаются подписями, и это не недоделка: там карточка
   целиком является ссылкой, а ссылка внутри ссылки недопустима в разметке.
   ========================================================================== */

.article-tags a {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  border: 1px solid var(--line);
  padding: 3px 9px;
  border-radius: 100px;
  transition: border-color .18s ease, background-color .18s ease;
}

.article-tags a:hover,
.article-tags a:focus-visible {
  border-color: var(--accent);
  background: var(--accent-soft);
}

/* ==========================================================================
   ВЫХОД ИЗ ПРОЕКТА: «ЕЩЁ В РАЗДЕЛЕ»

   Страница проекта была тупиком. Посетитель приходит на неё из поиска или по
   чужой ссылке, дочитывает — и дальше у него ровно два выхода: кнопка «назад» в
   браузере и верхнее меню. Для портфолио это худшее, что может случиться:
   человек уже смотрит работы бюро, а показать ему следующую нечем. У новости
   соседние записи были с самого начала, у проекта — нет.

   Отделяем блок линией сверху: это уже не про этот проект, а про то, куда
   пойти дальше, и читаться он должен как другая часть страницы.
   ========================================================================== */

.project-siblings {
  margin-top: clamp(48px, 6vw, 84px);
  padding-top: clamp(28px, 4vw, 44px);
  border-top: 1px solid var(--line);
}

/* Ссылка «Весь раздел» стоит в одной строке с заголовком и на узком экране
   уходит под него: `home-section-head` для этого и сделан флексом с переносом. */
.section-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.section-all svg {
  width: 16px;
  height: 16px;
  transition: transform .18s ease;
}

.section-all:hover svg,
.section-all:focus-visible svg { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .section-all svg { transition: none; }
  .section-all:hover svg { transform: none; }
}

/* ==========================================================================
   КАТАЛОГ ПРОЕКТОВ

   Страница /catalog/: все работы бюро одним списком, живые и архивные вместе.
   Плотный список, а не сетка карточек, — сюда приходят искать конкретное.
   Своей палитры нет: только существующие переменные, иначе тёмная тема
   разъедется.
   ========================================================================== */

.catalog-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 clamp(16px, 2.5vw, 24px);
}

.catalog-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 260px;
  max-width: 420px;
  padding: 0 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 100px;
}

.catalog-search svg {
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--ink-faint);
}

.catalog-search input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 11px 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}

.catalog-search input:focus { outline: none; }
.catalog-search:focus-within { border-color: var(--accent); }

/* Крестик очистки у type="search" в вебките рисуется тёмным всегда и на тёмной
   теме превращается в чёрное пятно. Escape очищает поле и без него. */
.catalog-search input::-webkit-search-cancel-button { display: none; }

.catalog-chips { display: flex; flex-wrap: wrap; gap: 6px; }

.catalog-chip {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: var(--surface);
  color: var(--ink-soft);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  transition: color .18s ease, border-color .18s ease, background-color .18s ease;
}

.catalog-chip:hover { color: var(--ink); border-color: var(--ink-faint); }

.catalog-chip.is-on {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent);
  font-weight: 600;
}

.catalog-count {
  margin: 0;
  color: var(--ink-soft);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}

/* Быстрый переход к разделу. На телефоне список в триста строк листается
   полминуты, и это единственный способ попасть в «Транспорт» сразу. */
.catalog-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin: 0 0 clamp(22px, 3vw, 34px);
  padding-bottom: clamp(14px, 2vw, 20px);
  border-bottom: 1px solid var(--line);
}

.catalog-jump a {
  color: var(--ink-soft);
  font-size: 14px;
  text-decoration: none;
  transition: color .18s ease;
}

.catalog-jump a:hover { color: var(--accent); }

/* Строка каталога: название слева, пометки справа одной группой — иначе год и
   «в архиве» разъезжаются по разным краям и читаются как два разных столбца. */
.catalog-meta {
  flex: none;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}

.catalog-flag {
  padding: 2px 8px;
  border-radius: 100px;
  background: var(--paper-2);
  color: var(--ink-soft);
  font-size: 12px;
  white-space: nowrap;
}

.catalog-empty {
  margin: clamp(16px, 3vw, 28px) 0;
  color: var(--ink-soft);
}

/* Ссылка «туда, где остальное»: с архива в каталог и обратно. Не кнопка —
   это боковой ход, а не главное действие страницы. */
.archive-elsewhere {
  margin: 0 0 clamp(22px, 3vw, 32px);
  color: var(--ink-soft);
  font-size: 15px;
}

.archive-elsewhere a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
}

.archive-elsewhere svg { width: 16px; height: 16px; transition: transform .18s ease; }
.archive-elsewhere a:hover svg { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .archive-elsewhere svg,
  .catalog-chip { transition: none; }
  .archive-elsewhere a:hover svg { transform: none; }
}
