/* ============================================================
   Блок «Команда (лента людей)» — team-members
   ТЗ: site/docs/tz/tz-team-block.md

   Раскладка ряда — свой CSS Grid из трёх областей, а не колонки Bootstrap:
   на ≥768 левая колонка должна быть ОДНОЙ ячейкой из трёх строк
   (номер / фото / имя+должность), а правая — сквозной колонкой во всю высоту
   ряда. В .row/.col это выражается только вложенным рядом, то есть лишним
   уровнем DOM ради того же результата. Сетка и утилиты Bootstrap на странице
   при этом никуда не деваются — блок живёт внутри .container из page.php.

   Цвет — ТОЛЬКО контекстная палитра --ctx-* (style.css, раздел «КОНТЕКСТНАЯ
   ПАЛИТРА»): обе темы уже внутри этих токенов. Поэтому в файле ноль hex
   и ни одной ветки «если тёмная тема».

   ВСЕ селекторы минимум из двух классов не для красоты: страница кейса задаёт
   типографику через `.case-body h3` / `.case-body p` (специфичность 0,1,1),
   и одноклассовое правило ей проигрывает. Два класса (0,2,0) перебивают.
   ============================================================ */

.team-section {
	/* --- меры и ритм --- */

	/* Мера = мера сетки кейсов, один в один. 23.08.2026, по замечанию владельца
	   «в команде и о компании сжатая вёрстка по ширине, в отличие от портфолио,
	   сделай везде одинаково, как в портфолио».
	   Раньше здесь стояла --case-wide (1152px) — мера СТРАНИЦЫ КЕЙСА, и на
	   главной лента вставала уже сетки на 158px с каждой... с обеих сторон
	   суммарно, то есть панель «Команда» читалась поджатой рядом с панелью
	   «ПО для застройщиков».
	   Сетка меряется так (cases-grid.css:61 — .cases-head/.cases-grid):
	     max-width: var(--case-max)  внутри секции с padding-inline: --case-pad,
	   то есть min(100vw − 2·--case-pad, 2000px). У .team-section точно такой же
	   padding-inline, поэтому достаточно взять тот же потолок — левый и правый
	   край заголовка, линейки и рядов совпадают с краями карточек.
	   Полный full-bleed сюда не годится и не нужен: сетка тоже не full-bleed,
	   full-bleed у неё только ФОН секции. Читаемость строки при этом не страдает
	   — меру текста держит своя, 62ch на .team-member__bio p.
	   Токены объявлены на :root (style.css:2156), доступны и вне страницы кейса. */
	--team-measure: var(--case-max, 2000px);

	/* Разрыв фото ↔ текст. T25/T25.1: было clamp(1.25rem, 3vw, 3rem) — но при
	   колонках 5fr/7fr текст всё равно уезжал вправо не из-за gap, а из-за того,
	   что колонка фото (5fr ≈ 460px) была ВТРОЕ шире самого фото (208px), и весь
	   избыток становился пустотой. Колонки на ≥768 теперь auto/1fr (фото ровно
	   под свой размер, текст — остаток), поэтому gap стал единственным зазором
	   и его ужали до умеренного. */
	--team-gap: clamp(1.25rem, 2.5vw, 2rem);      /* колонка фото ↔ колонка текста */

	/* Ритм между людьми ужат 23.08.2026 (было clamp(2.5rem, 5vw, 4.5rem)) —
	   владелец попросил, чтобы каждый сотрудник занимал меньше места и лента
	   читалась плотнее. Нижняя граница держит воздух, чтобы соседи
	   не слипались. */
	--team-rhythm: clamp(1.75rem, 3.5vw, 3rem);  /* между людьми */

	/* Мера ЧИТАЕМОСТИ правой колонки — ОДНА на весь текстовый блок (T25.1,
	   24.08.2026, «текст и заголовок расширять синхронно»). Раньше 62ch висела
	   индивидуально на .team-member__bio p и на .team-member__location: описание
	   упиралось в ≈500px, а имя (без ограничителя) тянулось во всю расширенную
	   колонку (≈940px+) — правые края имени и описания разъезжались.
	   Теперь ограничитель ОБЩИЙ, на областях __id и __text: имя, должность,
	   описание и локация делят одну меру и растут вместе, левые И правые края
	   выровнены. Потолок держит строку читаемой на очень широком экране,
	   но он заметно шире прежних 62ch — описание больше не вдвое уже заголовка.

	   T91 (24.08.2026, по замечанию владельца «тексты сотрудников сделай пошире»):
	   было 78ch (≈757px). На широком десктопе (≥1200) текстовая колонка рядом
	   с фото 208px имеет запас ≈1160px, а 78ch резал строку почти вдвое от
	   доступного — справа зияла пустота. Поднято до 100ch (≈970px): строки идут
	   заметно шире, текст меньше переносится, при этом 100ch — разумный верхний
	   предел читаемости для абзаца с line-height 1.6 (не разъезжается в «простыню»
	   во всю колонку 1160px+). На ≤lg колонка и так уже меры (712/559/355px
	   по замерам), мера там не срабатывает — раскладка мобилки/планшета не меняется. */
	--team-text-measure: 100ch;

	/* Воздух под линейкой. Ужат 23.08.2026 вместе с общим ритмом
	   (было clamp(1.5rem, 3vw, 2.5rem)). Всё ещё больше, чем у case-facts-grid
	   (там clamp(0.875rem, 1.6vw, 1.25rem)): в этот запас уходит дрейф круга
	   (слой L2, до 10px), при меньшем значении круг на входе в кадр наезжал бы
	   на линейку. */
	--team-rule-gap: clamp(1.125rem, 2.4vw, 1.75rem);

	/* --- линейки ---
	   Тот же приём, что у .case-fact и .bottom_nav: волосяная линейка вместо
	   рамки и заливки. Линейка ОДНА на всех: акцентная (втрое толще, цветом
	   --ctx-accent) стояла у первого человека и снята 22.08.2026 вместе со всем
	   выделением первого ряда — см. большой комментарий в team-members.php. */
	--team-rule: var(--ctx-border);

	/* Кольцо портрета, см. .team-member__photo */
	--team-ring: color-mix(in srgb, var(--ctx-ink) 16%, transparent);

	/* Приглушённый текст блока (лид, счётчик, инициалы).
	   НЕ --ctx-muted напрямую: вне страницы кейса он берётся из фиксированного
	   --macro-muted (#7e7f82), а это 4.0:1 на белом — ниже порога WCAG AA
	   для мелкого текста, а весь приглушённый текст здесь мелкий (0.8125rem).
	   Рецепт взят у самой же палитры: на странице кейса --ctx-muted именно так
	   и считается — доля основного текста, прозрачностью (style.css:3103).
	   Здесь та же формула, но доля выше, поэтому обе темы проходят 4.5:1. */
	--team-quiet: color-mix(in srgb, var(--ctx-ink) 68%, transparent);

	/* --team-index-ghost (тон крупного номера ряда) удалён 23.08.2026
	   вместе с нумерацией людей — узла .team-member__index больше нет. */

	/* --- портрет ---
	   Базовое значение мобильное (mobile-first), десктопное — в @media ниже. */
	--team-photo: clamp(88px, 24vw, 120px);

	/* Акцент ТЕКСТОМ ≠ акцент заливкой: вне кейса в тёмной теме заливочный
	   --macro-accent слишком тёмен для текста, там берётся его «текстовая»
	   светлота. Порядок фолбэков — как в case-facts-grid.css:71. */
	--team-accent-text: var(--case-accent-text, var(--macro-accent-text, var(--ctx-accent)));

	/* Запас картинки по высоте сверх маски, доля диаметра D. Из него живёт
	   параллакс слоя L1: сверху и снизу остаётся по bleed/2. */
	--team-img-bleed: 0.2;

	/* --- параллакс: полуразмах каждого слоя (ТЗ §5.1) ---
	   ЕДИНСТВЕННОЕ место, где записаны амплитуды: их читают и CSS
	   scroll-driven анимации (путь A), и JS-фолбэк (путь B).
	   L2 и L3 на мобильном выключены — см. комментарий у @media ниже.

	   ⚠️ ТЗ §5.1 просило 0.18·D при картинке 150% высоты. Так и было бы,
	   если бы портреты приходили обычными прямоугольными фото. Реальные
	   портреты команды — PNG 448×448 с УЖЕ ВЫРЕЗАННЫМ кругом Ø420 и прозрачным
	   полем. Для квадратного источника object-fit:cover в боксе 1:1.5 вписывает
	   его по высоте и увеличивает в 1.39 раза — то есть в маске остаётся
	   центральные 72% и без того плотно скадрированной головы (у части портретов
	   волосы обрезаны уже в исходнике). Плюс вырезанный круг обязан
	   перекрывать маску в любой фазе, иначе на краю вылезет серп фона.
	   Отсюда пересчёт ниже; связь величин — в двух неравенствах у --team-img-bleed
	   и в комментарии к .team-member__img. Вернуть размах ТЗ можно ровно двумя
	   числами, но только вместе с прямоугольными исходниками. */
	--team-drift-img: calc(var(--team-photo) * 0.05);
	--team-drift-frame: 0px;

	/* Свой горизонтальный отступ — на случай, если блок поставят вне
	   бутстраповского контейнера (шаблон без .container). Внутри .container
	   он гасится правилом ниже, иначе паддинги сложились бы. */
	padding-inline: var(--case-pad, clamp(1rem, 4.5vw, 6rem));

	/* Вертикали немного: page.php уже даёт .container py-5 mt-5 (48+48px). */
	padding-block: clamp(1.5rem, 4vw, 3rem);
}

