/* ================================================================
   Hero
   Новая структура (по Figma 196:12307): фото сверху, ниже текст-блок
   с blur+tint, перекрывающий низ фото на -240. Виньетки больше нет —
   её роль играет blur+tint, как в case-hero страницы Brighty.
   ================================================================ */

.hero {
    overflow: clip;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: var(--hero-width);
    margin-inline: auto;
}

/* На мобиле hero (вместе с видосом) растягивается до краёв экрана,
   выходя за паддинги .page (16px). А текстовому блоку внутри возвращаем
   те же 16px паддинги, чтобы заголовок/описание/кнопки не липли к краю. */
@media (max-width: 767px) {
    .hero {
        margin-left: calc(-1 * var(--content-padding-x));
        margin-right: calc(-1 * var(--content-padding-x));
        width: calc(100% + 2 * var(--content-padding-x));
        max-width: none;
    }
    .hero__body {
        padding-left: var(--content-padding-x);
        padding-right: var(--content-padding-x);
    }
}

/* Фото-блок — квадратный (aspect-ratio 1:1) для пропорционального
   скейла на мобиле. Margin -40% эквивалент Figma'шных -240px при
   ширине 600 (240 / 600 = 40 %). На мобиле остаётся та же доля. */
.hero__photo {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1;
    margin-bottom: -40%;
    overflow: hidden;
}

.hero__photo-media {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Радиальный градиент-виньетка поверх hero-видео.
   Центр (прозрачная зона) смещён в верх-центр — там лицо в портрете.
   К краям, особенно к низу, плавно затемняется до чёрного — фото
   мягко перетекает в текстовый блок (который наезжает на photo
   через margin-bottom: -40%).
   pointer-events: none — слой не перехватывает клики/тачи. */
.hero__photo::after {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(
        circle at 50% 45%,
        transparent 0%,
        transparent 24.5%,
        rgba(0, 0, 0, 0.55) 49%,
        rgba(0, 0, 0, 1) 70%
    );
    pointer-events: none;
    border-radius: inherit;
}

/* Текст-блок hero — повторяет паттерн case-hero (blur + linear gradient
   tint), без своих css-фон/виньетки. */
.hero__body {
    position: relative;
    width: 100%;
    padding-top: var(--space-80);
    padding-bottom: var(--space-32);
    display: flex;
    flex-direction: column;
    gap: var(--space-32);
    align-items: center;
    text-align: center;
}

/* Слой Linear Gradient — затемнение от прозрачного к чёрному, как у case-hero
   (точка stop 44.985 % — из Figma node 196:12309). */
.hero__tint {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 44.985%);
}

/* Слой Progressive Blur — стек из 6 backdrop-filter с возрастающими радиусами,
   как на странице кейса (полифил под W3C linear-blur() proposal).
   Сверху чётко (низ фото), снизу размытие нарастает к финалу зоны overlap. */
.hero__blur {
    position: absolute;
    top: -20px;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
}

.hero__blur > div {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.hero__blur > div:nth-child(1) {
    backdrop-filter: blur(1px);
    -webkit-backdrop-filter: blur(1px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 0) 20%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 0) 20%);
}

.hero__blur > div:nth-child(2) {
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 0) 30%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 0) 30%);
}

.hero__blur > div:nth-child(3) {
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 0) 40%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 0) 40%);
}

.hero__blur > div:nth-child(4) {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 50%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 50%);
}

.hero__blur > div:nth-child(5) {
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 60%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 60%);
}

.hero__blur > div:nth-child(6) {
    backdrop-filter: blur(32px);
    -webkit-backdrop-filter: blur(32px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 1) 100%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 1) 100%);
}

/* Контент hero — над blur/tint слоями. */
.hero__name,
.hero__intro,
.hero__edu,
.hero__buttons {
    position: relative;
    z-index: 1;
    width: 100%;
}

.hero__name {
    text-align: center;
}

.hero__intro,
.hero__edu {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    align-items: stretch;
}

.hero__buttons {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: center;
}

/* Новый стиль кнопок (Figma 196:12318): белый текст на белом-10% фоне.
   Раньше был синий акцент. */
.hero__button {
    flex: 1 0 0;
    min-width: 0;
    padding: var(--space-12) var(--space-16);
    background: rgba(255, 255, 255, 0.1);
    color: var(--color-text-primary);
    border-radius: var(--radius-button);
    text-align: center;
    white-space: nowrap;
    transition: background 0.15s ease;
}

.hero__button:hover {
    background: rgba(255, 255, 255, 0.16);
}

/* ================================================================
   ProjectCard — обновлённая раскладка (Figma 196:12328 / 12457).
   Структура:
     .project-card                          — обёртка, gap-64 между card и media-row
       .project-card__inner                 — карточка (600 wide, rounded-24)
         .device                            — телефон / планшет (mb -240 / -160)
         .project-card__text                — текст-блок снизу с blur+tint
           .project-card__tint
           .project-card__blur
           .project-card__title-group       — title-row + description + stats
             .project-card__title-row       — icon + title-link
               .project-card__title-link    — <div> (+ --soon для «Скоро»)
                 .project-card__title       — h2 названия
                 .project-card__title-action — лейбл «Скоро» (abs, только --soon)
           .project-card__press             — опционально
           .project-card__cta               — кнопка «Смотреть кейс»
                                              (единственный путь в кейс)
       .project-card__media                 — опционально, ряд 3-4 тайлов
   Варианты устройства: --phone (default) | --tablet
   ================================================================ */

.project-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-32); /* card → media row */
    width: 100%;
}

/* Внутренний контейнер карточки. Overflow VISIBLE — иначе верх bezel'а
   устройства (особенно у планшета, -23.65px) клипуется. Скруглённые края
   снизу гарантирует .project-card__text у которого свой overflow hidden. */
.project-card__inner {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: var(--card-width);
    border-radius: var(--radius-card);
}

/* Overlap между устройством и текст-блоком. Phone -240, tablet -160 (Figma). */
.project-card--phone .device {
    margin-bottom: -240px;
}

.project-card--tablet .device {
    margin-bottom: -160px;
}

/* --- Visual <img> для кейсов с внутренней страницей ---------------
   Альтернатива .device + blur + tint: одна готовая картинка с уже
   выпеченными phone bezel + screen + Progressive Blur + tint снизу.
   Используется для Brighty (и далее — для других кейсов, у которых
   есть страница). Картинка 360×564 включает horizontal padding 55px
   слева/справа и vertical padding 10px сверху/снизу (унифицировано
   между превью на главной и шапкой кейса), чтобы один visual подходил
   к обоим местам без отдельных wrapper'ов.

   Преимущество: snapshot целиком (одна картинка) при VT — никакого
   backdrop-filter+isolation проблемы. Минус: blur статичный, не
   реактивный (но screen статичный — это не важно). */

