/* sofyamatveeva.com — вёрстка сайта Софьи Матвеевой.
   Все значения живут в :root и описаны в DESIGN.md. Правило одно:
   в разметке и в правилах ниже стоят токены, а не числа и цвета. */

/* ── шрифт ──────────────────────────────────────────────────────────── */
/* Файлы кладёт scripts/install-font.mjs из архива с abcdinamo.com/free/areal.
   Если их нет, срабатывает fallback на Arial — ровно прежний вид.
   Переменная версия: оси wght 400–700, slnt -12…0, DRKM 0–1 (тёмная тема). */
@font-face {
  font-family: 'ABC Areal';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/ABCAreal-Variable.woff2') format('woff2');
}
/* Моноширинный — только для колонки годов в CV: цифры должны стоять ровно. */
@font-face {
  font-family: 'ABC Areal Mono';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/ABCArealMono-Variable.woff2') format('woff2');
}

/* Статические начертания — на случай, если переменный файл не отдастся. */
@font-face {
  font-family: 'ABC Areal Static';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ABCAreal-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'ABC Areal Static';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/ABCAreal-Bold.woff2') format('woff2');
}

/* ── токены ─────────────────────────────────────────────────────────── */
/* Единственное место в файле, где стоят сырые значения. Подробности,
   контрасты и область применения каждого токена — в DESIGN.md. */
:root {
  --font: 'ABC Areal', 'ABC Areal Static', Arial, Helvetica, sans-serif;
  --font-mono: 'ABC Areal Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* цвет */
  --ink:          #000;       /* 21:1  — основной текст, заголовки */
  --ink-muted:    #474744;    /* 9.3:1 — аннотации, цитаты, подробности */
  --ink-faint:    #6e6e69;    /* 5.1:1 — подписи, годы, роли */
  --line:         #dcdcd8;    /* линейки между строками, декоративные */
  --line-strong:  #8a8a85;    /* 3.5:1 — подчёркивание ссылок, органы управления */
  --paper:        #fff;
  --paper-sunk:   #f5f5f3;    /* подсветка плитки при наведении */
  --focus:        #2015ff;
  --scrim:        rgba(0, 0, 0, .6);
  --tap-highlight: rgba(255, 255, 255, .1);

  /* кегль */
  --fs-label: 12px; --fs-small: 14px; --fs-base: 16px; --fs-body: 18px;
  --fs-lead: 20px;  --fs-title: 26px;
  --fs-display: clamp(30px, 4vw, 46px);
  --fs-logo: 42px;  --fs-logo-sm: 24px;

  /* интерлиньяж */
  --lh-display: 1.05; --lh-tight: 1.25; --lh-normal: 1.45; --lh-loose: 1.6;

  /* трекинг */
  --ls-caps: .08em; --ls-display: -.01em;

  /* отступы, кратно 4 */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px; --s-5: 20px; --s-6: 24px;
  --s-7: 32px; --s-8: 40px; --s-9: 48px; --s-10: 64px;
  --s-page: 120px;            /* вертикальный ритм полосы */

  /* сетка */
  --page: 1200px; --gutter: 20px; --gap-cards: 40px;
  --header: 80px;      /* фиксированная шапка: верхний отступ полосы её перекрывает */
  --rail: 100px;       /* плашка с именем вдоль левого края */
  --slider-lane: 64px; /* полоса под стрелку карусели, сбоку от кадра */
  --card-min: 220px;   /* уже карточки название «Treplev.Sample.» рвётся посреди слова */

  /* движение */
  --dur: .25s; --dur-fast: .15s; --ease: ease-in-out;

  /* слои */
  --z-ui: 10; --z-header: 100; --z-overlay: 1000;
}

/* ── основа ─────────────────────────────────────────────────────────── */
* { -webkit-tap-highlight-color: var(--tap-highlight); }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ink); text-decoration: none; }
a:focus-visible,
button:focus-visible { outline: auto 1px var(--focus); outline-offset: var(--s-1); }