/* Плоский фолбэк там, где нет color-mix — тот же приём, что у .case-page
   и case-facts-grid. */
@supports not (color: color-mix(in srgb, red, blue)) {
	.team-section {
		--team-ring: var(--ctx-border);
		--team-quiet: var(--ctx-muted);
	}
}

.container .team-section,
.container-fluid .team-section {
	padding-inline: 0;
}

/* Мера — на прямых детях секции, а не на самой секции: так фон/паддинги
   остаются во всю ширину колонки страницы, а контент центрируется. */
.team-section > * {
	max-width: var(--team-measure);
	margin-inline: auto;
}

/* Внутри бутстраповского контейнера центрировать ВТОРОЙ раз нельзя: .container
   уже центрирован, и остаток (1320 − 1152 = 168px) разошёлся бы по половине
   на сторону — блок встал бы с отступом 84px от левого края собственного <h1>,
   который page.php печатает по краю контейнера. Прижимаем к тому же краю:
   мера соблюдена, левая вертикаль страницы одна. */
.container .team-section > *,
.container-fluid .team-section > * {
	margin-inline: 0;
}

/* Панель главной. cases-grid.css:1015 держит правило
   `[data-home-panel]:not(.cases-panel) > * { margin-inline: 0 auto }` (0,2,0) —
   оно прижимало содержимое чужих панелей влево, потому что их меры были УЖЕ
   меры сетки (у ленты стояла --case-wide) и центрирование увело бы их вправо
   от ленты табов. С 23.08.2026 мера здесь та же, что у сетки (см. --team-measure),
   и посылка правила для этой панели перестала быть верной: ниже ~2192px оно
   ни на что не влияет (мера упирается в паддинги), а выше — прижимает ленту
   к левому краю, пока табы и карточки центрируются. Возвращаем центрирование
   ТОЛЬКО своей секции, у себя в файле: cases-grid.css не наш и правится
   параллельно. Специфичность (0,3,0) перебивает без оглядки на порядок
   подключения файлов. ⚠️ Комментарий в cases-grid.css при этом устарел
   в части «у team-section это --case-wide» — сказать владельцу, а не молча
   править чужой блок. */