/* Overlap текстового блока на визуал пропорционален ширине визуала.
   Phone-visual: 240/360 ≈ 66.67 % ширины. Tablet-visual: 160/600 ≈ 26.67 %.

   margin-bottom = max(-240px, -66.667 %):
     • Пока container шире/равен 360 (визуал в свою фикс-ширину 360) —
       -66.667 % от container'а оказывается «больше» (по модулю) -240 px,
       max() выбирает -240px. Дизайнерский overlap сохраняется.
     • Когда container уже 360 (визуал скейлится по max-width:100 %) —
       -66.667 % оказывается «слабее» -240 px, max() выбирает процент,
       overlap плавно уменьшается пропорционально визуалу.

   Старый @media ≤767 px резал overlap до -160 px на 767-м, хотя визуал
   ещё держался в полную ширину — отсюда визуальный «прыжок» текста вниз
   ровно на брейкпоинте. Сейчас прыжка нет — переход непрерывный. */
.project-card__visual,
.case-hero__visual {
    display: block;
    width: 360px;
    max-width: 100%;
    height: auto;
    margin-bottom: max(-240px, -66.667%);
}

/* Tablet-вариант — горизонтальный планшет шире (600px = card-width)
   и overlap меньше (-160, как у .project-card--tablet .device).
   PNG включает рамку планшета + screen + Progressive Blur + tint
   снизу — точно как phone-visual, только пропорции другие. */
.project-card__visual--tablet,
.case-hero__visual--tablet {
    width: 600px;
    margin-bottom: max(-160px, -26.667%);
}

/* Текст-блок: pt-80 + responsive padding-inline (64 / 48 / 0) + pb-32.
   Содержит 2 фоновых слоя.
   БЕЗ overflow: hidden и border-radius на самом блоке — иначе ломается
   стек масок backdrop-filter (browser создаёт изолированный контекст,
   и каждый слой блюра «видит» соседей вместо чистого фона).
   Скругление нижних углов вынесено на сами слои .tint и .blur > div.

   min-height = overlap (240px у phone) + хвост (32px) = 272px.
   Гарантия: при коротком описании (Abuse Moscow, Soulmate) низ телефона
   не торчит из-под текст-блока — блок всегда минимум 272 px и накрывает
   overlap полностью. У карточек с длинным описанием и фактоидами высота
   текста растёт сама — min-height ни на что не влияет. */
.project-card__text {
    position: relative;
    width: 100%;
    min-height: 272px;
    padding: var(--space-80) var(--space-64) var(--space-32);
    display: flex;
    flex-direction: column;
    gap: var(--space-32);
    align-items: center;
}

/* У tablet-карточек overlap всего -160px, поэтому хватает 192px. */
.project-card--tablet .project-card__text {
    min-height: 192px;
}

@media (max-width: 1023px) {
    .project-card__text {
        padding-inline: var(--space-48);
    }
}

@media (max-width: 767px) {
    .project-card__text {
        padding-inline: 0;
    }
}

/* Слой Linear Gradient — прозрачно → чёрный на 74.419 % (точные значения Figma).
   Border-radius на самом слое — чтобы нижние углы tint'а закруглялись,
   когда у родительского text-block НЕТ overflow: hidden. */
.project-card__tint {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 74.419%);
    border-radius: 0 0 var(--radius-card) var(--radius-card);
}

/* Слой Progressive Blur — стек из 6 backdrop-filter с возрастающими радиусами,
   полифил W3C linear-blur(). Высота строго совпадает с .project-card__text,
   чтобы блюр не обрезался резко по нижнему краю overflow: hidden. */
.project-card__blur {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.project-card__blur > div {
    position: absolute;
    inset: 0;
    pointer-events: none;
    /* Скругление нижних углов — чтобы блюр на нижних углах карточки
       не выходил за пределы скруглённой формы card'а. */
    border-radius: 0 0 var(--radius-card) var(--radius-card);
}

.project-card__blur > div:nth-child(1) {
    backdrop-filter: blur(1px);
    -webkit-backdrop-filter: blur(1px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 0) 20%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 0) 20%);
}

.project-card__blur > div:nth-child(2) {
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 0) 30%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 0) 30%);
}

.project-card__blur > div:nth-child(3) {
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 0) 40%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%, rgba(0, 0, 0, 1) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 0) 40%);
}

.project-card__blur > div:nth-child(4) {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 50%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%, rgba(0, 0, 0, 1) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 50%);
}

.project-card__blur > div:nth-child(5) {
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 60%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 0) 60%);
}

.project-card__blur > div:nth-child(6) {
    backdrop-filter: blur(32px);
    -webkit-backdrop-filter: blur(32px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 1) 100%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 1) 50%, rgba(0, 0, 0, 1) 100%);
}

/* Контент карточки — над фоновыми слоями и над card-cover ссылкой. */
.project-card__title-group {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
    align-items: center;
    width: 100%;
}

.project-card__title-row {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Иконка 32×32 слева от названия. По умолчанию — inline через flex+gap
   родителя (.project-card__title-link), чтобы блок целиком центрировался.
   В --soon варианте — absolute, чтобы измерительная ширина title-link была
   = ширина тайтла, и symmetric absolute-сосед справа (лейбл «Скоро») держал
   визуальный баланс. */
.project-card__icon {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    display: block;
    border-radius: 8px;
    overflow: hidden;
}

.project-card__title-link--soon .project-card__icon {
    position: absolute;
    right: calc(100% + 12px);
    top: calc(50% - 16px);
}

.project-card__icon img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.project-card__title {
    white-space: nowrap;
    color: var(--color-text-primary);
}

/* Title-link — обёртка вокруг icon + названия (+ action-лейбл «Скоро»
   в --soon варианте). Тег — <div>; в кликабельных кейсах единственный
   путь в кейс — кнопка .project-card__cta внизу карточки.

   Базовый вариант (кликабельные карточки): icon идёт inline через flex+gap,
   чтобы блок (icon + title) центрировался целиком. Если icon оставить
   absolute, при отсутствии симметричного элемента справа визуальный центр
   уезжал бы вправо ровно на половину иконки. */
.project-card__title-link {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-12);
    color: inherit;
    text-decoration: none;
}

/* --soon вариант: icon снова absolute слева, лейбл «Скоро» absolute справа —
   измерительная ширина title-link = ширина тайтла, и симметричные absolute-
   соседи держат визуальный баланс. */
.project-card__title-link--soon {
    display: block;
}

/* Action-контейнер — справа от названия, только в --soon варианте
   (текст «Скоро»). Позиционируется absolute (top:0 / bottom:0), не
   попадает в measurement title-link. Дистанция от названия — 12px. */
.project-card__title-action {
    position: absolute;
    left: calc(100% + 12px);
    top: 0;
    bottom: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 1px;
    font-size: 16px;
    line-height: 1.25;
    color: var(--color-text-primary);
    opacity: 0.4;
    white-space: nowrap;
}

/* «Скоро» вариант — title-link это <div>, не кликабелен. */
.project-card__title-link--soon {
    cursor: default;
}