img:not([src]) { visibility: hidden; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Ссылка «к содержанию» спрятана, пока её не поймает фокус. Спрятанная
   всегда — а именно так она и жила под .visually-hidden — она бесполезна. */
.skip-link {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.skip-link:focus {
  width: auto; height: auto; margin: 0; overflow: visible; clip-path: none;
  left: var(--s-5); top: var(--s-5); z-index: var(--z-overlay);
  padding: var(--s-2) var(--s-4); font-size: var(--fs-base);
  background-color: var(--paper); border: 1px solid var(--ink);
}

/* ── ссылки и стрелка ───────────────────────────────────────────────── */
/* Подчёркивание одно на всех: text-decoration, а не border-bottom, —
   оно не наезжает на выносные элементы и правильно разрывается при
   переносе строки. */
.work-head__link a,
.about__review-title a,
.cv__ttl a,
.cv__contacts a {
  text-decoration: underline; text-decoration-color: var(--line-strong);
  text-underline-offset: var(--s-1); text-decoration-thickness: 1px;
  transition: text-decoration-color var(--dur-fast) var(--ease);
}
.work-head__link a:hover,
.about__review-title a:hover,
.cv__ttl a:hover,
.cv__contacts a:hover { text-decoration-color: var(--ink); }

/* Стрелка — знак, а не слово: альтернативный текст пустой. Один кегль,
   один цвет, одно правило на все три места, где она встречается. */
.work-head__link a::after,
.about__review-title a::after,
.cv__ttl a::after {
  content: "↗" / ""; font-size: .7em; vertical-align: super; margin-left: .25em;
  color: var(--ink-faint); text-decoration: none; display: inline-block;
}

/* ── движение ───────────────────────────────────────────────────────── */
/* Если человек попросил систему убрать анимацию — убираем: карточки,
   плитка, ссылки, зум и карусель переключаются мгновенно. Карусель
   читает ту же настройку в gallery.js, чтобы не ждать transitionend.
   Блок стоит здесь, среди сквозных правил, а не в конце файла: он
   побеждает !important, а не порядком, и от места не зависит. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* ── сетка ──────────────────────────────────────────────────────────── */
/* Полоса одна на весь сайт: мера из --page, поля у краёв из --gutter.
   Брейкпоинты переменными быть не могут — CSS не подставляет var() в
   условие @media, — поэтому три числа описаны в DESIGN.md. */
.container {
  width: 100%; max-width: var(--page); margin-inline: auto;
  padding-inline: var(--gutter); box-sizing: border-box;
}

/* Плашка с именем стоит поверх левого края, а полоса центрируется по окну.
   Пока поле у края уже плашки (окно 961–1159 и 1201–1359), текст и левая
   стрелка карусели уходили под неё. Отступ на ширину плашки с обеих сторон
   держит полосу по центру и вне плашки; на широком окне ничего не меняет. */
main { padding-inline: var(--rail); }

@media screen and (max-width: 1200px) {
  :root { --page: 960px; --gutter: 10px; --gap-cards: 20px; }
}
@media screen and (max-width: 960px) {
  :root { --page: 640px; --gutter: 20px; --slider-lane: 40px; }
  main { padding-inline: 0; }   /* плашки ниже 960 нет */
}
@media screen and (max-width: 600px) {
  /* На телефоне стрелок нет — листают свайпом, а кадр забирает всю ширину. */
  :root { --s-page: 64px; --slider-lane: 0px; }
}

/* ── ритм полосы ────────────────────────────────────────────────────── */
/* Отступы живут на самих блоках, а не на классах-утилитах: из десяти
   классов pt-N и pb-N в собранный HTML доезжали четыре сочетания,
   а манифестное значение сборка и так не читала. */
.works        { padding: var(--s-page) 0; }
.work-credits { padding: var(--s-page) 0 var(--s-7); }
.work-slides  { padding-bottom: var(--s-page); }
.work-about   { padding-bottom: var(--s-page); }
.cv-page      { padding: var(--s-page) 0; }

/* ── шапка сайта ────────────────────────────────────────────────────── */
/* десктоп: имя вертикальной плашкой вдоль левого края (t453) */
.logo-side {
  position: fixed; left: 0; bottom: 0; width: 100vh; height: var(--rail);
  z-index: var(--z-header); margin: 0; padding: 0; list-style: none;
  background-color: var(--paper); text-align: center;
  display: table; table-layout: fixed;
  transform-origin: left bottom;
  transform: rotate(-90deg) translateY(100%);
}
.logo-side__item { display: table-cell; text-align: center; vertical-align: middle; }
.logo-side__link {
  font-size: var(--fs-logo); font-weight: 700; text-transform: uppercase; color: var(--ink);
}

/* мобильная шапка: имя по центру (t454) */
.logo-top { display: none; width: 100%; }
/* Отступы имени взяты из шкалы. В наследстве Тильды их было три слоя
   подряд — padding у обёртки, padding у внутренней, margin у самого
   текста, — и шапка вырастала до 352 пикселей при 55 пикселях
   содержимого. */
.logo-top__inner { width: 100%; padding: var(--s-10) 0 var(--s-5); }
.logo-top__wrapper { width: 100%; }
.logo-top__text {
  display: inline-block; font-size: var(--fs-logo-sm); font-weight: 700; color: var(--ink);
  margin: 0; padding: 0; white-space: normal;
}

/* меню CV / Contacts (t456) */
/* Фон прозрачный — решение автора. Плата за это описана в DESIGN.md:
   шапка фиксированная, поэтому содержимое страницы проезжает сквозь её
   текст при прокрутке. Не «исправлять» заливкой, не спросив. */
.topmenu {
  position: fixed; top: 0; left: 0; width: 100%; height: var(--header); z-index: var(--z-header);
  background-color: transparent;
}
/* Одна строка, один центр. Потомок у строки один — меню, поэтому оно
   прижато к правому краю. Раньше здесь была таблица Тильды и пустой
   распорный div с кеглем 24px: он тянул базовую линию вниз, а соседнюю
   ссылку вверх. Распорка удалена, выравнивание держит флексбокс. */
.topmenu__inner {
  display: flex; align-items: center; justify-content: flex-end;
  width: 100%; height: var(--header);
}

.topmenu__right { padding-right: var(--s-8); text-align: right; }
.topmenu__list { list-style: none; margin: 0; padding: 0; }
.topmenu__item { display: inline-block; margin: 0; white-space: nowrap; padding: 0 var(--s-4); }
.topmenu__item:first-child { padding-left: 0; }
.topmenu__item:last-child { padding-right: 0; }
.topmenu__link { font-size: var(--fs-body); font-weight: 400; color: var(--ink); }
.topmenu__link[aria-current="page"] { opacity: .7; }

@media screen and (max-width: 1200px) {
  .topmenu__right { padding-right: var(--s-5); }
}
@media screen and (max-width: 960px) {
  /* Скрыт весь <nav> с плашкой, а не только список внутри: иначе пустая
     обёртка осталась бы третьим элементом флексбокса, и space-between
     растащил бы имя и меню по краям. */
  .logo-side-nav { display: none; }
  /* Шапка — одна строка с переносом: на 768 имя и меню стоят рядом на
     общей базовой линии, на 390 меню переезжает под имя. При переносе
     space-between оставляет одиночный элемент у левого края, поэтому
     оба прижаты к --gutter — вровень с текстом страницы. */
  /* Класс, а не голый header: тегом <header> размечены ещё титры работы
     и шапка CV, и это правило сдвигало их на --gutter внутрь полосы. */
  .site-header {
    position: relative;
    display: flex; flex-wrap: wrap; align-items: baseline;
    justify-content: space-between;
    gap: var(--s-2) var(--s-6);
    padding: var(--s-6) var(--gutter) 0;
    /* та же полоса, что у .container: на планшете шапка иначе шла бы
       от края экрана, а текст страницы — от края полосы в 640 */
    max-width: var(--page); margin-inline: auto; box-sizing: border-box;
  }
  .logo-side { display: none; }
  .logo-top { display: block; width: auto; }
  .logo-top__inner { width: auto; padding: 0; }
  .logo-top__wrapper { width: auto; }
  /* width сбрасываем: с базовым 100% флекс-элемент занимал всю строку
     и меню переносилось даже там, где рядом с именем есть место. */
  .topmenu {
    position: static; width: auto; height: auto;
    display: block; margin: 0; padding: 0;
  }
  .topmenu__inner { display: block; width: 100%; height: auto; }
  .topmenu__right { padding: 0; text-align: left; }
  .topmenu__list { display: block; margin-left: 0; }
  /* Пункты остаются в строку (базовый inline-block); вертикальная
     подушка даёт площадь нажатия 34px по высоте. */
  .topmenu__item { padding: var(--s-1) var(--s-4) var(--s-1) 0; }
  .topmenu__item:last-child { padding-right: 0; }
}

/* ── главная: карточки работ ────────────────────────────────────────── */
/* Колонок столько, сколько влезает карточек не уже --card-min: на полной
   полосе это четыре, на окнах 961–1159 и 1201–1239 — три. Жёсткие четыре
   колонки сжимали карточку там до 170–210px, и название рвалось посреди
   слова. Последний ряд неполный — карточка встаёт в свою колонку, а не
   растягивается. Ниже 960 колонки встают друг под друга. */
.works__row {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
  gap: var(--gap-cards);
}
@media screen and (max-width: 960px) { .works__row { grid-template-columns: minmax(0, 1fr); } }

.work-card { overflow: hidden; text-align: center; }

.work-card__link { display: block; }
.work-card__table {
  display: flex; flex-direction: column;
  width: 100%; height: 260px; position: relative; overflow: hidden;
}
.work-card__cell { display: block; width: 100%; margin-top: auto; margin-bottom: auto; }
.work-card__bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center center;
}
/* Затемнение и название проявляются при наведении (t401__show_hover),
   а на узких экранах видны всегда — как и на прежнем сайте. */
.work-card__overlay {
  position: absolute; inset: 0; opacity: 0;
  background-color: var(--scrim);
  transition: opacity var(--dur) var(--ease);
}
.work-card__textwrapper {
  padding: var(--s-5); position: relative; overflow-wrap: anywhere; opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.work-card__content { margin: var(--s-7) auto; position: relative; }
.work-card__title {
  /* в разметке было 500, но Times рисовал 400 — повторяем то, что видно */
  color: var(--paper); font-size: var(--fs-body); font-weight: 400; line-height: var(--lh-normal); text-transform: uppercase;
}
.work-card__cell:hover .work-card__overlay,
.work-card__cell:hover .work-card__textwrapper,
.work-card__link:focus-visible .work-card__overlay,
.work-card__link:focus-visible .work-card__textwrapper { opacity: 1; }
@media screen and (max-width: 960px) {
  .work-card__overlay,
  .work-card__textwrapper { opacity: 1 !important; }
}

/* Незаметный вход в админку внизу главной. */
.admin-dot { margin: 0; padding: 0 0 var(--s-7); text-align: center; line-height: 1; }
.admin-dot a {
  display: inline-block; padding: var(--s-2) var(--s-4); font-size: var(--fs-lead);
  color: var(--line); transition: color var(--dur) var(--ease);
}
.admin-dot a:hover, .admin-dot a:focus-visible { color: var(--ink-faint); }

/* ── работа: титры ──────────────────────────────────────────────────── */
/* Титры были четырьмя строками текста подряд. Теперь это титул: жанр
   надзаголовком, название крупно, выходные данные и роль под ним. */
.work-head { display: flex; flex-direction: column; padding-bottom: var(--s-7); }
/* Если у работы есть аннотация — титры слева, она справа. */
.work-head--split {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s-8) var(--s-9);
  align-items: start;
}
.work-head__main { display: flex; flex-direction: column; }
.work-head__lede { padding-top: var(--s-1); }
.work-head__lede p { margin: 0; font-size: var(--fs-body); line-height: var(--lh-loose); color: var(--ink-muted); }
.work-head__genre {
  margin: 0 0 var(--s-3); font-family: var(--font-mono); font-size: var(--fs-label);
  letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--ink-faint);
}
.work-head__title {
  margin: 0; font-size: var(--fs-display); line-height: var(--lh-display);
  font-weight: 700; letter-spacing: var(--ls-display);
}
.work-head__lines { display: flex; flex-direction: column; margin-top: var(--s-5); max-width: 72ch; }
.work-head__meta { margin: 0 0 var(--s-1); font-size: var(--fs-body); line-height: var(--lh-normal); color: var(--ink-muted); }
.work-head__role {
  margin: var(--s-3) 0 0; font-family: var(--font-mono); font-size: var(--fs-label);
  letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--ink-faint);
}
/* Примечание после строки роли не должно к ней липнуть. */
.work-head__role + .work-head__meta { margin-top: var(--s-3); }
.work-head__link { margin: var(--s-3) 0 0; }
.work-head__link a {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--ink-faint);
}
.work-head__link a:hover { color: var(--ink); }
@media screen and (max-width: 960px) {
  .work-head--split { grid-template-columns: 1fr; gap: var(--s-6); }
  .work-head__lede { padding-top: 0; }
  .work-head__lede p { font-size: var(--fs-base); }
}
@media screen and (max-width: 600px) {
  .work-head__meta { font-size: var(--fs-base); }
}