.team-section[data-home-panel]:not(.cases-panel) > * {
	margin-inline: auto;
}

/* Подсказка редактору в пустом блоке (на фронт не попадает). */
.team-section__hint {
	color: var(--ctx-muted);
	font-size: 0.9375rem;
	margin: 0;
}


/* ============================================================
   Шапка секции — УБРАНА 23.08.2026 по решению владельца.
   Раньше здесь жили .team-head / .team-head--ruled / __title / __lead /
   __rule(::before) / __count (заголовок «Команда», лид, hairline со счётчиком,
   один в один .cases-head с главной). Разметку <header> сняли в team-members.php,
   правила удалены отсюда, чтобы не держать пустой ритм над лентой.
   Данные ACF сохранены — восстановление обратимо по истории обоих файлов.
   Лента теперь начинается со своей линии: border-top первого .team-member
   (класс team-list--under-head-rule больше не печатается, флаг $tm_has_head_rule
   жёстко false).
   ============================================================ */


/* ============================================================
   Лента людей
   ============================================================ */

/* margin-block, а не margin: сокращённое свойство обнулило бы и margin-inline,
   которым выше выставлена мера (правило .team-section > * специфичнее не будет —
   у него один класс). Ровно на этом список уезжал левее шапки секции. */
.team-section .team-list {
	list-style: none;
	margin-block: 0;
	padding: 0;
}

/* Ряд человека. Мобильная раскладка: фото и имя в строку, текст под ними. */
.team-section .team-member {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	grid-template-areas:
		"photo id"
		"text  text";
	column-gap: var(--team-gap);
	row-gap: clamp(0.75rem, 2.2vw, 1.125rem);

	border-top: 1px solid var(--team-rule);
	padding-top: var(--team-rule-gap);

	/* Ряд — субъект scroll-таймлайна (путь A, см. блок параллакса ниже).
	   Объявлено здесь, а не в @supports: свойство и так игнорируется там,
	   где не поддерживается, а держать его рядом с раскладкой честнее —
	   видно, что таймлайн принадлежит ряду. */
	view-timeline-name: --team-row;
	view-timeline-axis: block;
}

.team-section .team-member + .team-member {
	margin-top: var(--team-rhythm);
}

/* ⚠️ Верхняя линейка ленты снята у ПЕРВОГО ряда — T75, 24.08.2026, по прямому
   замечанию владельца «над Школьником убери полоску».
   История: линейки в ленте — язык блока, они разделяют людей (border-top на
   каждом .team-member). Пока над лентой стояла шапка со счётчиком (её волосок
   повторял .cases-head__rule на главной), border-top первого ряда сливался
   с линейкой шапки в одну линию под счётчиком. 23.08.2026 шапку убрали целиком
   (заголовок/лид/линейка), флаг $tm_has_head_rule жёстко false — и border-top
   первого человека остался висеть отдельной линией НАД первой карточкой, уже
   без счётчика и без смысла. Её и просил убрать владелец.
   Снимаем только у первого ряда: border-top + padding-top (зазор под линейку).
   Разделители МЕЖДУ людьми не трогаем — это ритм ленты. Ритм между рядами
   (.team-member + .team-member { margin-top }) первого ряда не касается.
   Селектор через :first-child, а не мёртвый класс team-list--under-head-rule:
   тот класс PHP больше не печатает (шапки нет), правило под него не срабатывало
   бы никогда. Три части селектора (.team-section .team-list .team-member) держат
   специфичность выше базового двухклассового .team-section .team-member. */