.project-card__description {
    color: var(--color-text-secondary);
    text-align: center;
    width: 100%;
}

/* Опциональный блок статистики — числа Inter Tight 18 white (без opacity). */
.project-card__stats {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: center;
    gap: var(--space-16);
    color: var(--color-text-primary);
}

/* Опциональный блок пресса — кликабельные ссылки внутри карточки.
   Поднят над card-cover линком z-index'ом, чтобы клики не перехватывались. */
.project-card__press {
    position: relative;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-12);
    width: 100%;
    color: var(--color-text-primary);
}

.project-card__press-label {
    color: var(--color-text-secondary);
}

.project-card__press a {
    color: var(--color-text-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
    transition: opacity 0.15s ease;
}

.project-card__press a:hover {
    opacity: 0.7;
}

/* CTA-пилюля «Смотреть кейс» — единственный путь на страницу кейса
   (Brighty / OhMyGuide / DNA). Сама карточка не кликабельна; ни заголовок,
   ни описание/фактоиды не ведут на кейс — только эта кнопка. Press-ссылки
   ведут на внешние ресурсы, не на кейс. */
.project-card__cta {
    position: relative;
    z-index: 2;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-12) var(--space-24);
    background: var(--color-text-primary);
    color: #000000;
    border-radius: var(--radius-button);
    text-decoration: none;
    white-space: nowrap;
    transition: opacity 0.15s ease;
}

.project-card__cta:hover {
    opacity: 0.85;
}

/* Media row — отдельная секция под карточкой, шире её (до 1000px). */
.project-card__media {
    display: flex;
    align-items: flex-start;
    gap: var(--space-12);
    width: 100%;
    max-width: var(--media-row-width);
    padding-bottom: var(--space-64);
}

.project-card__media-item {
    flex: 1 0 0;
    min-width: 0;
    /* 9:16 под пропорции showreel-видео; object-fit: cover на video
       кропит запечённые боковые «уши» в исходном 1080×1080. */
    aspect-ratio: 9 / 16;
    background: var(--color-media-placeholder);
    border-radius: var(--radius-tile);
    overflow: hidden;
    margin: 0;
}

.project-card__media-item > img,
.project-card__media-item > video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}


/* ================================================================
   Layout — Portfolio page
   ================================================================ */

.portfolio {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-120);
    padding-top: 0;
    padding-bottom: var(--space-240);
}

/* ================================================================
   Device — переиспользуемый мокап устройства.
   Используется и в .project-card на главной, и в кейс-страницах.
   Структура: .device > .device__screen + .device__bezel
   Варианты: .device--phone / .device--tablet
   Все размеры — переменные из tokens.css (легко переопределяются на мобиле).
   ================================================================ */

.device {
    position: relative;
    flex-shrink: 0;
}

.device--phone {
    width:  var(--device-phone-width);
    height: var(--device-phone-height);
}

.device--tablet {
    width:  var(--device-tablet-width);
    height: var(--device-tablet-height);
}

.device__screen {
    position: absolute;
    inset: 0;
    overflow: hidden;
    background: var(--color-surface);
    border-radius: 20px;
}

.device--tablet .device__screen {
    border-radius: 16px;
}

.device__screen > img,
.device__screen > video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
}

.device__bezel {
    position: absolute;
    pointer-events: none;
}

.device__bezel img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.device--phone .device__bezel {
    top:    var(--device-phone-bezel-top);
    left:   var(--device-phone-bezel-left);
    width:  var(--device-phone-bezel-width);
    height: var(--device-phone-bezel-height);
}

.device--tablet .device__bezel {
    top:    var(--device-tablet-bezel-top);
    left:   var(--device-tablet-bezel-left);
    width:  var(--device-tablet-bezel-width);
    height: var(--device-tablet-bezel-height);
}

/* Мелкие телефоны (для «сборной солянки» в кейсе Brighty). Пропорции те же,
   что у .device--phone — только размеры меньше. */
.device--phone-sm {
    width:  var(--device-phone-sm-width);
    height: var(--device-phone-sm-height);
}

.device--phone-sm .device__bezel {
    top:    var(--device-phone-sm-bezel-top);
    left:   var(--device-phone-sm-bezel-left);
    width:  var(--device-phone-sm-bezel-width);
    height: var(--device-phone-sm-bezel-height);
}

.device--phone-md {
    width:  var(--device-phone-md-width);
    height: var(--device-phone-md-height);
}

.device--phone-md .device__bezel {
    top:    var(--device-phone-md-bezel-top);
    left:   var(--device-phone-md-bezel-left);
    width:  var(--device-phone-md-bezel-width);
    height: var(--device-phone-md-bezel-height);
}

/* Меньшие телефоны → меньшие радиусы экрана (пропорционально). */
.device--phone-sm .device__screen,
.device--phone-md .device__screen {
    border-radius: 12px;
}

/* ================================================================
   Page: Case Study
   Скелет страницы конкретного кейса (brighty.html и т.п.).
   Сюда будут добавляться секции по мере наполнения.
   ================================================================ */

.case {
    position: relative; /* для absolute-позиции навигации */
    display: flex;
    flex-direction: column;
    gap: var(--space-120);
    padding-block: var(--space-40) var(--space-240);
}

/* Nav кейс-страницы: fixed — остаётся на той же высоте viewport'а
   при скролле. Изначальная позиция (top: 40) совпадает с padding-top у .case,
   поэтому в нулевом скролле кнопка визуально лежит на одной линии с верхом
   контента — как раньше при absolute.

   Ширина рассчитана так, чтобы кнопка «назад» по левому краю выравнивалась
   с левым краем контент-колонки (600px) внутри .page (padding-inline 24/16).
   Поэтому max-width = card-width + 2 × content-padding-x, а внутрь добавлен
   тот же padding-inline. На любой ширине viewport'а кнопка лежит на одной
   вертикали с левым краем hero/intro. */
.case__nav {
    position: fixed;
    top: var(--space-40);
    left: 50%;
    transform: translateX(-50%);
    width: 100%;
    max-width: calc(var(--card-width) + var(--content-padding-x) * 2);
    padding-inline: var(--content-padding-x);
    z-index: 100;
    display: flex;
    justify-content: flex-start;
    pointer-events: none; /* wrapper не перехватывает клики, только кнопка */
}

.case__back {
    pointer-events: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-md);
    background: rgba(255, 255, 255, 0.16);
    color: var(--color-text-primary);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    transition: background 0.15s ease;
}

.case__back:hover {
    background: rgba(255, 255, 255, 0.24);
}

.case__back svg {
    width: 24px;
    height: 24px;
    display: block;
    stroke: currentColor;
}