/* ── работа: слайдшоу ───────────────────────────────────────────────── */
.slider { position: relative; overflow: hidden; }
.slider__main { position: relative; }
/* Кадр ужат на две полосы по краям: стрелки стоят в них, на бумаге,
   а не поверх фотографии — на светлом кадре их было не видно. */
.slider__container {
  position: relative; width: 100%;
  padding-inline: var(--slider-lane); box-sizing: border-box;
}

.slider__viewport { position: relative; overflow: hidden; }
/* Горизонтальный жест отдаём свайпу в gallery.js, вертикальный остаётся
   прокрутке страницы. Без этого мобильный браузер забирает жест себе,
   шлёт pointercancel, и кадр не перелистывается. */
.slider__container { touch-action: pan-y; }
.slider__track { display: flex; transition: transform var(--dur) var(--ease); will-change: transform; }
.slider__item { flex: 0 0 100%; width: 100%; overflow: hidden; }
.slider__wrapper { text-align: center; }
.slider__frame { position: relative; aspect-ratio: 1160 / 700; }
.slider__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: 50%;
  cursor: zoom-in;
}

.slider__arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: none; border: none; padding: 0; margin: 0;
  cursor: pointer; z-index: var(--z-ui); color: var(--ink);
  width: var(--slider-lane); display: flex; align-items: center; justify-content: center;
}
.slider__arrow svg { display: block; width: 18px; height: auto; }
.slider__arrow--left { left: 0; }
.slider__arrow--left svg { transform: rotate(180deg); }
.slider__arrow--right { right: 0; }
@media screen and (max-width: 600px) { .slider__arrow { display: none; } }