.team-section .team-list > .team-member:first-child {
	border-top: 0;
	padding-top: 0;
}

/* ⚠️ Здесь БЫЛ модификатор .team-member--lead: у первого человека толще
   и акцентнее линейка, крупнее портрет, крупнее имя и первый абзац описания.
   Полностью удалён 22.08.2026 по решению владельца («собственника жирным
   не выделяй, пусть будет как все»). PHP этот класс больше не печатает, мёртвых
   правил под него в файле не осталось — если снова увидишь --lead в разметке,
   значит кто-то откатил PHP, а не забыл CSS. Основание отмены — в team-members.php. */

/* Декоративный порядковый номер (.team-member__index) удалён 23.08.2026
   вместе с самим узлом в PHP — владелец попросил убрать нумерацию людей.
   Здесь были: базовое display:none (скрытие на 375), включение мелкой
   подписью на ≥768 и крупный номер-декор на ≥992. Все правила сняты;
   если снова увидишь .team-member__index в разметке, значит откатили PHP. */

/* --- скруглённо-квадратная маска портрета (T66) ---
   Кроп делает CSS, а не сервер: жёсткий квадратный кроп в медиатеке отрезает
   макушку у портрета, снятого не по центру, и отменить это уже нечем.
   Размер team-portrait — мягкий ресайз без кропа, кадрируем здесь.

   T66 (24.08.2026, по решению владельца): было border-radius: 50% (круг) —
   стало скруглённый квадрат. Радиус — общий токен проекта --case-radius
   (:root в style.css:2427 — 1.25rem, ≥768 1.5rem), тот же, что у всех
   плиток/карточек: панель «Команда» теперь скруглена в единый радиус с
   сеткой кейсов и панелью «О компании». Токен на :root, доступен и вне
   страницы кейса. Соотношение 1:1 держит aspect-ratio — портрет остаётся
   квадратным, меняются только углы. */
.team-section .team-member__photo {
	grid-area: photo;
	position: relative;
	overflow: hidden;
	width: var(--team-photo);
	aspect-ratio: 1 / 1;
	/* T67 (24.08.2026): дефолт снова КРУГ. Скруглённый квадрат — опциональный
	   модификатор .is-square (радиус --case-radius, тот же токен, что у плиток/
	   карточек). Переключается саб-полем crop_square на каждом человеке. */
	border-radius: 50%;
	background-color: var(--ctx-surface);           /* видно до загрузки картинки */
	/* inset-кольцо, а не border: бордер дал бы субпиксельный шов поверх фото,
	   внутреннее кольцо рисуется по внутреннему краю (по скруглённому контуру
	   маски, overflow:hidden) и шва не даёт.
	   Цвет — не --ctx-border, а прозрачный оттенок ТЕКСТА: линейка отделяет
	   поверхность от фона, а кольцу приходится отделять фотографию, и она
	   бывает темнее фона страницы (у нас такой портрет есть — тёмный фон
	   съёмки в тёмной теме сливался с фоном сайта). Оттенок ink в тёмной теме
	   светлый, в светлой тёмный, то есть кольцо всегда контрастнее снимка. */
	box-shadow: inset 0 0 0 1px var(--team-ring);
}

/* Скруглённо-квадратная маска — опция человека (саб-поле crop_square). Токен
   --case-radius общий для проекта (1.25rem, ≥768 1.5rem). Два класса на
   селекторе держат специфичность (0,2,0), как у базового правила выше. */
.team-section .team-member__photo.is-square {
	border-radius: var(--case-radius, 1.25rem);
}

/* T68 (24.08.2026, по решению владельца): у КВАДРАТНЫХ портретов (.is-square —
   Богдан Ядыкин, Александр Школьник) object-fit:cover зумил квадратный источник
   в 1.39× и срезал макушку. Круглые портреты (9 человек, без .is-square) легли
   идеально — их база выше НЕ трогаем (круг + cover эталон). Здесь ТОЛЬКО для
   is-square возвращаем исходный масштаб: object-fit:contain вписывает весь PNG
   (круглый вырез Ø420 на прозрачном поле 448×448) целиком в скруглённо-квадратную
   маску, без увеличения — макушка и запас поля сверху видны полностью. Высота
   картинки возвращается к 100% бокса (базовый параллакс-запас 116% для contain
   не нужен и увёл бы масштаб), центрирование остаётся тем же transform:-50%.
   Форма .is-square (скруглённый квадрат) сохранена правилом выше; поля, что
   даёт contain, ложатся на фон --ctx-surface бокса — это ок. Три класса в
   селекторе (.team-member__img внутри .is-square) держат специфичность выше
   базового двухклассового правила img. */