/* ================================================================
   Page transition — Cross-Document View Transitions

   Между страницами портфолио (index ↔ brighty ↔ ohmyguide) ходит
   shared-element transition: phone, фоновый blur, фоновый tint и
   заголовок морфят между превью-карточкой на главной и шапкой кейса.
   Всё остальное (icon, description, stats, press на главной;
   subtitle, date, intro-блоки, «Главное» на кейсе) — фейдится через
   root и появляется stagger'ом на новой странице.

   Поддержка: Chrome 126+, Safari 18+. Firefox — фолбэк = обычная
   навигация без анимации.

   Sequence (общая ~1.5 c):
     0–450ms   — root старой страницы (контент без VT-имени) → opacity 0
     400–950ms — phone/blur/tint/title морфят bbox старой → новая позиция
     950ms+    — контент новой страницы появляется stagger'ом
                 (через html[data-revealing] + tt-reveal keyframe).
                 Атрибут data-revealing ставит inline pagereveal-listener
                 в <head> каждой прод-страницы.

   --- Как подключить новый кейс ----------------------------------
     1) Дай кейсу slug (например, dna).
     2) Подготовь готовую картинку с phone + screen + Progressive Blur +
        tint, 360×564, положи в src/assets/projects/<slug>/Main-screen.png.
     3) Добавь блок per-case binding'а ниже (4 строки):
            .vt-phone-dna     { view-transition-name: dna-phone;     }
            .vt-title-dna     { view-transition-name: dna-title;     }
            .vt-text-card-dna { view-transition-name: dna-card-text; }
            .vt-text-case-dna { view-transition-name: dna-case-text; }
     4) Добавь группу в ::view-transition-group ниже:
            phone в 10, title в 20, card-text/case-text в 15.
     5) В index.html на превью-карточке: <img class="project-card__visual
        vt-phone-dna" ...>, <div class="project-card__text vt-text-card-dna">,
        <h2 class="... vt-title-dna">.
     6) В <case>.html в case-hero: <img class="case-hero__visual vt-phone-dna" ...>,
        <div class="case-hero__text vt-text-case-dna">, <h1 class="... vt-title-dna">.
     7) Добавь slug в VT_SLUG_MAP в inline-скриптах в <head>
        index.html и <case>.html (для data-morphing орchestration).
   ================================================================ */

@view-transition {
    navigation: auto;
}

/* --- Тайминги root-снимка -------------------------------------- */

/* Кросс-fade между старым и новым root.
   Старый фейдится 0-700ms по мягкой sigmoid-кривой (0.4/0/0.6/1) —
   opacity падает равномерно, без «плато» в начале и без резкого
   обрыва в конце. Видимый угасающий шлейф вместо «чпуньк».

   Новый root приходит с задержкой 500ms (= overlap 200ms с концом
   fade-out старого) и доезжает за 400ms. До 500ms он невидим —
   юзер не видит новый контент кейса (case-section'ы, nav, etc)
   поверх затухающей старой страницы.

   Stagger дочерних элементов new root начинается с 950ms (overlap
   50ms с концом fade-in). Контент проявляется по очереди через
   html[data-revealing] + tt-reveal keyframe — поверх уже видимого
   нового root'а. */
::view-transition-old(root) {
    animation: page-tt-fade-out 700ms cubic-bezier(0.4, 0, 0.6, 1) forwards;
}

::view-transition-new(root) {
    animation: page-tt-fade-in 400ms cubic-bezier(0.4, 0, 0.6, 1) 500ms forwards;
    opacity: 0;
}

/* --- Тайминги морфа shared-элементов --------------------------- */
/* Перечисляем все группы (phone + title на каждый кейс).
   Тайминги общие — последовательность fade → morph → reveal задаётся
   через animation-delay.

   blur и tint НЕ получают собственный view-transition-name — иначе
   view-transition-name создаёт stacking context + isolation, и
   backdrop-filter на blur-слое перестаёт видеть фон позади. Без
   собственного имени blur и tint становятся частью root snapshot
   и фейдятся вместе с ним; на real DOM (после VT) backdrop-filter
   снова работает как ожидается. */

/* Настраиваем только GROUP (интерполяция transform/width/height между
   старым и новым bbox). Image pair (::view-transition-old / -new)
   оставляем на дефолтном cross-fade — он быстрый (~250ms) и НЕ
   конфликтует с delay'ом group'а. Если задавать image pair тайминги
   вручную, в Chromium бывают глюки с двойной перерисовкой snapshot'а:
   старый image фейдится, затем при старте delay'а group'а
   перерисовывается ещё раз → визуальное мерцание phone'а.

   Cross-fade быстро (0–250ms) — потом group геометрически интерполирует
   transform с 400 до 950ms. Phone «settles» в new appearance быстро,
   но плавно едет по позиции/размеру. */

::view-transition-group(brighty-phone),
::view-transition-group(brighty-title),
::view-transition-group(omg-phone),
::view-transition-group(omg-title),
::view-transition-group(dna-phone),
::view-transition-group(dna-title) {
    animation-duration: 550ms;
    animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
    animation-delay: 400ms;
}

/* --- Z-order pseudo-elements ----------------------------------- */
/* Phone и title ДОЛЖНЫ быть выше root, иначе во время морфа phone
   уходит из «cut-out» в root snapshot'е (root pseudo захватывает всё
   что НЕ имеет VT-имени; на месте phone'а — прозрачная дырка по
   bbox phone'а В МОМЕНТ CAPTURE'А). Когда group морфит, phone
   двигается в новую позицию — где у root'а уже нет дырки, и root
   перекрывает phone, заставляя его «исчезать» на пол-пути.

   Phone z 10, root z 5, title z 20 — phone всегда поверх root,
   title — поверх phone (на превью title пересекается с phone'ом
   только через Progressive Blur слой). */

::view-transition-group(brighty-phone),
::view-transition-group(omg-phone),
::view-transition-group(dna-phone)        { z-index: 10; }
::view-transition-group(root)             { z-index: 5;  }
::view-transition-group(brighty-card-text),
::view-transition-group(brighty-case-text),
::view-transition-group(omg-card-text),
::view-transition-group(omg-case-text),
::view-transition-group(dna-card-text),
::view-transition-group(dna-case-text)    { z-index: 15; }
::view-transition-group(brighty-title),
::view-transition-group(omg-title),
::view-transition-group(dna-title)        { z-index: 20; }

/* --- Phone image pair: без cross-fade -------------------------- */
/* Phone snapshot на главной и на кейсе содержит ОДИН И ТОТ ЖЕ image
   (тот же home-screen.png внутри одинакового iPhone bezel). Дефолтный
   cross-fade image pair (opacity 0↔1 за 250ms) создаёт лишнее
   полупрозрачное «моргание» посредине, при том что визуально
   результат cross-fade равен исходнику. Отключаем — phone стабильно
   visible с opacity 1 на протяжении всей анимации, group интерполирует
   только transform (позиция и размер).

   Для title cross-fade ОСТАВЛЯЕМ дефолтным — там snapshot'ы разного
   размера (40px h2 на превью vs 64px h1 в шапке кейса), кросфейд
   между ними нужен для плавного «вырастания/уменьшения». */