/* Номер кадра под фотографией — тем же моноширинным, что жанр и роль
   в титрах: цифры не прыгают, когда 9 сменяется на 10. */
.slider__counter {
  margin: 0; padding-top: var(--s-4); text-align: center;
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}

/* ── работа: описание спектакля ─────────────────────────────────────── */
/* Блок под слайдшоу: аннотация, состав таблицей, цитаты критики.
   Набран в том же ключе, что и CV, — мелкие капительные заголовки,
   моноширинные подписи. */
.about { display: flex; flex-direction: column; gap: var(--s-9); }

.about__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--s-8) var(--s-9); align-items: start;
}

.about__block { display: flex; flex-direction: column; gap: var(--s-4); }
.about__h {
  margin: 0; font-size: var(--fs-small); font-weight: 700; letter-spacing: var(--ls-caps); text-transform: uppercase;
  border-bottom: 1.5px solid var(--ink); padding-bottom: var(--s-2);
}

.about__pairs { margin: 0; display: flex; flex-direction: column; }
.about__pair { padding: var(--s-2) 0; border-bottom: 1px solid var(--line); }
.about__pair:last-child { border-bottom: none; }
.about__pair dt {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: var(--s-1);
}
.about__pair dd { margin: 0; font-size: var(--fs-base); line-height: var(--lh-normal); }