.team-section .team-member__photo.is-square .team-member__img,
.team-section .team-member__photo.is-square .team-member__img[src$=".svg"] {
	height: 100%;
	object-fit: contain;
	object-position: 50% 50%;
}

/* [src$=".svg"] в селекторе обязателен: глобальная страховка темы
   img[src$=".svg"] { width:100%; height:auto } имеет специфичность (0,1,1)
   и иначе раздула бы портрет, если кто-то зальёт SVG (как в cases-grid.css:71). */
/* [src$=".svg"] в селекторе обязателен: глобальная страховка темы
   img[src$=".svg"] { width:100%; height:auto } имеет специфичность (0,1,1)
   и иначе раздула бы портрет, если кто-то зальёт SVG (как в cases-grid.css:71). */
.team-section .team-member__img,
.team-section .team-member__img[src$=".svg"] {
	position: absolute;
	left: 0;
	top: 50%;
	width: 100%;
	/* Высота маски + запас под параллакс (по bleed/2 сверху и снизу).
	   Два неравенства, которые НЕЛЬЗЯ нарушить, меняя bleed или drift:
	     1) обычное прямоугольное фото (непрозрачное, cover заливает бокс):
	        drift ≤ bleed/2                     → 0.05 ≤ 0.10 ✓
	     2) портрет-вырез (круг Ø0.9375 холста, углы прозрачные): круг обязан
	        перекрыть маску в крайней фазе
	        0.46875·(1 + bleed) − drift ≥ 0.5   → 0.5625 − 0.05 = 0.5125 ✓
	   Нарушение (1) впустит в маску край фото, нарушение (2) — серп фона. */
	height: calc(100% * (1 + var(--team-img-bleed)));
	max-width: none;
	object-fit: cover;
	object-position: var(--team-focus, 50% 30%);
	/* Центрирование. Параллакс добавляется в этот же transform — другого
	   свойства мы в такт скроллу не трогаем (см. ниже). */
	transform: translate3d(0, -50%, 0);
}

/* Фолбэк без фото: инициалы в том же круге. Кегль считается от диаметра,
   поэтому работает и на 88px, и на 296px. */
.team-section .team-member__initials {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: calc(var(--team-photo) * 0.3);
	font-weight: 600;
	line-height: 1;
	letter-spacing: 0.02em;
	color: var(--team-quiet);
	user-select: none;
}

.team-section .team-member__id {
	grid-area: id;
	align-self: center;   /* на мобильном имя стоит рядом с кругом */
	min-width: 0;
	/* Та же общая мера, что у __text: имя/должность и описание/локация делят
	   один ограничитель ширины и расширяются синхронно (T25.1). */
	max-width: var(--team-text-measure);
}

.team-section .team-member__name {
	font-size: clamp(1.375rem, 2vw, 1.75rem);
	font-weight: 600;
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: var(--ctx-ink);
	margin: 0;
}

/* Должность — та же гарнитура, что имя (наследуется от body, SF UI Display),
   отличается ТОЛЬКО весом (400 vs 600) и кеглем (чуть мельче имени).
   Дополнение владельца T25 (ТЗ tz-team-layout §3): бывший «микро-кикер»
   (uppercase / ls 0.12em / акцентный --team-accent-text) заменён на обычный
   приглушённый текст. font-family не объявляем — единство гарнитуры
   с именем гарантируется наследованием, а не повтором. */
.team-section .team-member__role {
	margin: 0.25rem 0 0;
	font-size: clamp(1rem, 1.15vw, 1.125rem);
	font-weight: 400;
	text-transform: none;
	letter-spacing: normal;
	line-height: 1.3;
	color: var(--ctx-muted);
}

/* Правая колонка ряда целиком: описание + подпись «место дислокации».
   Обёртка нужна именно как область сетки — на ≥768 левая колонка это жёстко
   три строки (index / photo / id), четвёртой области под подпись в ряду нет,
   а класть подпись внутрь .team-member__bio нельзя: там wpautop-абзацы,
   и подпись должна жить даже у человека без описания. */
.team-section .team-member__text {
	grid-area: text;
	min-width: 0;
	/* Общая мера читаемости (см. --team-text-measure): описание + локация
	   не длиннее заголовка и наоборот — оба ограничителя одинаковы. */
	max-width: var(--team-text-measure);
}

.team-section .team-member__bio {
	min-width: 0;
}

/* --ctx-ink, а не --ctx-muted: описание — основной текст страницы,
   приглушённый на сайте занят служебным (figcaption, bottom_nav__label). */
/* max-width СНЯТ 24.08.2026 (T25.1): мера читаемости перенесена на всю правую
   колонку (.team-member__text / __id, --team-text-measure), чтобы описание
   и заголовок расширялись синхронно. Индивидуальный 62ch на абзаце делал
   описание уже имени. */