::view-transition-old(brighty-phone),
::view-transition-new(brighty-phone),
::view-transition-old(omg-phone),
::view-transition-new(omg-phone),
::view-transition-old(dna-phone),
::view-transition-new(dna-phone) {
    animation: none;
    opacity: 1;
}

@keyframes page-tt-fade-out {
    to { opacity: 0; }
}

@keyframes page-tt-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* --- Per-case binding ------------------------------------------ */
/* Атомарные классы ставятся на парные элементы на главной и в кейсе.
   Имя view-transition-name должно быть УНИКАЛЬНЫМ на странице — поэтому
   у каждого кейса свой slug. Морфят только phone и title — blur/tint
   фейдятся как часть root (см. комментарий выше про backdrop-filter). */

.vt-phone-brighty { view-transition-name: brighty-phone; }
.vt-title-brighty { view-transition-name: brighty-title; }

.vt-phone-omg { view-transition-name: omg-phone; }
.vt-title-omg { view-transition-name: omg-title; }

.vt-phone-dna { view-transition-name: dna-phone; }
.vt-title-dna { view-transition-name: dna-title; }

/* Text-блок (description/stats/press на превью; subtitle/date/links на кейсе).
   Orphan groups — имя только на одной стороне перехода. По дефолту orphan
   делает fade-out (если name только в old snapshot) или fade-in (если только
   в new snapshot). Это И НУЖНО — текст на превью и на кейсе разный, морфить
   между ними бессмысленно, нужен именно фейд.

   Зачем вообще даём имя, если морфа нет? — чтобы блок выпал из root и можно
   было поставить z-index ВЫШЕ visual'а (z 10). Иначе текст в overlap-зоне
   уходит под visual во время VT. */
.vt-text-card-brighty { view-transition-name: brighty-card-text; }
.vt-text-case-brighty { view-transition-name: brighty-case-text; }
.vt-text-card-omg     { view-transition-name: omg-card-text; }
.vt-text-case-omg     { view-transition-name: omg-case-text; }
.vt-text-card-dna     { view-transition-name: dna-card-text; }
.vt-text-case-dna     { view-transition-name: dna-case-text; }

/* --- Stagger reveal на новой странице -------------------------- */
/* Включается inline-скриптом из <head>:
     window.addEventListener('pagereveal', e => {
         if (e.viewTransition) html.dataset.revealing = '';
     });
   Без VT (cold load, Firefox) атрибут не появляется и элементы
   остаются в нормальном виде — без анимации, без скрытия. */

@keyframes page-tt-reveal {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}

html[data-revealing] .case-hero__title-group p,
html[data-revealing] .case-hero__links,
html[data-revealing] .case-intro__block,
html[data-revealing] .case-results,
html[data-revealing] .project-card__icon,
html[data-revealing] .project-card__title-action,
html[data-revealing] .project-card__description,
html[data-revealing] .project-card__stats,
html[data-revealing] .project-card__press,
html[data-revealing] .project-card__cta,
html[data-revealing] .project-card__media {
    opacity: 0;
    animation: page-tt-reveal 500ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
}

/* Stagger-задержки. Морф shared элементов длится 400→950ms.
   Reveal стартует на 950ms (overlap 50ms — «течёт», не рвётся),
   шаг ~70ms между блоками. */

/* Внутренняя страница кейса (case-hero + intro + Главное). */
html[data-revealing] .case-hero__title-group p:nth-of-type(1) { animation-delay: 950ms;  }
html[data-revealing] .case-hero__title-group p:nth-of-type(2) { animation-delay: 1020ms; }
html[data-revealing] .case-hero__links                        { animation-delay: 1090ms; }
html[data-revealing] .case-intro__block:nth-of-type(1)        { animation-delay: 1160ms; }
html[data-revealing] .case-intro__block:nth-of-type(2)        { animation-delay: 1240ms; }
html[data-revealing] .case-intro__block:nth-of-type(3)        { animation-delay: 1320ms; }
html[data-revealing] .case-results                            { animation-delay: 1400ms; }

/* Главная (превью-карточка). Та же ритмика — на back с кейса
   icon/title-action/description/stats/press/media появляются stagger'ом.
   __media (ряд тайлов под Brighty) после press — последний элемент карточки,
   логично что появляется в самом конце. */
html[data-revealing] .project-card__icon                      { animation-delay: 950ms;  }
html[data-revealing] .project-card__title-action              { animation-delay: 1020ms; }
html[data-revealing] .project-card__description               { animation-delay: 1090ms; }
html[data-revealing] .project-card__stats                     { animation-delay: 1160ms; }
html[data-revealing] .project-card__press                     { animation-delay: 1240ms; }
html[data-revealing] .project-card__cta                       { animation-delay: 1320ms; }
html[data-revealing] .project-card__media                     { animation-delay: 1400ms; }

/* --- Остальные карточки на главной --------------------------------
   Помимо контента морфящей карточки, на главную возвращаются и
   ДРУГИЕ project-card'ы (FINTCH, OMG/Brighty в зависимости от направления,
   DNA, etc.). Они тоже должны появляться stagger'ом, иначе видны
   мгновенно — нарушает ритм.

   Морфящую карточку (ту, чей view-transition-name участвует в transition)
   исключаем через :not(:has(.vt-phone-<slug>)) — она остаётся opacity 1,
   её содержимое уже в stagger через свои селекторы выше.

   Slug морфящего кейса знаем через html[data-morphing=<slug>] — атрибут
   ставит inline pagereveal listener из sessionStorage, который заполняется
   на pageswap старой страницы. */

html[data-revealing][data-morphing="brighty"] .project-card:not(:has(.vt-phone-brighty)),
html[data-revealing][data-morphing="omg"]     .project-card:not(:has(.vt-phone-omg)),
html[data-revealing][data-morphing="dna"]     .project-card:not(:has(.vt-phone-dna)) {
    opacity: 0;
    animation: page-tt-reveal 500ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
}

/* Stagger-задержки между карточками. nth-of-type считает по <article> —
   первая project-card идёт после <header class="hero">, она nth-of-type(1).
   Задержки разнесены на 80ms — тот же ритм что у контента.
   Покрываем до 6 карточек, чтобы при добавлении новых кейсов не
   получился inst-show. Если карточек станет больше — добавь сюда. */
html[data-revealing][data-morphing] .project-card:nth-of-type(1) { animation-delay: 1400ms; }
html[data-revealing][data-morphing] .project-card:nth-of-type(2) { animation-delay: 1480ms; }
html[data-revealing][data-morphing] .project-card:nth-of-type(3) { animation-delay: 1560ms; }
html[data-revealing][data-morphing] .project-card:nth-of-type(4) { animation-delay: 1640ms; }
html[data-revealing][data-morphing] .project-card:nth-of-type(5) { animation-delay: 1720ms; }
html[data-revealing][data-morphing] .project-card:nth-of-type(6) { animation-delay: 1800ms; }