/* пресса: выходные данные колонкой слева, заголовок-ссылка и цитата справа —
   тот же приём, что в списке работ в CV. Никаких линеек и отступов внутри:
   всё висит на одной вертикали, поэтому блок читается сразу. */
.about__reviews { display: flex; flex-direction: column; }
.about__review {
  display: grid; grid-template-columns: 13rem minmax(0, 1fr); gap: 0 var(--s-8);
  padding: var(--s-6) 0; border-bottom: 1px solid var(--line);
}
.about__review:first-child { padding-top: var(--s-1); }
.about__review:last-child { border-bottom: none; padding-bottom: 0; }

/* Выходные данные занимают всю высоту записи, иначе они задавали бы высоту
   первой строки сетки — и у короткого заголовка между ним и цитатой зияла бы
   дыра в полсотни пикселей. Справа максимум три элемента: заголовок,
   цитата, перевод. */
.about__review-meta {
  grid-column: 1; grid-row: 1 / span 3; align-self: start;
  margin: var(--s-1) 0 0; display: flex; flex-direction: column; gap: var(--s-1);
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--ink-faint); line-height: var(--lh-normal);
}
.about__review-meta span:first-child { color: var(--ink-muted); }

/* Мера: в `ch` она считается от кегля самого элемента, поэтому одно и то же
   число даёт одинаковую длину строки и в заголовке 20px, и в переводе 14px.
   Сетка остаётся широкой — просто текст в правой колонке не тянется во всю. */