.team-section .team-member__bio p {
	margin: 0 0 0.625rem;
	font-size: clamp(1rem, 1.05vw, 1.0625rem);
	font-weight: 400;
	line-height: 1.6;
	color: var(--ctx-ink);
}

.team-section .team-member__bio p:last-child {
	margin-bottom: 0;
}

/* --- место дислокации ---
   Тихая подпись в подвале текстового блока (ТЗ tz-team-layout §5): иконка-пин
   + город обычным регистром, приглушённо. Бывший капс-лейбл «Место дислокации»
   убран из визуала — его роль (пометить, что это локация) взяла иконка-пин,
   а для скринридера остался visually-hidden лейбл в разметке.

   align-items: center (было baseline) — пин центрируется по строке города.
   Иконка и текст — flex-элементы: на узком экране города переносятся целой
   строкой, а не отрываются по слову от пина. */
.team-section .team-member__location {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	column-gap: 0.4375rem;
	row-gap: 0.125rem;
	margin: clamp(0.875rem, 1.6vw, 1.25rem) 0 0;   /* единый ритм с описанием */
	/* max-width снят: меру держит родитель .team-member__text (T25.1). Локация
	   и так внутри него — двойной ограничитель не нужен. */
	font-size: 0.9375rem;
	font-weight: 400;
	line-height: 1.4;
	color: var(--ctx-muted);
}

/* Человек без описания: подпись оказывается единственным содержимым колонки,
   и отбивка сверху ей уже не от чего. */
.team-section .team-member__location:first-child {
	margin-top: 0;
}

/* Пин — geo-маркер перед городом, красится currentColor = --ctx-muted (обе
   темы автоматически). flex:0 0 auto — не сжимается и не тянется. */
.team-section .team-member__location-icon {
	flex: 0 0 auto;
	width: 0.875em;
	height: 0.875em;
	color: var(--ctx-muted);
}

/* Города — обычным регистром: у Школьника их два через «;» («Торонто, Канада;
   Дубай, ОАЭ»). min-width: 0 обязателен — flex-элемент по умолчанию не сжимается
   уже своего контента, и длинный список городов вылез бы за колонку
   горизонтальным скроллом. Переносится значение штатно, по пробелам. */
.team-section .team-member__location-value {
	min-width: 0;
	letter-spacing: normal;
	text-wrap: pretty;
}


/* ============================================================
   ≥768: две колонки, фото слева
   T25.1 (замечание владельца «текст сильно уехал вправо, сделай шире /
   ближе к фото»): было 5fr / 7fr — левая колонка ≈460px под фото 208px,
   разница ≈250px уходила в пустоту и толкала текст вправо, а правая колонка
   оказывалась узкой. Стало: левая колонка ровно под фото (auto = ширина
   .team-member__photo, тот же clamp 120–208px), правая — minmax(0, 1fr),
   то есть ВСЁ оставшееся место. Между ними только --team-gap. Меру строки
   текста по-прежнему держит своя, 62ch на .team-member__bio p — так что шире
   комфортного текст не растянется, но и не поджат. Медиазапроса на 992
   не нужно: колонки те же, размер фото тянет clamp().
   ============================================================ */

@media (min-width: 768px) {
	.team-section {
		--team-photo: clamp(120px, 15vw, 208px);

		/* L2 включается только здесь. На узком экране круг стоит вплотную
		   к имени и его дрейф на ±10px читается дрожанием, а не глубиной.
		   L1 (внутри маски) работает везде. L3 (номер) снят вместе
		   с нумерацией людей 23.08.2026. */
		--team-drift-frame: clamp(0px, 0.8vw, 10px);
	}

	/* Раскладка ряда (ТЗ tz-team-layout §2): совмещаем «текст выровнен по фото»
	   и «фото отцентровано относительно текста», разведя их по ролям областей.
	   Левая колонка (auto, под фото) — фото на ОБЕ строки; правая (1fr, остаток) —
	   строка 1 имя/должность (__id), строка 2 описание/локация (__text).
	     • align-items: start держит верхнюю кромку правой колонки на верхней
	       линии ряда → верх имени = верх фото = стартовая линия под линейкой
	       («текст выровнен по фото»).
	     • __photo { align-self: center } центрирует круг по высоте всей левой
	       области (обе строки) → фото по центру пары «имя/должность + описание/
	       локация» («фото отцентровано относительно текста»).
	   DOM плоский (__photo / __id / __text — три прямых ребёнка <li>),
	   визуальный поток «имя → должность → описание → локация» собирает grid,
	   а не вложенность — узлы не дублируются. */
	.team-section .team-member {
		/* auto = ширина фото (левая область = .team-member__photo, а он
		   width: --team-photo, макс. 208px), minmax(0, 1fr) = весь остаток
		   под текст. Раньше 5fr/7fr раздували левую колонку до ≈460px. */
		grid-template-columns: auto minmax(0, 1fr);
		grid-template-areas:
			"photo id"
			"photo text";
		grid-template-rows: auto 1fr;
		align-items: start;
		/* Вертикальные зазоры внутри правой колонки задаются margin'ами
		   её элементов (должность → margin-top, локация → margin-top):
		   row-gap раздвинул бы и левую колонку с фото. */
		row-gap: 0;
	}

	/* Имя/должность — строка 1 правой колонки, прижаты к низу своей auto-строки,
	   то есть вплотную к описанию ниже (единый вертикальный поток). Верх строки
	   при этом стоит на верхней линии ряда — этим и держится выравнивание по фото. */
	.team-section .team-member__id {
		align-self: end;
		margin-top: 0;
	}

	/* Описание/локация — строка 2, от верха своей ячейки: продолжают поток
	   сразу под именем/должностью. Центрируется не текст, а ФОТО (см. выше),
	   поэтому здесь start, а не center. */
	.team-section .team-member__text {
		align-self: start;
	}

	/* Фото — по центру всей левой области (обе grid-строки), напротив центра
	   текстового блока. */
	.team-section .team-member__photo {
		align-self: center;
	}
}