/* ---------------- Hero кейса ----------------
   Сверху телефон с интерфейсом, снизу — текстовая зона: название,
   роль, дата, ссылки. Между ними отрицательный gap −240 (как в Figma)
   → телефон визуально утопает в backdrop-blur текста.
   ---------------------------------------- */
.case-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: var(--card-width);
    margin-inline: auto;
    border-radius: var(--radius-card);
    overflow: hidden;
}

.case-hero__phone {
    display: flex;
    align-items: center;
    padding-block: 10px;
    margin-bottom: -240px;
}

.case-hero__text {
    position: relative;
    width: 100%;
    padding-top: var(--space-80);
    padding-bottom: var(--space-32);
    display: flex;
    flex-direction: column;
    gap: var(--space-32);
    align-items: center;
    /* Сам блок прозрачный — фон и блюр кладём слоями ниже. */
}

/* Progressive Blur — стек из 6 слоёв backdrop-filter с разными радиусами и
   масками, сдвинутыми вниз. Эталонный полифил под W3C proposal:
   https://github.com/w3c/csswg-drafts/issues/13285 (linear-blur()).

   Контейнер по высоте ≈ текстовому блоку (top: -20 — чуть-чуть «выходит»
   вверх, чтобы аккуратно зацепить самый низ телефона над текстом).

   Каждый слой накрывает «полосу» из 4 стопов: прозрачно → плотно → плотно
   → прозрачно. Соседние полосы перекрываются → плавный градиент блюра.

   Радиус удваивается ×2 (1 → 2 → 4 → 8 → 16 → 32px). Пики сжаты в верхнюю
   половину слоя (0–50 %), т.к. дальше телефона уже нет — блюрить нечего:
     слой 1 — blur 1px,  peak  0–10 %   (вершина слоя ≈ низ телефона)
     слой 2 — blur 2px,  peak 10–20 %
     слой 3 — blur 4px,  peak 20–30 %
     слой 4 — blur 8px,  peak 30–40 %
     слой 5 — blur 16px, peak 40–50 %
     слой 6 — blur 32px, peak 50–100 % (максимум прямо в конце overlap) */
.case-hero__blur {
    position: absolute;
    top: -20px;
    left: 0;
    right: 0;
    bottom: 0;
    pointer-events: none;
}

.case-hero__blur > div {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.case-hero__blur > div:nth-child(1) {
    backdrop-filter: blur(1px);
    -webkit-backdrop-filter: blur(1px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%,
        rgba(0, 0, 0, 1) 10%,
        rgba(0, 0, 0, 0) 20%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 1) 0%,
        rgba(0, 0, 0, 1) 10%,
        rgba(0, 0, 0, 0) 20%);
}

.case-hero__blur > div:nth-child(2) {
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%,
        rgba(0, 0, 0, 1) 10%,
        rgba(0, 0, 0, 1) 20%,
        rgba(0, 0, 0, 0) 30%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 0%,
        rgba(0, 0, 0, 1) 10%,
        rgba(0, 0, 0, 1) 20%,
        rgba(0, 0, 0, 0) 30%);
}

.case-hero__blur > div:nth-child(3) {
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%,
        rgba(0, 0, 0, 1) 20%,
        rgba(0, 0, 0, 1) 30%,
        rgba(0, 0, 0, 0) 40%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 10%,
        rgba(0, 0, 0, 1) 20%,
        rgba(0, 0, 0, 1) 30%,
        rgba(0, 0, 0, 0) 40%);
}

.case-hero__blur > div:nth-child(4) {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%,
        rgba(0, 0, 0, 1) 30%,
        rgba(0, 0, 0, 1) 40%,
        rgba(0, 0, 0, 0) 50%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 20%,
        rgba(0, 0, 0, 1) 30%,
        rgba(0, 0, 0, 1) 40%,
        rgba(0, 0, 0, 0) 50%);
}

.case-hero__blur > div:nth-child(5) {
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%,
        rgba(0, 0, 0, 1) 40%,
        rgba(0, 0, 0, 1) 50%,
        rgba(0, 0, 0, 0) 60%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 30%,
        rgba(0, 0, 0, 1) 40%,
        rgba(0, 0, 0, 1) 50%,
        rgba(0, 0, 0, 0) 60%);
}

.case-hero__blur > div:nth-child(6) {
    backdrop-filter: blur(32px);
    -webkit-backdrop-filter: blur(32px);
    mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%,
        rgba(0, 0, 0, 1) 50%,
        rgba(0, 0, 0, 1) 100%);
    -webkit-mask-image: linear-gradient(to bottom,
        rgba(0, 0, 0, 0) 40%,
        rgba(0, 0, 0, 1) 50%,
        rgba(0, 0, 0, 1) 100%);
}

/* Слой Linear Gradient — от прозрачного к чёрному.
   Параметры точно из Figma: to 74.419% — black. */
.case-hero__tint {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 74.419%);
}

/* Контент текста — над слоями. */
.case-hero__title-group,
.case-hero__links {
    position: relative;
    z-index: 1;
}

.case-hero__title-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-16);
    align-items: center;
    width: 100%;
    text-align: center;
}

.case-hero__date {
    color: var(--color-text-secondary);
}

.case-hero__links {
    display: flex;
    gap: var(--space-16);
    align-items: center;
    justify-content: center;
    width: 100%;
}

.case-hero__links a {
    text-decoration: underline;
    text-underline-offset: 2px;
    transition: opacity 0.15s ease;
}

.case-hero__links a:hover {
    opacity: 0.7;
}

/* ---------------- Intro кейса ----------------
   Стек блоков «Контекст / Ситуация до / Роль».
   Каждый блок: серифный заголовок 36 + параграф 16 (приглушённый).
   Между блоками gap-40, внутри блока gap-12.
   ---------------------------------------- */
.case-intro {
    display: flex;
    flex-direction: column;
    gap: var(--space-40);
    width: 100%;
    max-width: var(--card-width);
    margin-inline: auto;
}

.case-intro__block {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
}

.case-intro__text {
    color: var(--color-text-secondary);
}

/* ---------------- Results («Главное») ----------------
   Сетка ключевых метрик кейса. 2 колонки одинаковой ширины:
     • Левая: highlight-карточка (белый фон, чёрный текст) + default-карточка.
     • Правая: одна высокая default-карточка с тремя статами.
   На мобиле всё стекается в одну колонку.

   Карточки:
     • highlight — bg #fff, текст чёрный, gap-16 (заголовок → стат)
     • default   — bg rgba(255,255,255,0.1), текст белый, gap-24
   ---------------------------------------- */

.case-results {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
    width: 100%;
    max-width: var(--card-width);
    margin-inline: auto;
}

.case-results__grid {
    display: flex;
    gap: var(--space-12);
    align-items: stretch; /* колонки одинаковой высоты */
    width: 100%;
}

.case-results__column {
    flex: 1 0 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
}

.case-results__card {
    display: flex;
    flex-direction: column;
    padding: var(--space-24);
    border-radius: var(--radius-card);
    flex: 1 0 auto;
}