.about__review-title {
  grid-column: 2; margin: 0; font-size: var(--fs-lead); line-height: var(--lh-tight); font-weight: 400;
  max-width: 52ch; text-wrap: balance;
}

.about__review-quote {
  grid-column: 2; margin: var(--s-3) 0 0; font-size: var(--fs-base); line-height: var(--lh-loose); color: var(--ink-muted);
  max-width: 59ch; text-wrap: pretty; hyphens: auto;
}
.about__trans {
  grid-column: 2; margin: var(--s-2) 0 0; font-size: var(--fs-small); line-height: var(--lh-loose); color: var(--ink-faint);
  max-width: 54ch; text-wrap: pretty; hyphens: auto;
}

@media screen and (max-width: 960px) {
  .about { gap: var(--s-8); }
  .about__cols { gap: var(--s-7); }
  .about__review { grid-template-columns: 1fr; gap: 0; padding: var(--s-5) 0; }
  .about__review-meta {
    grid-column: 1; grid-row: auto; flex-direction: row; flex-wrap: wrap;
    gap: 0 var(--s-3); margin: 0 0 var(--s-2);
  }
  .about__review-meta span + span::before { content: '· '; color: var(--ink-faint); }
  .about__review-title { grid-column: 1; font-size: var(--fs-body); }
  .about__review-quote, .about__trans { grid-column: 1; }
}

/* ── CV ─────────────────────────────────────────────────────────────── */
/* Таблицей: год — что — роль. Набрано тем же Areal, годы моноширинным,
   чтобы цифры в колонке стояли столбиком. */
.cv { display: flex; flex-direction: column; gap: var(--s-10); }

/* Портрет высокий, текста рядом мало — равняем по нижнему краю, иначе
   справа от фотографии зияет дыра. */
.cv__intro { display: flex; gap: var(--s-8); align-items: flex-end; }
.cv__photo { width: clamp(260px, 27vw, 380px); flex: none; display: block; }
.cv__lede { display: flex; flex-direction: column; gap: var(--s-4); padding-bottom: var(--s-2); flex: 1 1 auto; min-width: 0; }
.cv__role {
  margin: 0; font-size: var(--fs-title); line-height: var(--lh-tight); font-weight: 700;
  letter-spacing: var(--ls-display);
}
.cv__bio { margin: 0; font-size: var(--fs-body); line-height: var(--lh-loose); color: var(--ink-muted); max-width: 54ch; }