/* ============================================================
   Крупный номер ряда (декор левой колонки на ≥992) удалён 23.08.2026
   вместе со всей нумерацией людей — владелец попросил убрать номера.
   Раньше здесь .team-member__index подавался крупным кеглем (clamp 3–4.5rem,
   тон --team-index-ghost) как верхний якорь ряда. Узел и все его правила сняты.
   ============================================================ */


/* ============================================================
   Единый тон для разнокалиберных фото — опция блока (as-is / mono)
   ============================================================ */

/* Фильтр висит на ОБЁРТКЕ, не на движущемся <img>: обёртка при параллаксе
   не анимируется, фильтр считается один раз и заодно даёт картинке
   собственный слой композитора. filter создаёт containing block для
   position:absolute — обёртка и так position:relative, конфликта нет. */
/* :not(--noimg) — круг с инициалами красится токенами и обесцвечивать его
   незачем: grayscale увёл бы поверхность из палитры страницы в серый. */
.team-section--mono .team-member:not(.team-member--noimg) .team-member__photo {
	filter: grayscale(1) contrast(1.04);
}

/* transition: filter объявлен ТОЛЬКО внутри hover-медиазапроса. На тач-
   устройствах hover залипает после тапа, и фото осталось бы цветным навсегда —
   рассинхрон с соседями. */
@media (hover: hover) and (pointer: fine) {
	.team-section--mono .team-member:not(.team-member--noimg) .team-member__photo {
		transition: filter 0.4s ease;
	}

	.team-section--mono .team-member:not(.team-member--noimg) .team-member__photo:hover {
		filter: grayscale(0) contrast(1);
	}
}


/* ============================================================
   ПАРАЛЛАКС — три слоя, текст неподвижен (ТЗ §5)

   L1  <img> внутри маски   −p   0.18·D   главный эффект: круг стоит в макете,
                                          лицо «плавает» внутри — окно в глубину
   L2  сама маска           +p   ≤10px    контрслой: без него L1 читается
                                          как «картинка съехала», а не как глубина
   L3  номер 01…05          −p   ≤8px     третья скорость, склеивает левую
                                          колонку в одну сцену
   —   имя/должность/текст   0             двигать читаемый текст на скролле —
                                          главный грех параллакса

   Движок — два пути с ОДНИМ источником амплитуд (--team-drift-*):
   A) CSS scroll-driven animations — вне главного потока, JS не участвует;
   B) rAF + IntersectionObserver в team-members.js — Firefox и старьё.
   Второго места, где записаны числа, быть не должно.
   ============================================================ */

@supports (animation-timeline: view()) {
	@media not (prefers-reduced-motion: reduce) {
		.team-section .team-member__img,
		.team-section .team-member__photo {
			/* Именованный таймлайн ряда, а не animation-timeline: view() на самом
			   слое. Принципиально: субъектом должен быть РЯД. Картинка на 50%
			   выше маски, её собственный cover-диапазон не совпал бы
			   с диапазоном ряда и слои разъехались бы по фазе.
			   Имя ищется вверх по предкам, timeline-scope не нужен. */
			animation-timeline: --team-row;
			animation-range: cover 0% cover 100%;
			animation-timing-function: linear;
			animation-fill-mode: both;
			/* auto = «длительность равна длительности таймлайна». Начальное
			   значение animation-duration в CSS Animations 2 уже auto, но пишем
			   явно: конкретное время (даже 1ms) схлопнуло бы всю анимацию
			   в начало диапазона, и слой стоял бы в крайней фазе. */
			animation-duration: auto;
		}

		.team-section .team-member__img {
			animation-name: team-drift-img;
		}

		.team-section .team-member__photo {
			animation-name: team-drift-frame;
		}
	}
}