.case-results__card--highlight {
    background: #FFFFFF;
    color: #000000;
    gap: var(--space-16);
}

.case-results__card--default {
    background: rgba(255, 255, 255, 0.1);
    color: var(--color-text-primary);
    gap: var(--space-24);
}

/* Стат (число + лейбл) — gap 2px внутри, выровнено по левому краю. */
.case-results__stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Лейбл под числом — чуть приглушённый (opacity вместо цвета,
   чтобы работало и на белой, и на тёмной карточке). */
.case-results__stat-label {
    opacity: 0.7;
}

/* «Подробнее» — прижимается к низу карточки, чтобы во всех карточках
   с разной высотой ссылка визуально лежала на одной линии. */
.case-results__more {
    margin-top: auto;
    text-decoration: underline;
    text-underline-offset: 2px;
    color: inherit;
    transition: opacity 0.15s ease;
}

.case-results__more:hover {
    opacity: 0.7;
}

/* Адаптив: ≤ 767px — стек в одну колонку. */
@media (max-width: 767px) {
    .case-results__grid {
        flex-direction: column;
    }
}

/* ---------------- Outcome («Итоги») ----------------
   Финальный блок страницы кейса. Простой: заголовок + параграфы.
   ---------------------------------------- */
.case-outcome {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
    width: 100%;
    max-width: var(--card-width);
    margin-inline: auto;
}

.case-outcome__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    color: var(--color-text-secondary);
}

/* ---------------- Misc («сборная солянка») ----------------
   Сетка из 5 рядов с подложкой rgba(255,255,255,0.05).
   Внутри — мелкие/средние телефоны разных раскладок.

   На десктопе: ряды 600px wide (или 100% — full-row layout), фиксированной
   высотой 296px и центрированным контентом.

   На мобиле: ряды НЕ стекаются в колонку — каждый ряд получает
   горизонтальный скролл (overflow-x: auto), чтобы телефоны оставались
   крупными и читаемыми. Пользователь свайпает горизонтально.
   ---------------------------------------- */
.case-misc {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    width: 100%;
    max-width: var(--card-width);
    margin-inline: auto;
}

/* Базовый ряд — flex с центрированием, фиксированной высотой 296px.
   overflow: hidden — большие телефоны (336px) обрезаются по высоте ряда (296px),
   как в Figma (overflow-clip). */
.case-misc__row {
    display: flex;
    gap: var(--space-24);
    align-items: flex-start;
    justify-content: center;
    height: 296px;
    padding-block: var(--space-20);
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius-xl, 1.25rem);
    width: 100%;
    overflow: hidden;
}

/* Двух-колоночный ряд: ширина = full, gap-8, fill columns. */
.case-misc__row--cols {
    background: transparent;
    padding-block: 0;
    height: auto;
    gap: var(--space-8);
}

.case-misc__col {
    flex: 1 0 0;
    min-width: 0;
    height: 296px;
    padding-block: var(--space-20);
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius-xl, 1.25rem);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Колонка со СМЕЩЁННЫМИ телефонами (ряд 5): два телефона позиционированы
   absolute с overflow-clip контейнера. */
.case-misc__col--stacked {
    position: relative;
    overflow: hidden;
}

.case-misc__col--stacked .device {
    position: absolute;
}

/* Левый телефон в stacked-колонке — снизу-слева.
   left привязан к центру колонки через calc(50% − offset), чтобы
   композиция оставалась центрированной при любой ширине контейнера
   (на мобиле колонка растягивается до 100%). На десктопной ширине
   296px формула даёт те же 40.25px, что и исходный макет. */
.case-misc__col--stacked .device:nth-child(1) {
    left: calc(50% - 107.75px);
    top: 70px;
}

/* Правый телефон — сверху-справа (overflow обрежет, как в Figma). */
.case-misc__col--stacked .device:nth-child(2) {
    left: calc(50% - 10px);
    top: -41.2px;
}

/* Адаптив: ≤ 767px — каждый ряд получает горизонтальный скролл.
   Контент не стекается в колонку, не уменьшается; пользователь свайпает. */
@media (max-width: 767px) {
    .case-misc__row {
        justify-content: flex-start;
        overflow-x: auto;
        padding-inline: var(--space-20);
        /* Прячем нативный скролл-бар на мобильном — UX чище. */
        scrollbar-width: none;
    }
    .case-misc__row::-webkit-scrollbar {
        display: none;
    }

    /* Колоночные ряды на мобиле стекаются вертикально и НЕ скроллятся:
       каждая колонка занимает всю доступную ширину секции, телефон
       центрируется внутри. Сбрасываем унаследованный от .case-misc__row
       padding-inline — внутренние колонки должны доходить до краёв
       контейнера, без двойного отступа. */
    .case-misc__row--cols {
        flex-direction: column;
        padding-inline: 0;
        overflow-x: visible;
    }

    .case-misc__row--cols .case-misc__col {
        width: 100%;
        flex: none;
    }
}

/* ---------------- Feature section («01. ...») ----------------
   Повторяющийся блок одной фичи в кейсе. Состоит из:
     • Заголовка («01. Название»)
     • Sub-блоков: Контекст / Решение / Результат (текст + стат-сетка)
     • Showcase'ов с телефонами (1, 2 или 3 в ряд)
     • Анимационных плейсхолдеров

   Ширина 861px (шире чем текст-контент 600), чтобы вместить 3 телефона
   в ряд. Текстовые подблоки центрируются и держат макс 600 для читаемости.
   ---------------------------------------- */

.case-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-24);
    width: 100%;
    max-width: var(--card-width); /* 600px — как и весь остальной контент кейса */
    margin-inline: auto;
    margin-top: var(--space-120); /* доп. spacer между case-секциями: 120 + .case gap 120 = 240 */
    /* Showcase'ы с телефонами могут «вылетать» за 600 (как Hug в Figma) —
       не клипуем по горизонтали. */
}

/* Заголовок секции + текстовые подблоки ограничены шириной читаемой колонки. */
.case-section__title,
.case-section__subblock {
    width: 100%;
    max-width: var(--card-width);
}

.case-section__subblock {
    display: flex;
    flex-direction: column;
    gap: 6px; /* заголовок → текст (одноразовая величина) */
    align-items: flex-start;
}

.case-section__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-8); /* между параграфами */
    color: var(--color-text-secondary);
}

/* Результаты — 3 стата в ряд с pt-14 (одноразовая величина из Figma). */
.case-section__results-grid {
    display: flex;
    gap: var(--space-24);
    align-items: flex-start;
    width: 100%;
    padding-top: 14px;
}