.cv__section { display: flex; flex-direction: column; gap: var(--s-5); }
.cv__sechead {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  border-bottom: 1.5px solid var(--ink); padding-bottom: var(--s-2);
}
.cv__sechead h2 {
  margin: 0; font-size: var(--fs-small); font-weight: 700;
  letter-spacing: var(--ls-caps); text-transform: uppercase;
}
.cv__seccount {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* список постановок: год · название и подробности · роль */
.cv__work {
  display: grid; grid-template-columns: 4.5rem 1fr 11rem;
  gap: var(--s-1) var(--s-6); padding: var(--s-3) 0; border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.cv__work:last-child { border-bottom: none; }
.cv__work--cont .cv__yr { visibility: hidden; }
.cv__yr {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.cv__ttl { font-size: var(--fs-body); line-height: var(--lh-tight); }
.cv__job {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--ink-faint); text-align: right; line-height: var(--lh-normal);
}
.cv__meta { grid-column: 2; font-size: var(--fs-small); line-height: var(--lh-normal); color: var(--ink-muted); }
/* Наклон — ось slnt переменного шрифта. Синтетический курсив здесь
   рисовался от безысходности: italic-файла нет, все четыре @font-face
   объявлены normal. font-synthesis запрещает браузеру подменять. */
.cv__note {
  grid-column: 2; font-size: var(--fs-small); color: var(--ink-faint);
  font-variation-settings: 'slnt' -12; font-synthesis: none;
}

/* избранное плиткой */
/* Линии рисуют сами плитки, а не фон под ними: иначе в неполном ряду
   оставались бы серые пустые клетки. */
.cv__highlights {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  border-top: 1px solid var(--line); border-left: 1px solid var(--line);
}
.cv__hl {
  background: var(--paper); padding: var(--s-5); display: flex; flex-direction: column; gap: var(--s-2);
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  transition: background-color var(--dur-fast) var(--ease);
}
.cv__hl:hover { background: var(--paper-sunk); }
.cv__hl-yr { font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.cv__hl-ttl { font-size: var(--fs-lead); line-height: var(--lh-tight); }
.cv__hl-venue { font-size: var(--fs-small); color: var(--ink-muted); }

/* простые строки: год — что — пояснение */
.cv__row {
  display: grid; grid-template-columns: 9rem 1fr; gap: var(--s-1) var(--s-6);
  padding: var(--s-3) 0; border-bottom: 1px solid var(--line); align-items: baseline;
}
.cv__row:last-child { border-bottom: none; }
.cv__row-yr {
  font-family: var(--font-mono); font-size: var(--fs-label); color: var(--ink-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.cv__row-what { font-size: var(--fs-base); }
.cv__row-sub { grid-column: 2; font-size: var(--fs-small); color: var(--ink-muted); }

/* студенческие работы — плашками */
.cv__chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.cv__chip { font-size: var(--fs-small); color: var(--ink-muted); border: 1px solid var(--line); padding: var(--s-1) var(--s-3); }

/* контакты в шапке: подписи колонкой слева, значения колонкой справа.
   display: contents пускает dt и dd обёртки прямо в сетку. Волосяная линия
   сверху — та же, что делит строки в разделах; жирная 1.5px принадлежит
   языку заголовков разделов, здесь она не к месту. */
.cv__contacts {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s-2) var(--s-6); margin: var(--s-2) 0 0; padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
.cv__contacts > div { display: contents; }
.cv__contacts dt {
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--ink-faint); padding-top: var(--s-1);
}
.cv__contacts dd { margin: 0; font-size: var(--fs-base); line-height: var(--lh-normal); overflow-wrap: anywhere; }

@media screen and (max-width: 960px) {
  .cv { gap: var(--s-8); }
  .cv__intro { flex-direction: column; align-items: flex-start; gap: var(--s-6); }
  .cv__photo { width: min(300px, 70%); }
  .cv__work { grid-template-columns: 3.6rem 1fr; }
  .cv__job { grid-column: 2; text-align: left; }
  .cv__row { grid-template-columns: 6.5rem 1fr; }
}

/* ── зум по клику ───────────────────────────────────────────────────── */
.zoomer {
  position: fixed; inset: 0; z-index: var(--z-overlay); display: none;
  background-color: var(--paper); opacity: 0; transition: opacity var(--dur) var(--ease);
}
.zoomer.is-open { display: block; opacity: 1; }
.zoomer__stage {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: var(--s-8); box-sizing: border-box; cursor: zoom-out;
}
.zoomer__img { max-width: 100%; max-height: 100%; object-fit: contain; cursor: default; }
.zoomer__close {
  position: absolute; top: var(--s-3); right: var(--s-3); z-index: 2;
  width: var(--s-8); height: var(--s-8); padding: 0; border: none; background: none; cursor: pointer;
}
.zoomer__close::before,
.zoomer__close::after {
  content: ''; position: absolute; left: 9px; top: 19px;
  width: 22px; height: 2px; background-color: var(--ink);
}
.zoomer__close::before { transform: rotate(45deg); }
.zoomer__close::after { transform: rotate(-45deg); }
.zoomer__arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: none; border: none; padding: var(--s-5); cursor: pointer; z-index: 2;
  color: var(--ink);
}
.zoomer__arrow svg { display: block; width: 18px; height: auto; }
.zoomer__arrow--left { left: var(--s-3); }
.zoomer__arrow--left svg { transform: rotate(180deg); }
.zoomer__arrow--right { right: var(--s-3); }
/* Номер кадра — тем же набором, что под каруселью. Стоит внизу по центру,
   в поле --s-8, которое сцена и так оставляет вокруг кадра. */
.zoomer__counter {
  position: absolute; left: 0; right: 0; bottom: var(--s-3); z-index: 2;
  margin: 0; text-align: center; pointer-events: none;
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--ls-caps);
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
/* На телефоне в зуме, как и в карусели, листают свайпом. Щипок оставлен:
   кадр во весь экран хочется ещё и приблизить. */
.zoomer { touch-action: pan-y pinch-zoom; }
@media screen and (max-width: 600px) { .zoomer__arrow { display: none; } }
body.is-zoomed { overflow: hidden; }