/* p = положение ряда: +1 — только входит снизу, 0 — центр в центре вьюпорта,
   −1 — ушёл вверх. Отсюда from = p+1, to = p−1. */

@keyframes team-drift-img {   /* −p: на входе картинка поджата вверх и «отстаёт» */
	from { transform: translate3d(0, calc(-50% - var(--team-drift-img)), 0); }
	to   { transform: translate3d(0, calc(-50% + var(--team-drift-img)), 0); }
}

@keyframes team-drift-frame { /* +p: контрход, быстрее страницы */
	from { transform: translate3d(0, var(--team-drift-frame), 0); }
	to   { transform: translate3d(0, calc(-1 * var(--team-drift-frame)), 0); }
}

/* team-drift-mark удалён вместе с номером ряда (23.08.2026). */

/* Путь B. JS пишет ОДНУ custom property на человека (--p), слои её наследуют.
   Амплитуды те же самые. Анимируется только transform: translate3d(...) —
   ни top, ни margin, ни background-position (грех старого parallax.js). */
@supports not (animation-timeline: view()) {
	/* Три класса, а не два: базовое правило портрета имеет вариант
	   .team-member__img[src$=".svg"] со специфичностью (0,2,1) и перебило бы
	   двухклассовое — портрет-SVG остался бы без параллакса. */
	.team-section .team-member .team-member__img {
		transform: translate3d(0, calc(-50% - var(--p, 0) * var(--team-drift-img)), 0);
	}

	.team-section .team-member__photo {
		transform: translate3d(0, calc(var(--p, 0) * var(--team-drift-frame)), 0);
	}

	/* will-change ВРЕМЕННЫЙ: класс вешает IO на входе ряда и снимает на выходе.
	   Постоянный will-change на пятнадцати слоях — выделенная GPU-память
	   впустую. На пути A он не нужен вовсе: браузер сам поднимает слой
	   под scroll-таймлайн. */
	.team-section .team-member.is-parallaxing .team-member__img {
		will-change: transform;
	}
}


/* ============================================================
   Появление при скролле — отдельная механика от параллакса.
   Анимируется .team-member, параллакс — её потомки: разные элементы,
   transform не конфликтует.
   Класс .reveal-ready вешает JS, поэтому без JS и при reduce люди просто
   видны, а не спрятаны навсегда. Длительность ОБЯЗАНА совпадать
   с REVEAL_MS в team-members.js.
   ============================================================ */

.team-section .team-list.reveal-ready .team-member {
	opacity: 0;
	transform: translateY(16px);
	transition: opacity 0.45s cubic-bezier(0.22, 0.61, 0.36, 1),
		transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
	transition-delay: 0s;
}

/* Шахматка — только на первом экране (класс вешает JS): ниже задержка
   копилась бы и человек «догонял» бы пользователя после того, как тот долистал. */
.team-section .team-list.reveal-ready .team-member.is-stagger {
	transition-delay: calc(min(var(--i, 0), 3) * 60ms);
}

.team-section .team-list.reveal-ready .team-member.is-inview {
	opacity: 1;
	transform: none;
}

/* Мгновенный показ (быстрый флик, якорь, восстановление скролла): ряд уже
   в кадре, анимировать его — значит показать дырку. Класс живёт один кадр. */
.team-section .team-list.reveal-ready .team-member.is-instant {
	transition: none;
}


/* ============================================================
   prefers-reduced-motion — гашение ПОЛНОЕ, а не ослабление.
   Гард обязателен и здесь, и в JS: подключённый на сайте AOS этот
   медиазапрос не обрабатывает вовсе (в его CSS его просто нет).
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
	.team-section {
		--team-drift-img: 0px;
		--team-drift-frame: 0px;
	}

	/* Центрирование ОСТАЁТСЯ: transform:none сдвинул бы картинку вниз
	   на пол-её-высоты и в маске оказался бы низ кадра. */
	.team-section .team-member__img {
		animation: none !important;
		transform: translate3d(0, -50%, 0) !important;
	}

	.team-section .team-member__photo {
		animation: none !important;
		transform: none !important;
	}

	.team-section--mono .team-member .team-member__photo {
		transition: none !important;
	}

	.team-section .team-list.reveal-ready .team-member,
	.team-section .team-list.reveal-ready .team-member.is-stagger,
	.team-section .team-list.reveal-ready .team-member.is-inview {
		opacity: 1;
		transform: none;
		transition: none;
		transition-delay: 0s;
	}
}


/* ============================================================
   Редактор блоков. У редактора свой контейнер прокрутки, и scroll-таймлайн
   там либо врёт, либо держит слои в крайней фазе — фото выглядело бы
   «съехавшим» ещё до публикации. Превью показываем статикой.
   Специфичность (0,3,0) перебивает правила выше без !important.
   ============================================================ */

.wp-admin .team-section .team-member__img {
	animation: none;
	transform: translate3d(0, -50%, 0);
}

.wp-admin .team-section .team-member__photo {
	animation: none;
	transform: none;
}