.case-section__stat {
    flex: 1 0 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.case-section__stat-label {
    opacity: 0.7;
}

/* Showcase: ряд телефонов. Hug-ширина (как в Figma): блок берёт содержимое
   и центрируется в родителе через .case-section align-items: center.
   На десктопе — БЕЗ wrap'а: 3 телефона спокойно выходят за 600 контента.
   На ≤1023 включается wrap (если не помещается в viewport). */
.case-section__phones {
    display: flex;
    gap: var(--space-40);
    align-items: center;
    justify-content: center;
    padding-block: var(--space-32);
    border-radius: var(--radius-tile);
}

/* Авто-spacer: любой subblock, идущий ПОСЛЕ визуального шоукейса (телефоны,
   компэр, анимация, баннеры) получает дополнительный padding-top.
   CSS делает это автоматически через sibling-селектор — без модификаторов
   класса в HTML, чтобы не забыть ни в одном месте. */
.case-section__phones + .case-section__subblock,
.case-section__compare + .case-section__subblock,
.case-section__animation + .case-section__subblock,
.case-section__banners + .case-section__subblock {
    padding-top: var(--space-32);
}

/* Showcase «До / После» — две колонки рядом с подписями.
   В правой может быть несколько телефонов в ряд (через __compare-row).
   Hug-ширина, без wrap'а на десктопе. Gap унифицирован с compare-row (40). */
.case-section__compare {
    display: flex;
    gap: var(--space-40);
    align-items: center;
    justify-content: center;
    padding-block: var(--space-32);
}

.case-section__compare-column {
    display: flex;
    flex-direction: column;
    gap: var(--space-24); /* подпись «До/После» → телефон */
    align-items: center;
}

.case-section__compare-label {
    text-align: center;
    color: var(--color-text-primary);
}

.case-section__compare-row {
    display: flex;
    gap: var(--space-40);
    align-items: center;
    justify-content: center;
}

/* ≤1023px (планшет): showcase'ы оборачиваются, чтобы не выходить за viewport. */
@media (max-width: 1023px) {
    .case-section__phones,
    .case-section__compare,
    .case-section__compare-row {
        flex-wrap: wrap;
        max-width: calc(100vw - var(--content-padding-x) * 2);
    }
}

/* ≤767px (мобила): всё стекается вертикально, единый gap-40 между телефонами. */
@media (max-width: 767px) {
    .case-section__phones,
    .case-section__compare,
    .case-section__compare-row {
        flex-direction: column;
        gap: var(--space-40);
    }
}

/* --stacked: до/после идут не рядом (как в секции 02), а друг под другом.
   Gap у compare-row общий — var(--space-40). */
.case-section__compare--stacked {
    flex-direction: column;
    gap: var(--space-40);
}

.case-section__compare--stacked .case-section__compare-column {
    width: auto;
}

/* Banner showcase — 2 категории (Системные / Рекламные), в каждой
   ряды по 2 баннера-плейсхолдера. Сами «настоящие» баннеры — мини-
   карточки из приложения; пока ставим placeholder под скриншот. */
.case-section__banners {
    display: flex;
    flex-direction: column;
    gap: var(--space-24);
    width: 100%;
    padding-block: var(--space-32);
}

.case-section__banner-label {
    color: var(--color-text-primary);
    text-align: center;
}

.case-section__banner-row {
    display: flex;
    gap: var(--space-12);
    align-items: flex-start; /* баннеры разной высоты — не растягиваем */
    width: 100%;
}

.case-section__banner {
    flex: 1 0 0;
    min-width: 0;
    /* Плейсхолдер (если картинки ещё нет): aspect ratio для размера */
    aspect-ratio: 292 / 100;
    background: rgba(255, 255, 255, 0.1);
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-16);
    text-align: center;
    color: var(--color-text-primary);
    overflow: hidden;
}

/* Когда внутри картинка — снимаем плейсхолдерные стили: фон, padding,
   фиксированную пропорцию и радиус (картинка уже содержит свой). */
.case-section__banner:has(img) {
    background: transparent;
    padding: 0;
    aspect-ratio: auto;
    border-radius: 0;
    overflow: visible;
}

.case-section__banner img {
    width: 100%;
    height: auto; /* натуральная высота — у разных баннеров она разная */
    display: block;
}

@media (max-width: 767px) {
    .case-section__banner-row {
        flex-direction: column;
        gap: var(--space-16);
    }

    .case-section__banner {
        /* flex: none — не растягивать через grow/shrink; ширина — 100% колонки,
           высота — натуральная высота картинки внутри. */
        flex: none;
        width: 100%;
        aspect-ratio: auto;
    }

    /* Только пустой плейсхолдер (без img) сохраняет минимальную высоту. */
    .case-section__banner:not(:has(img)) {
        min-height: 80px;
    }
}

/* Анимация-плейсхолдер: квадратная подложка с подписью посередине.
   aspect-ratio 1:1 — высота всегда = ширине.
   Когда внутри <video> — снимаем плейсхолдерные стили, видео покрывает блок. */
.case-section__animation {
    background: rgba(255, 255, 255, 0.1);
    border-radius: var(--radius-tile);
    padding: var(--space-48);
    width: 100%;
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-primary);
    text-align: center;
    overflow: hidden;
}

/* Когда внутри видео — контейнер становится портретным (9:16) под пропорции
   снятого материала, шириной до 608px и центрируется в секции. object-fit: cover
   на самом video кропит запечённые «уши» по бокам, оставляя только портретный кадр. */
.case-section__animation:has(video) {
    background: transparent;
    padding: 0;
    aspect-ratio: 9 / 16;
    max-width: 608px;
}

.case-section__animation video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: var(--radius-tile);
}

@media (max-width: 767px) {
    .case-section__results-grid {
        flex-direction: column;
    }

    /* Анимация — aspect-ratio: 1/1 наследуется, меняем только padding на мобиле. */
    .case-section__animation {
        padding: var(--space-24);
    }
}

/* ================================================================
   Адаптив компонентов ≤ 767px (мобила):
     • Медиа-тайлы строятся в колонку (друг под другом, до 440px шириной).
   ================================================================ */
@media (max-width: 767px) {
    .project-card__media {
        flex-direction: column;
        align-items: center;
    }

    .project-card__media-item {
        flex: none;
        width: 100%;
        max-width: 440px;
    }
}


/* ================================================================
   Site footer — две колонки: копирайт слева, ссылка на политику справа.
   Нулевые паддинги (плотно к нижнему краю), горизонтальное выравнивание
   под контентную колонку через --content-padding-x.
   ================================================================ */
.site-footer {
    width: 100%;
    max-width: var(--card-width);
    margin: 0 auto;
    padding: 0 var(--content-padding-x) var(--space-24);
    display: flex;
    justify-content: center;
    color: var(--color-text-secondary);
}

/* ================================================================
   Ink-underline — обёртка ключевой фразы под эффект rough-notation
   (см. src/scripts/ink-underline.js).

   Цель: фраза «выходит вперёд» из тела текста — становится 100%
   белой против фоновой :secondary (rgba 255 .7), а маркер сверху
   рисует SVG-обводку фирменным голубым (#24A8FF — задаётся в JS).
   ================================================================ */
.ink-underline {
    color: var(--color-text-primary);
}

.site-footer__copyright {
    color: var(--color-text-secondary);
    margin: 0;
}
