/* Страница направления Centris Print Cup.
 *
 * Раскладка и поведение сняты с cupprint.com (спецификация —
 * docs/cup-page-spec.md), но оформление наше: острые углы вместо
 * скруглений, полоса цвета суб-бренда по верхней кромке, пунктир-биговка
 * как разделитель. Декоративные фигуры образца не переносились.
 *
 * Отдельным файлом, а не в resources/css/app.css: node на рабочей машине
 * не установлен, npm run build выполнить нельзя, а Tailwind собирает
 * только те классы, что были в шаблонах на момент сборки. Этот файл
 * отдаётся как есть.
 */

.cupx {
    /* Шаг вертикальной сетки. Расстояние между любыми двумя блоками
       страницы складывается из нижнего отступа верхнего и верхнего
       отступа нижнего, поэтому все секции берут отступы отсюда — тогда
       промежуток везде одинаковый. Раньше каждая секция назначала себе
       свой, и полоса с роликами прижималась к соседней вдвое плотнее
       остальных, а лента работ упиралась в блок отзывов вплотную.
     *
     * Имя не `--cupx-gap`: так уже называется просвет между кадрами
     * в бегущих лентах (.cupx-track), и объявленный на body шаг секций
     * перебивал бы его запасное значение во всякой ленте, которой его
     * не задали в разметке. */
    --cupx-rhythm: clamp(48px, 6vw, 92px);

    /* Самый крупный текст страницы — размер заголовков секций («Что мы
       делаем»): так решил владелец. Заголовок первого экрана и подписи
       3D-секции ограничены им же (min(…, var(--cupx-text-max))). */
    --cupx-text-max: clamp(26px, 3.2vw, 42px);

    --cup: #2b8a63;
    --cup-ink: #1e6b4c;
    --cup-wash: #eef5f1;
    --cup-deep: #123b2b;
    /* Светлая подложка полосы с видео. Ею же залиты все поверхности,
       что прежде были чисто белыми: белый лист рядом с этой полосой
       читался как другой оттенок бумаги, а не как та же страница. */
    /* Два фона на всю страницу и больше никаких. Секции идут через одну:
       белая, дымчатая, белая — чередование и держит ритм вместо цветных
       заливок, которые тут были раньше. Зелёный остался только у самих
       предметов: кнопок, значков, панели первого экрана. */
    --cup-paper: #f5f5f7;
    --cupx-mist: #f5f5f7;
    --cupx-white: #ffffff;
    --paper: #f4f1ea;
    --paper-warm: #fbfaf7;
    --paper-deep: #e8e2d6;
    --ink: #15171c;
    --ink-soft: #3a3e47;
    --ink-muted: #5e626b;
    --ink-faint: #82868f;
    --line: #d5d2cd;
}

/* ── Общие детали раздела ────────────────────────────────────────── */

/* Заголовок секции. У образца это скруглённая «таблетка»; у нас плоский
   блок цвета без радиуса — тот же приём, наша геометрия. */
/* Заголовок секции — просто текст. Прежде это была плашка цвета
   направления с белым текстом; заливку сняли, и держать заголовок
   теперь должны кегль и цвет, а не прямоугольник под ним. */
.cupx-heading {
    display: block;
    color: var(--ink);
    font-size: var(--cupx-text-max);
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.02em;
}

/* На цветной секции текст остаётся белым: без него заголовок
   потерялся бы в тёмно-зелёной заливке блока. */
.cupx-on-color .cupx-heading {
    color: #fff;
}

.cupx-lead {
    max-width: 62ch;
    margin-top: 26px;
    font-size: 17px;
    line-height: 1.65;
    color: var(--ink-muted);
}

.cupx-section {
    padding-block: var(--cupx-rhythm);
}

.cupx-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-top: 34px;
}

/* Кнопки. Форма наша — прямоугольник без радиуса; цвет берётся от
   суб-бренда, а не от общего оранжевого акцента сайта. */
/* Таблетка, а не прямоугольник. Отступление от общей геометрии сайта
   намеренное и только на этой странице: раскладка здесь снята с образца,
   и там же, где появилась скруглённая панель и круглые стрелки,
   прямоугольная кнопка выглядела бы забытой. */
.cupx-btn,
.cupx-btn-ghost {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 17px 32px;
    border-radius: 999px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.01em;
    transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}

/* Заливка берётся не от фирменного `--cup`, а от его тёмного варианта:
   белым по #2b8a63 выходит 4.27:1, то есть чуть ниже порога читаемости
   для кегля кнопки. `--cup-ink` для того в палитре и заведён — 6.9:1.
   Светлый фирменный остаётся там, где он и работает: на плашках
   заголовков и в панели героя, где текст крупный. */
.cupx-btn {
    background: var(--cup-ink);
    color: #fff;
}

.cupx-btn:hover {
    background: #17573d;
}

.cupx-btn-ghost {
    border: 1px solid currentColor;
    color: var(--cup-ink);
}

.cupx-btn-ghost:hover {
    background: var(--cup);
    border-color: var(--cup);
    color: #fff;
}

.cupx-on-color .cupx-btn {
    background: var(--cup-paper);
    color: var(--cup-ink);
}

.cupx-on-color .cupx-btn:hover {
    background: var(--paper-deep);
}

.cupx-on-color .cupx-btn-ghost {
    color: #fff;
}

.cupx-on-color .cupx-btn-ghost:hover {
    background: var(--cup-paper);
    color: var(--cup-ink);
}

/* Круглые стрелки слайдеров — единственное скругление, которое мы взяли
   у образца: это орган управления, а не украшение, и квадратная стрелка
   читается хуже. */
.cupx-arrows {
    display: flex;
    gap: 10px;
}

/* 43px — на десятую меньше прежних 48: крупные кружки спорили с подписью
   слайда. От этой высоты считается и отступ подписи под стрелками. */
.cupx-arrows button {
    width: 43px;
    height: 43px;
    border-radius: 50%;
    /* Залитый кружок цвета направления, а не светлая кнопка с ободком:
       на первом экране такие читались лучше всего, и раздел выровнен
       по ним. Ободок оставлен прозрачным, чтобы размер кнопки совпадал
       с вариантом на цветном фоне, где ободок видимый. */
    border: 1px solid transparent;
    background: var(--cup-ink);
    color: #fff;
    font-size: 18px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.cupx-arrows button svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.cupx-arrows button:hover {
    background: var(--cup);
    border-color: transparent;
    color: #fff;
}

.cupx-arrows button[disabled] {
    opacity: 0.35;
    pointer-events: none;
}

.cupx-on-color .cupx-arrows button {
    border-color: rgba(255, 255, 255, 0.45);
    background: transparent;
    color: #fff;
}

.cupx-on-color .cupx-arrows button:hover {
    background: var(--cup-paper);
    color: var(--cup-ink);
}

/* Плейсхолдер там, где снимка ещё нет. Честно подписан: серая заливка
   без подписи выглядит как незагрузившаяся картинка. */
.cupx-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 24px;
    background: var(--paper-deep);
    color: var(--ink-faint);
    font-size: 12px;
    line-height: 1.4;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.12em;
}

.cupx-placeholder svg {
    width: 38px;
    height: 38px;
    opacity: 0.5;
}

/* ── 1. Герой ────────────────────────────────────────────────────── */

/* Первый экран — зелёный во всю ширину, шапка лежит поверх него.
 *
 * Секция подтянута под шапку на её высоту (--cupx-header-h ставит
 * cup-page.js; 73px — запас до скрипта: 72px строки и 1px кромки)
 * и на столько же выше отступ сверху, поэтому содержимое стоит там же,
 * где стояло бы под шапкой. Пока экран виден, шапка прозрачная и зелень
 * идёт сплошной — см. «Шапка поверх первого экрана» ниже.
 *
 * Глубина — не картинкой, а тремя слоями градиента: светлое пятно
 * справа, за стаканами, тень в левом нижнем углу и основной переход
 * от фирменного зелёного к глубокому. */
.cupx-hero {
    --hero-header: var(--cupx-header-h, 73px);
    position: relative;
    isolation: isolate;
    overflow: hidden;
    margin-top: calc(-1 * var(--hero-header));
    padding-block: calc(var(--hero-header) + clamp(24px, 4vw, 64px)) clamp(48px, 6vw, 96px);
    background:
        radial-gradient(55% 75% at 76% 44%, rgba(120, 214, 168, 0.26) 0%, rgba(120, 214, 168, 0) 62%),
        radial-gradient(80% 110% at 0% 100%, rgba(10, 44, 31, 0.55) 0%, rgba(10, 44, 31, 0) 60%),
        linear-gradient(140deg, #217a55 0%, #1b6547 46%, #134b36 100%);
    color: #fff;
}

.cupx-hero-inner {
    display: grid;
    grid-template-columns: minmax(0, 1.04fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(16px, 2.5vw, 48px);
    min-height: min(640px, calc(100svh - var(--hero-header) - 140px));
}

.cupx-hero-panel {
    position: relative;
    padding-block: clamp(12px, 2vw, 32px);
    color: #fff;
}

.cupx-hero-panel h1 {
    font-size: clamp(38px, 5vw, 66px);
    font-weight: 700;
    line-height: 1.06;
    letter-spacing: -0.035em;
}

.cupx-hero-sub {
    margin-top: 20px;
    font-size: clamp(18px, 2vw, 24px);
    line-height: 1.3;
    color: rgba(255, 255, 255, 0.9);
}

/* Абзацы — белым в 80%: на глубоком зелёном это 7:1 и выше, а полный
   белый спорил бы с заголовком. */
.cupx-hero-panel p:not(.cupx-hero-sub) {
    margin-top: 20px;
    max-width: 52ch;
    font-size: 16px;
    line-height: 1.65;
    color: rgba(255, 255, 255, 0.8);
}

.cupx-hero .cupx-actions {
    margin-top: 38px;
}

/* Карусель на зелёном: свет за стаканом белый, а не зелёный, под
   стаканом — тень-подиум, подпись и стрелки — светлые. */
.cupx-hero .cupx-slides::before {
    background: radial-gradient(circle, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.06) 44%, transparent 70%);
}

.cupx-hero .cupx-slide {
    z-index: 1;
}

.cupx-hero .cupx-slides::after {
    content: "";
    position: absolute;
    z-index: 0;
    /* Под текущим стаканом: он сдвинут от центра на 18% ширины кадра. */
    left: 32%;
    bottom: calc(var(--cupx-caption) + clamp(22px, 2.6vw, 40px));
    width: 46%;
    height: 34px;
    transform: translate(-50%, 50%);
    border-radius: 50%;
    background: radial-gradient(closest-side, rgba(6, 30, 21, 0.45), rgba(6, 30, 21, 0));
    pointer-events: none;
}

.cupx-hero .cupx-slide strong {
    color: #fff;
}

.cupx-hero .cupx-arrows button {
    border-color: rgba(255, 255, 255, 0.38);
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
}

.cupx-hero .cupx-arrows button:hover {
    border-color: #fff;
    background: #fff;
    color: var(--cup-ink);
}

/* ── 1а. Первый экран: 3D-карусель ──────────────────────────────── */

/* Сменил прежний первый экран (x-cp.cup.hero) по передаче
 * centris-cup3d-handoff-v7. Сцена с подписью и вкладками — модуль
 * в Shadow DOM (resources/js/cup3d), заголовок над ней — разметка
 * страницы. Кегли, цвета и отступы заголовка сняты с передачи
 * (styles.css модуля, .intro и её @container-правила), поэтому
 * снаружи и внутри он читается одним экраном.
 *
 * Правила идут после .cupx-hero и перебивают его отступы и фон
 * порядком: класс cupx-hero у секции оставлен ради прозрачной шапки.
 * Ширины в @container — ширина самой секции, как у модуля. */
.cupx-showroom {
    /* Край сетки сайта (.shell): подписи и кнопки сцены встают на одну
       линию с заголовком и логотипом в шапке. Поле .shell берём
       у redesign/editorial.css — оно там перебивает поле из app.css.
       Проценты считаются уже внутри модуля, от ширины сцены, — а она
       во всю ширину окна, как и родитель .shell. */
    --cup3d-pad: clamp(22px, 5vw, 80px);
    --cup3d-edge: max(var(--cup3d-pad), (100% - 1440px) / 2 + var(--cup3d-pad));

    container-type: inline-size;
    padding-block: var(--hero-header) 0;
    /* Градиент передачи (.showroom) — на всю секцию, от кромки окна под
       прозрачной шапкой до кнопок внизу. Внутри модуля он снят, иначе
       на стыке заголовка и сцены встали бы два градиента со швом. */
    background: radial-gradient(ellipse at 51% 49%, #337354 0%, #205a44 31%, #164a39 61%, #0e362c 100%);
    color: #f4f6ed;
}

/* Заголовок слева, строки справа, низом по одной линии. Сцена
   подтянута под заголовок на 20px, как в передаче, и тянуть её можно
   сквозь заголовок: ссылок в нём нет. */
.cupx-showroom-intro {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 32px;
    padding-top: 40px;
    pointer-events: none;
}

.cupx-showroom-eyebrow {
    margin: 0 0 17px;
    font-size: 11px;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: #b8cbac;
}

/* Заголовок — в одну строку и размером с заголовки секций (владелец:
   крупнее них на странице ничего нет). На узком экране кегль ещё меньше —
   ровно настолько, чтобы строка влезла: делитель — ширина строки
   в кеглях с запасом, своя у каждого языка (--showroom-title-em ниже).
   Тот же кегль заложен в высоту заголовка у .cupx-showroom-stage. */
.cupx-showroom {
    /* «Реклама, которую держат в руках» — 16.4 кегля в ширину,
       «Qo‘llarda yuradigan reklama» — 12.9, «Advertising held in every
       hand» — 14.1 (замерено в браузере шрифтом страницы, 23.09).
       Сменится заголовок — замерить заново. */
    --showroom-title-em: 16.7;
}

:lang(uz) .cupx-showroom {
    --showroom-title-em: 13.3;
}

:lang(en) .cupx-showroom {
    --showroom-title-em: 14.4;
}

.cupx-showroom h1 {
    margin: 0;
    font-size: min(var(--cupx-text-max), (100cqw - 2 * var(--cup3d-pad)) / var(--showroom-title-em));
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.02em;
    white-space: nowrap;
    color: #f4f6ed;
}

.cupx-showroom h1 span {
    color: #d8e9b4;
}

.cupx-showroom-copy {
    flex: 0 1 400px;
    margin: 0 0 4px;
    padding-left: 20px;
    font-size: 16px;
    line-height: 1.65;
    color: #e4ecdf;
}

.cupx-showroom-copy span {
    display: block;
    margin-top: 12px;
    font-size: 14px;
    color: #a4c1ae;
}

/* Сцена. Её высоту модуль берёт из --cup3d-stage-h (site.css).
 *
 * В передаче сцена — clamp(340px, 43cqw, 550px), и на ноутбуке 1440×900
 * вкладки выбора уезжали под нижний край окна. Здесь она ещё и не выше,
 * чем остаётся от окна за шапкой, заголовком и подписью с вкладками;
 * на 1920×1080 это те же 550. Высоту заголовка считаем из его правил:
 * отступ сверху, надзаголовок в строку по 1.5 и его отступ, две строки
 * h1 по 1.045. cqw в переменных считаются там, где их берут, — и здесь,
 * и внутри модуля это ширина секции. */
.cupx-showroom-stage {
    --showroom-h1: min(var(--cupx-text-max), (100cqw - 2 * var(--cup3d-pad)) / var(--showroom-title-em));
    --showroom-intro: calc(40px + 1.08 * var(--showroom-h1));
    /* Под сценой в первый экран уходят название со стрелками (43 и 28
       отступа), кнопка заявки (8 + 51) и воздух снизу. */
    --showroom-below: 146px;
    --cup3d-stage-h: clamp(340px,
        min(43cqw, 100svh - var(--hero-header) - var(--showroom-intro) + 20px - var(--showroom-below)),
        550px);

    position: relative;
    z-index: 1;
    margin-top: -20px;
    /* Место под сцену с названием до того, как модуль его нарисует:
       иначе всё ниже первого экрана прыгнуло бы на загрузке. 71 — строка
       названия со стрелками и отступ под ней (.selection). */
    min-height: calc(var(--cup3d-stage-h) + 71px);
}

/* Кнопка заявки — под названием модели, по его оси: выбрал упаковку —
   оставил заявку. Прежний первый экран держал кнопки под заголовком, но
   в композиции передачи места там нет. «Контакты» сняты владельцем. */
.cupx-showroom .cupx-showroom-actions {
    justify-content: center;
    margin-top: 0;
    padding-block: 8px clamp(40px, 5cqw, 64px);
}

.cupx-showroom .cupx-btn {
    background: #dfedb4;
    color: #153c2e;
}

.cupx-showroom .cupx-btn:hover {
    background: #eef6d4;
}

.cupx-showroom .cupx-btn-ghost {
    border-color: rgba(255, 255, 255, 0.35);
    color: #f4f6ed;
}

.cupx-showroom .cupx-btn-ghost:hover {
    border-color: #f4f6ed;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
}

@container (min-width: 1700px) {
    .cupx-showroom-intro {
        padding-top: 55px;
    }

    .cupx-showroom-stage {
        --showroom-intro: calc(55px + 1.08 * var(--showroom-h1));
        --cup3d-stage-h: clamp(340px,
            100svh - var(--hero-header) - var(--showroom-intro) + 20px - var(--showroom-below),
            590px);
        --showroom-below: 154px;
        min-height: calc(var(--cup3d-stage-h) + 79px);
    }
}

/* Планшет: у передачи сцена здесь 425px и под заголовок не заходит. */
@container (max-width: 1000px) {
    .cupx-showroom-intro {
        padding-top: 34px;
    }

    .cupx-showroom-copy {
        flex-basis: 320px;
        font-size: 14px;
    }

    .cupx-showroom-copy span {
        font-size: 12px;
    }

    .cupx-showroom-stage {
        --showroom-intro: calc(34px + 1.08 * var(--showroom-h1));
        --cup3d-stage-h: clamp(340px,
            100svh - var(--hero-header) - var(--showroom-intro) - var(--showroom-below),
            425px);
        margin-top: 0;
    }
}

/* Телефон: заголовок в столбик, под сценой — название со стрелками. */
@container (max-width: 640px) {
    .cupx-showroom-intro {
        display: block;
        padding-top: 30px;
    }

    .cupx-showroom-eyebrow {
        margin-bottom: 13px;
        font-size: 9px;
        letter-spacing: 2.1px;
    }

    .cupx-showroom-copy {
        display: none;
    }

    .cupx-showroom-stage {
        --showroom-intro: calc(30px + 1.08 * var(--showroom-h1));
        --showroom-below: 158px;
        --cup3d-stage-h: clamp(300px,
            100svh - var(--hero-header) - var(--showroom-intro) - var(--showroom-below),
            375px);
        min-height: calc(var(--cup3d-stage-h) + 83px);
    }

    .cupx-showroom .cupx-showroom-actions {
        padding-inline: var(--cup3d-edge);
    }
}

/* ── Шапка поверх первого экрана ── */

/* Прозрачная, пока первый экран под ней: зелень героя идёт сплошной
   от верхней кромки окна. Класс `cupx-header-solid` ставит cup-page.js,
   когда экран уехал из-под шапки, — и она снова своего зелёного цвета.
   По умолчанию прозрачная, а не наоборот: страница открывается сверху,
   и шапка не должна мигнуть сплошной до первого кадра скрипта. */
body.cupx > header {
    transition: background-color 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease;
}

body.cupx:not(.cupx-header-solid) > header {
    background: transparent !important;
    border-bottom-color: rgba(255, 255, 255, 0.12) !important;
    box-shadow: none;
}

/* Страницу чуть прокрутили, а первый экран ещё под шапкой: его текст
   и кнопки уезжают под неё, и сквозь прозрачную шапку они ложились
   поверх логотипа и меню. Здесь шапка — полупрозрачный зелёный
   с размытием: зелень героя сквозь неё видна, текст — нет. */
body.cupx.cupx-header-scrolled:not(.cupx-header-solid) > header {
    background: rgba(24, 92, 66, 0.82) !important;
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
}

.cupx-kicker {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: rgba(255, 255, 255, 0.7);
}

/* Правая половина — чистая бумага. У образца стакан стоит на белом, и
   весь вес кадра держит само изделие; цветная подложка под ним только
   спорила с панелью слева. */
.cupx-hero-media {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 22px;
    padding: clamp(12px, 2vw, 30px);
}

/* Сцена — кадр, подпись и стрелки одним блоком. Раньше кадр висел сам
   по себе в середине подложки, а стрелки с точками стояли строкой
   в нижнем углу и с ним не связывались ничем. */
.cupx-stage {
    position: relative;
    /* Запас под кадром: сверху ряд стрелок, под ним название в две
       строки. Держим величину здесь, а не на .cupx-slides, потому что
       по ней равняются и стрелки — а они этой сцене соседи, не потомки. */
    --cupx-caption: 124px;
}

/* Мягкое пятно света под изделием. Подложка первого экрана — чистая
   бумага, и стакан на ней висел в пустоте; пятно даёт ему место, на
   котором он стоит, и не спорит с панелью слева, потому что взято
   из цвета направления на четыре процента. */
.cupx-slides::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 46%;
    width: min(78%, 520px);
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(43, 138, 99, 0.10) 0%, rgba(43, 138, 99, 0.04) 46%, transparent 70%);
    pointer-events: none;
}

.cupx-slides {
    position: relative;
    /* Кадр занимает подложку целиком: маленький стакан посреди большого
       поля читался как заглушка, а не как витрина. Подняли на высоту
       ряда стрелок: полоса под кадром выросла со 78 до 124 пикселей,
       и без запаса стакан ужался бы ровно на эту разницу. */
    /* Запас сверху под наклон. Стакан в кадре повёрнут на 6–8°, и край,
       который при повороте поднимается, выходил выше этой коробки — а она
       обрезает всё за кромкой: у двухслойного стакана срезало верх ободка
       ровной линией. На запас коробка и выросла, чтобы стаканы не
       уменьшились. */
    --cupx-headroom: clamp(28px, 3vw, 44px);
    min-height: calc(clamp(386px, 30vw, 486px) + var(--cupx-headroom));
    /* Кадры уезжают вбок — за кромкой их обрезает эта коробка. */
    overflow: hidden;
    /* Глубина для поворота кадров при листании. Без перспективы
       `rotateY` вырождается в простое сжатие по горизонтали. Чем
       короче фокус, тем сильнее расхождение ближнего и дальнего края
       кадра — и тем заметнее объём. */
    perspective: 900px;
    perspective-origin: 50% 45%;
}

/* Верхняя строка — кадр, нижняя — подпись. Подпись стоит на своей
   высоте и не гуляет от того, что у одного стакана название в строку,
   а у другого в две. */
.cupx-slide {
    position: absolute;
    inset: 0;
    display: grid;
    padding-top: var(--cupx-headroom, 0px);
    /* Нижняя строка — подпись. Держим её запас в переменной, потому что
       на ту же величину равняются стрелки: при жёстких 62px название
       в две строки выдавливало объёмы за нижнюю кромку, а `overflow`
       сцены их дорезал — строка с миллилитрами пропадала совсем. */
    grid-template-rows: minmax(0, 1fr) minmax(var(--cupx-caption), auto);
    justify-items: center;
    /* Просвет между изделием и подписью шире прежних 14px: подпись со
       стрелками отошла от кадра и читается отдельной строкой, а не
       подножием стакана. */
    gap: clamp(22px, 2.6vw, 40px);
    /* Сам слайд не ездит: он держит подпись, а она стоит на месте.
       Ездит и поворачивается только кадр — см. .cupx-shot ниже. */
    visibility: hidden;
}

/* Видны три состояния: текущий кадр, следующий за ним и уходящий, пока
   доигрывает. Остальные ждут за правой кромкой. */
.cupx-slide.is-active,
.cupx-slide.is-next,
.cupx-slide.is-gone {
    visibility: visible;
}

/* Кадр, которому надо перескочить через сцену, встаёт на новое место
   мгновенно — класс ставит скрипт (cup-page.js, `is-instant`). Так
   ушедший влево возвращается в ждущие справа, а при листании назад
   ждущий справа — в ушедшие слева. Проезд через всю сцену был бы виден:
   при листании назад кадры улетали влево, а при частых нажатиях шли
   друг поверх друга. */
.cupx-slide.is-instant .cupx-shot {
    transition: none;
}

/* Текущий кадр всегда поверх соседей: при частом листании уходящий
   и следующий ещё в пути и проходят через середину сцены. */
.is-active .cupx-shot { z-index: 3; }
.is-next .cupx-shot { z-index: 2; }
.is-gone .cupx-shot { z-index: 1; }

/* До первой отрисовки не двигается вообще ничего: карусель раздаёт
   классы сразу всем кадрам, и без этого на загрузке по сцене проезжал
   лишний стакан. Класс ставит скрипт после первого кадра. */
[data-cup-slider]:not(.is-ready) .cupx-shot {
    transition: none;
}

/* Подпись — только у текущего. У следующего она осталась бы второй
   строкой поверх первой. Уходящая гаснет сразу, без плавного угасания:
   иначе при частом листании две-три подписи на миг стояли одна на
   другой. Проявляется новая — с небольшой задержкой, когда кадр уже
   в пути. */
.cupx-slide figcaption {
    opacity: 0;
    transition: none;
}

.cupx-slide.is-active figcaption {
    opacity: 1;
    transition: opacity 0.3s ease 0.12s;
}

/* Кадр: два стакана под встречными углами. Одиночный снимок анфас
   посреди пустой подложки выглядел как фотография из прайса; пара
   под углом даёт кадру глубину и объём. Наклон статический —
   стакан стоит под углом, а не качается: движение в первом экране
   тянет взгляд на себя и мешает читать заголовок рядом. */
/* Кадр ездит, поворачивается и меняет масштаб. Четыре положения:
   текущий по центру, следующий — уменьшенным справа (по нему видно,
   что в ряду есть продолжение), уходящий улетает влево, все прочие
   ждут за правой кромкой. Поворот по Y даёт объём: кадры не скользят
   плоскостями, а разворачиваются к зрителю. */
.cupx-shot {
    position: relative;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    width: 100%;
    min-height: 0;
    /* Ждущее положение — вплотную за правой кромкой сцены, ровно
       настолько, чтобы обрезка кадр скрыла.
     *
     * Раньше здесь стояло 185%, и в этом была вся беда. Перспектива
     * поджимает дальний кадр к центру ещё на четверть, так что из-за
     * кромки он выходил только на последней трети пути — а кривая
     * перехода к этому времени уже тормозила. Получалось, что стакан
     * не выезжает сбоку, а проявляется почти на своём месте. Теперь
     * весь путь от кромки до превью проходит на глазах. */
    transform: translateX(96%) translateZ(-260px) rotateY(-30deg) scale(0.42);
    opacity: 1;
    /* Дольше и мягче на выходе: кривая почти без разгона в конце, отчего
       кадр не тормозит рывком, а доезжает. */
    transition: transform 0.85s cubic-bezier(0.32, 0.72, 0, 1),
                opacity 0.6s ease;
}

.is-active .cupx-shot {
    transform: translateX(-18%) translateZ(0) rotateY(0deg) scale(1);
    opacity: 1;
}

/* Превью отодвинуто и по горизонтали, и в глубину: одно только
   уменьшение читается как «маленький стакан рядом», а сдвиг по Z
   вместе с поворотом — как «стоит дальше». Приглушённая яркость
   работает на то же. */
.is-next .cupx-shot {
    transform: translateX(36%) translateZ(-260px) rotateY(-26deg) scale(0.42);
    opacity: 0.85;
}

/* Назад уходит с поворотом в другую сторону — иначе движение вперёд
   и назад выглядят одинаково. */
.is-gone .cupx-shot {
    /* Уходит так же за кромку и так же непрозрачным: кадр уезжает
       со сцены, а не растворяется на ней. Здесь запас чуть больше —
       уходящий кадр крупнее превью и скрывается за кромкой позже. */
    transform: translateX(-112%) translateZ(-180px) rotateY(28deg) scale(0.7);
    opacity: 1;
}

.cupx-shot-main {
    position: relative;
    z-index: 2;
    flex: 0 1 auto;
    max-height: 100%;
    /* Потолок по ширине. Без него стакан упирался в высоту подложки
       и занимал весь первый экран. Ужат с 74%, чтобы текущий кадр
       и превью следующего разошлись на видимый просвет: сцена обрезает
       всё, что вышло за кромку, и разводить их, не сузив предмет,
       некуда. Высоких стаканов это почти не касается — им размер
       задаёт высота подложки, а не эта доля. */
    max-width: 60%;
    width: auto;
    transform-origin: 50% 88%;
}

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

/* У силуэта, в отличие от снимка, собственных размеров нет — только
   viewBox. Без явной высоты браузер даёт ему размер по умолчанию,
   и рисунок стакана выходит вдвое меньше соседних кадров. Тени у него
   тоже своей нет — он рисованный, поэтому мягкую даём ему одному. */
svg.cupx-shot-main {
    height: min(100%, 330px);
    aspect-ratio: 1 / 1;
    max-width: 100%;
    filter: drop-shadow(0 22px 20px rgba(18, 59, 43, 0.16));
}

/* Наклон свой у каждого кадра: одинаковый угол на всех пяти читался
   не как выкладка, а как перекошенная вёрстка — пролистываешь, стакан
   другой, крен тот же.

   Кренить стилями нужно не всё подряд. Стакан для мороженого и
   WOK-контейнер сняты уже под углом, и поворот поверх съёмки сложился бы
   с ним вдвое; им оставлен угол самой фотографии. Наклоняются только те
   кадры, где изделие стоит прямо, — два стакана и рисованный силуэт
   баскета. Порядок задан `config/cup.php`, там же менять и его. */
.cupx-slide:nth-child(1) .cupx-shot-main { transform: rotate(-8deg); }
.cupx-slide:nth-child(2) .cupx-shot-main { transform: rotate(7deg); }
.cupx-slide:nth-child(5) .cupx-shot-main { transform: rotate(-6deg); }

/* Баскет — самый широкий снимок в ряду, и при общем потолке в 60% ширины
   левый край его ободка после наклона выходил за кромку сцены: срезало
   несколько пикселей. Ему потолок ниже. */
.cupx-slide:nth-child(5) .cupx-shot-main { max-width: 54%; }

@media (prefers-reduced-motion: reduce) {
    .cupx-shot,
    .cupx-slide figcaption {
        transition: none;
    }

}

/* Подпись — сразу под стрелками и по их правому краю: те стоят в верху
   полосы, а подпись отступает ровно на их высоту и небольшой просвет.
   Прижатая к нижней кромке и выровненная по центру, она не стояла
   со стрелками ни на одной оси и читалась отдельной строкой. */
.cupx-slide figcaption {
    align-self: start;
    justify-self: end;
    max-width: min(100%, 460px);
    padding-top: 57px; /* 43px стрелки + 14px просвет */
    text-align: right;
}

.cupx-slide strong {
    display: block;
    font-size: clamp(18px, 1.7vw, 23px);
    font-weight: 400;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--ink);
}

/* Стрелки — парой у правого края сцены, как в витрине «Рассмотрите
   ближе», название — под ними по тому же краю. Стрелки и подпись одна
   группа: «листать» и «что сейчас в кадре».
 *
 * Прежде стрелки стояли справа, а название — по центру и ниже: на одной
 * оси они не стояли и читались двумя отдельными элементами. По центру
 * группа выбивалась из остальных стрелок раздела. */
.cupx-stage-arrows {
    position: absolute;
    right: 0;
    bottom: 0;
    z-index: 3;
    height: var(--cupx-caption);
    align-items: flex-start;
    justify-content: flex-end;
    gap: 12px;
}

.cupx-dots {
    display: flex;
    gap: 8px;
}

/* Точки первого экрана стоят по центру под кадром: в углу они читались
   как служебная строка, а не как переключатель кадров. */
.cupx-dots--center {
    justify-content: center;
    /* Точки отодвинуты от подписи со стрелками: втроём вплотную они
       читались одним слипшимся подвалом сцены. */
    margin-top: clamp(18px, 2vw, 30px);
}

.cupx-dots button {
    width: 28px;
    height: 3px;
    background: var(--line);
    transition: background-color 0.25s ease;
}

.cupx-dots button[aria-current="true"] {
    background: var(--cup);
}

.cupx-on-color .cupx-dots button {
    background: rgba(255, 255, 255, 0.35);
}

.cupx-on-color .cupx-dots button[aria-current="true"] {
    background: var(--cup-paper);
}

/* ── 2. Полоса цифр ──────────────────────────────────────────────── */

.cupx-stats {
    border-block: 1px solid var(--line);
    background: var(--paper-warm);
}

.cupx-stat {
    display: flex;
    align-items: baseline;
    gap: 12px;
    white-space: nowrap;
}

.cupx-stat b {
    font-size: clamp(28px, 3vw, 40px);
    font-weight: 700;
    letter-spacing: -0.03em;
    color: var(--cup-ink);
}

.cupx-stat span {
    font-size: 14px;
    color: var(--ink-muted);
}

/* ── Бегущая строка ──────────────────────────────────────────────── */

.cupx-marquee {
    overflow: hidden;
    /* Лента уезжает за край экрана, и на самой кромке слово обрывалось
       по букве: «...ленных машин» слева, «3 Н» справа — как будто вёрстка
       поехала. Полупрозрачные поля гасят строку до того, как она упрётся
       в границу, и обрыв читается как уход за кадр. */
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 5%, #000 95%, transparent 100%);
}

/* Две одинаковые дорожки в ряд; едет вся лента на половину своей ширины,
   и в этот момент вторая дорожка стоит ровно там, где стояла первая, —
   склейка незаметна. */
.cupx-marquee-inner {
    display: flex;
    width: max-content;
    animation: cupx-slide var(--cupx-duration, 40s) linear infinite;
    animation-direction: var(--cupx-direction, normal);
}

.cupx-track {
    display: flex;
    align-items: center;
    gap: var(--cupx-gap, 60px);
    padding-inline: calc(var(--cupx-gap, 60px) / 2);
}

.cupx-marquee:hover .cupx-marquee-inner,
.cupx-marquee:focus-within .cupx-marquee-inner {
    animation-play-state: paused;
}

@keyframes cupx-slide {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
    .cupx-marquee-inner {
        animation: none;
    }

    .cupx-marquee {
        overflow-x: auto;
    }
}

/* ── 3. Продукция ────────────────────────────────────────────────── */

/* Блоки продукции и дизайна поменялись фонами: светло-зелёная заливка
   поднялась к продукции, тёплая бумага ушла под дизайн. */
.cupx-products {
    background: var(--cupx-mist);
}

.cupx-grid {
    display: grid;
    /* Колонок столько же, сколько позиций направления, — шесть, в один
       ряд. Уже 1360px — по три в два ряда (см. «Адаптив»): ни одна
       карточка не остаётся во втором ряду одна. */
    grid-template-columns: repeat(6, minmax(0, 1fr));
    margin-top: 52px;
}

.cupx-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--cup-paper);
    box-shadow: 0 0 0 1px var(--line);
}

.cupx-card-stage {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    /* Подложка — строго квадрат от ширины колонки. Карточка выложена
       колонкой на флексе, а флекс-элемент по умолчанию не даёт сжать себя
       меньше содержимого (`min-height: auto`): высокий снимок распирал
       подложку, и в ряду зелёные поля выходили разной высоты, а описания
       под ними начинались на разных уровнях. */
    min-height: 0;
    overflow: hidden;
    padding: 28px;
    background: var(--cupx-mist);
}

.cupx-card-stage img {
    max-height: 100%;
    /* Без ограничения по ширине широкий кадр — стакан для мороженого,
       он лежачий — вылезал за кромку подложки вбок. */
    max-width: 100%;
    width: auto;
    object-fit: contain;
}

.cupx-card-stage svg {
    /* Рисунок ниже снимка: на съёмке вокруг изделия остаётся воздух,
       а силуэт занимал подложку целиком и в ряду выпирал вдвое. */
    height: 78%;
    width: auto;
    transition: transform 0.4s ease;
}

/* Линия прилавка нужна там, где силуэты стоят рядом и их сравнивают.
   Здесь силуэт один среди снимков — сравнивать не с чем, и линия
   читается как случайный штрих под изделием. */
.cupx-card-stage svg .silhouette-floor,
.cupx-slide svg .silhouette-floor {
    display: none;
}

/* Рисунок ведём цветом суб-бренда, а не чернильным: рядом с четырьмя
   цветными снимками чёрный контур читался как чертёж, а не как
   изображение изделия. */
.cupx-card-stage svg,
.cupx-slide svg {
    color: var(--cup-ink);
}

.cupx-card:hover .cupx-card-stage svg {
    transform: translateY(-6px);
}

.cupx-card-body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 8px;
    padding: 22px;
}

.cupx-card-body h3 {
    font-size: 17px;
    font-weight: 600;
    line-height: 1.25;
    color: var(--ink);
    /* Часть названий укладывается в строку, часть — в две. Без запаса
       описания в соседних карточках начинались на разной высоте. */
    min-height: 2.5em;
}

.cupx-card-body p {
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-muted);
}

.cupx-card-volumes {
    margin-top: auto;
    padding-top: 16px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--ink-faint);
}

.cupx-card-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-top: 14px;
    font-size: 14px;
    font-weight: 600;
    color: var(--cup-ink);
    transition: gap 0.25s ease;
}

/* Две ссылки карточки: «Подробнее» — на страницу позиции, под ней
   «Запросить расчёт» — к форме. Обе — текстом со стрелкой, одного вида
   (владелец, 23.09: «Подробнее» была кнопкой-таблеткой). Прижаты к низу:
   названия в одну и в три строки, а ссылки в ряду должны стоять на одной
   линии. */
.cupx-card-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    margin-top: auto;
    padding-top: 16px;
}

.cupx-card-actions .cupx-card-link {
    position: relative;
    /* Поверх растянутой ссылки «Подробнее»: иначе нажатие ушло бы
       на страницу позиции, а не к форме. */
    z-index: 2;
    margin-top: 0;
}

.cupx-card-more {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
    font-weight: 600;
    color: var(--cup-ink);
    transition: gap 0.25s ease;
}

/* Область ссылки — вся карточка: снимок и название тоже ведут на
   страницу позиции. */
.cupx-card-more::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}

/* Наведение на карточку — стрелка «Подробнее» отъезжает, как у второй
   ссылки под курсором: видно, куда уведёт нажатие. */
.cupx-card:hover .cupx-card-more,
.cupx-card-more:focus-visible {
    gap: 14px;
}

/* Курсор на «Запросить расчёт» — отъезжает её стрелка, а не обе. */
.cupx-card:has(.cupx-card-link:hover) .cupx-card-more {
    gap: 8px;
}

.cupx-card-more:focus-visible {
    outline: 2px solid var(--cup-ink);
    outline-offset: 3px;
    border-radius: 4px;
}

/* У позиции без объёмов (крышка) строки миллилитров нет, и прижимать
   ссылку к низу карточки было нечему — она вставала выше соседних. */
.cupx-card-body > p:not(.cupx-card-volumes) + .cupx-card-link {
    margin-top: auto;
    padding-top: 14px;
}

/* Описание и объёмы из карточки сняты — ссылка сразу за названием.
   Прижимаем её к низу: названия в одну и в три строки, а ссылки в ряду
   должны стоять на одной линии. */
.cupx-card-body > h3 + .cupx-card-link {
    margin-top: auto;
    padding-top: 14px;
}

.cupx-card-link:hover {
    gap: 14px;
}

/* ── 4. Услуги дизайна ───────────────────────────────────────────── */

/* Серая, как соседние секции (владелец, 23.09): белый блок между серыми
   читался дырой. Снимки стаканов прозрачные, холст кисти тоже — стакан
   стоит прямо на сером. */
.cupx-design {
    background: var(--cupx-mist);
}

.cupx-design-band {
    margin-top: 48px;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.cupx-design-band > * {
    box-shadow: 0 0 0 1px var(--line);
    background: var(--cup-paper);
    padding: 26px;
}

.cupx-design-band h3 {
    margin-top: 14px;
    font-size: 16px;
    font-weight: 600;
    color: var(--ink);
}

.cupx-design-band p {
    margin-top: 8px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-muted);
}

/* ── 5. О компании ───────────────────────────────────────────────── */

.cupx-about {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: stretch;
}

.cupx-about-media {
    min-height: 340px;
    background: var(--paper-deep);
}

.cupx-about-panel {
    position: relative;
    padding: clamp(34px, 4vw, 68px);
    background: var(--cup-deep);
    color: #fff;
}

.cupx-about-panel h2 {
    font-size: clamp(28px, 3.4vw, 44px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
}

.cupx-about-panel p {
    margin-top: 20px;
    max-width: 46ch;
    font-size: 16px;
    line-height: 1.7;
    color: rgba(255, 255, 255, 0.82);
}

/* ── 6. Анатомия стакана ─────────────────────────────────────────── */

/* Секция «Из чего сделан стакан». При прокрутке стакан раскладывается
 * на детали, подписи по сторонам соединяются с ними линиями, потом
 * стакан собирается обратно. Рисует cup-anatomy.js.
 *
 * Прокрутка «стоит» на сцене: дорожка (.cupx-anatomy-track) длиннее
 * экрана на полтора экрана, а сцена (.cupx-anatomy-pin) прилипает под
 * шапкой, пока дорожка не кончится. Прилипание — только с `.js` и там,
 * где анимация уместна (медиа-запрос ниже совпадает с LIVE в скрипте).
 * Без скрипта, на низком экране и при «уменьшить движение» сцена стоит
 * обычным блоком: стакан разобран, подписи и номера на месте. */
.cupx-anatomy {
    --anatomy-top: 72px;
    --anatomy-pin-h: calc(100svh - var(--anatomy-top));
    --anatomy-gap: clamp(28px, 4.5vw, 84px);
    --anatomy-stage-h: clamp(440px, 50vw, 620px);
    /* Сдвиг подписи вверх на половину кружка с номером: линия от детали
       приходит в центр кружка, а не в верх текста. */
    --part-shift: -20px;
    background: var(--cupx-white);
}

.cupx-anatomy-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: var(--anatomy-gap);
    margin-top: clamp(24px, 3.6vh, 48px);
}

.cupx-anatomy-stage {
    position: relative;
    height: var(--anatomy-stage-h);
    aspect-ratio: 666 / 1160;
}

/* Мягкое пятно света за стаканом — тот же приём, что под изделием
   в первом экране. Прежде здесь был лист с двумя острыми углами, но
   разобранный стакан закрывал его почти целиком, и из-за деталей
   торчали одни прямые углы — лист читался случайным прямоугольником. */
.cupx-anatomy-stage::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 54%;
    width: 170%;
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(43, 138, 99, 0.13) 0%, rgba(43, 138, 99, 0.05) 40%, transparent 66%);
    pointer-events: none;
}

.cupx-anatomy-canvas,
.cupx-anatomy-fallback {
    position: absolute;
    transition: opacity 0.4s ease;
}

.cupx-anatomy-canvas {
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
}

/* Собранный стакан снимком — пока не догрузились слои или если скрипта
   нет вовсе. Стоит там же, где его рисует canvas: смена без скачка. */
.cupx-anatomy-fallback {
    left: 4.5%;
    top: 22.16%;
    width: 80.33%;
    height: auto;
}

.cupx-anatomy.is-ready .cupx-anatomy-canvas {
    opacity: 1;
}

.cupx-anatomy.is-ready .cupx-anatomy-fallback {
    opacity: 0;
}

/* ── Подписи ── */

.cupx-anatomy-col {
    position: relative;
}

/* Подпись стоит на той же высоте, что номер её детали на сцене. */
.cupx-anatomy-part {
    position: absolute;
    top: var(--y);
    display: flex;
    align-items: flex-start;
    gap: 16px;
    width: min(100%, 34ch);
    transform: translateY(calc(var(--part-shift) + var(--part-rise, 0px)));
    transition: opacity 0.45s ease calc(var(--i, 0) * 70ms),
                transform 0.6s cubic-bezier(0.22, 0.61, 0.36, 1) calc(var(--i, 0) * 70ms);
}

.cupx-anatomy-col--left .cupx-anatomy-part {
    right: 0;
}

.cupx-anatomy-col--right .cupx-anatomy-part {
    left: 0;
}

.cupx-anatomy-num {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--cup);
    color: #fff;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 13px;
    font-weight: 500;
}

.cupx-anatomy-part h3 {
    padding-top: 8px;
    font-size: 17px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ink);
}

.cupx-anatomy-part p {
    margin-top: 6px;
    font-size: 15px;
    line-height: 1.55;
    color: var(--ink-muted);
}

/* ── Номера и линии на сцене ── */

/* Линия идёт от подписи через просвет колонок к номеру детали. Ширина —
   доля сцены до номера плюс сам просвет, поэтому линия приходит точно
   в номер на любой ширине. Отступ 14px — воздух между линией и текстом. */
.cupx-anatomy-line {
    position: absolute;
    top: var(--y);
    height: 1px;
    background: var(--ink-faint);
    opacity: 0;
    transform: scaleX(0);
    transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) calc(var(--i, 0) * 70ms),
                opacity 0.2s ease calc(var(--i, 0) * 70ms);
    pointer-events: none;
}

.cupx-anatomy-line--left {
    left: calc(14px - var(--anatomy-gap));
    width: calc(var(--x) + var(--anatomy-gap) - 14px);
    transform-origin: left center;
}

.cupx-anatomy-line--right {
    left: var(--x);
    right: calc(14px - var(--anatomy-gap));
    transform-origin: right center;
}

/* Номер — белым кольцом по краю: стоит он то на крафте, то на белой
   бумаге, то на кофе, и без кольца терялся бы на тёмном. */
.cupx-anatomy-dot {
    position: absolute;
    left: var(--x);
    top: var(--y);
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    margin: -15px 0 0 -15px;
    border-radius: 50%;
    background: var(--cup-ink);
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.92), 0 8px 18px -6px rgba(18, 59, 43, 0.55);
    color: #fff;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 500;
    opacity: 0;
    transform: scale(0.4);
    transition: transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) calc(0.12s + var(--i, 0) * 70ms),
                opacity 0.25s ease calc(0.12s + var(--i, 0) * 70ms);
    pointer-events: none;
}

.cupx-anatomy.is-open .cupx-anatomy-line {
    opacity: 1;
    transform: scaleX(1);
}

.cupx-anatomy.is-open .cupx-anatomy-dot {
    opacity: 1;
    transform: scale(1);
}

/* Уходят разом и быстро: детали уже едут на места, и линии, указывающие
   в пустоту, не должны задерживаться. */
.cupx-anatomy:not(.is-open) .cupx-anatomy-line,
.cupx-anatomy:not(.is-open) .cupx-anatomy-dot {
    transition-delay: 0s;
    transition-duration: 0.18s;
}

/* Подсказка под стаканом — только пока он собран и подписей нет. */
.cupx-anatomy-hint {
    position: absolute;
    left: 50%;
    bottom: 0;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    white-space: nowrap;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
    opacity: 0;
    transform: translateX(-50%);
    transition: opacity 0.3s ease;
    pointer-events: none;
}

.cupx-anatomy-hint-arrow {
    display: inline-block;
    font-size: 15px;
    color: var(--cup-ink);
    animation: cupx-anatomy-nudge 1.6s ease-in-out infinite;
}

@keyframes cupx-anatomy-nudge {
    0%, 100% { transform: translateY(-2px); }
    50% { transform: translateY(3px); }
}

/* ── Под сценой ── */

/* Доводы, документы и кнопка — одной колонкой по центру, под сценой. */
.cupx-anatomy-after {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: clamp(20px, 3vw, 40px);
}

.cupx-anatomy-after .cupx-actions {
    justify-content: center;
}

.cupx-anatomy-facts {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 14px 36px;
}

.cupx-anatomy-facts li {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-size: 15px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--ink-soft);
}

.cupx-anatomy-facts i {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--cup-wash);
    color: var(--cup-ink);
}

.cupx-anatomy-facts svg {
    width: 17px;
    height: 17px;
}

/* ── Прилипание и анимация ── */

@media (prefers-reduced-motion: no-preference) and (min-height: 700px) {
    .js .cupx-anatomy {
        --anatomy-stage-h: clamp(420px, calc(var(--anatomy-pin-h) - 250px), 720px);
    }

    .js .cupx-anatomy-track {
        height: calc(var(--anatomy-pin-h) + 150svh);
    }

    .js .cupx-anatomy-pin {
        position: sticky;
        top: var(--anatomy-top);
        display: flex;
        flex-direction: column;
        justify-content: center;
        height: var(--anatomy-pin-h);
    }

    .cupx-anatomy.is-live:not(.is-told) .cupx-anatomy-part {
        --part-rise: 14px;
        opacity: 0;
    }

    .cupx-anatomy.is-live:not(.is-told) .cupx-anatomy-part {
        transition-delay: 0s;
    }

    .cupx-anatomy.is-live:not(.is-told) .cupx-anatomy-hint {
        opacity: 1;
    }
}

/* Второй экземпляр вводного абзаца — только для телефона, см. разметку. */
.cupx-anatomy-lead-after {
    display: none;
}

@media (max-width: 1100px) and (prefers-reduced-motion: no-preference) and (min-height: 700px) {
    .js .cupx-anatomy {
        --anatomy-stage-h: clamp(240px, calc(var(--anatomy-pin-h) - 480px), 520px);
    }
}

@media (max-width: 600px) {
    /* Номер — в строку с названием, текст — на всю ширину колонки:
       в два столбца по 170px кружок слева съедал четверть ширины,
       и подпись вырастала в шесть строк. */
    .cupx-anatomy-part {
        display: grid;
        grid-template-columns: 24px minmax(0, 1fr);
        align-items: center;
        gap: 4px 8px;
    }

    .cupx-anatomy-part > div {
        display: contents;
    }

    .cupx-anatomy-num {
        width: 24px;
        height: 24px;
        font-size: 10px;
    }

    .cupx-anatomy-part h3 {
        padding-top: 0;
        font-size: 14px;
        line-height: 1.25;
    }

    .cupx-anatomy-part p {
        grid-column: 1 / -1;
        margin-top: 0;
        font-size: 13px;
        line-height: 1.45;
    }

    .cupx-anatomy-facts {
        flex-direction: column;
        align-items: flex-start;
    }
}

@media (max-width: 600px) and (prefers-reduced-motion: no-preference) and (min-height: 700px) {
    .js .cupx-anatomy {
        --anatomy-stage-h: clamp(260px, calc(var(--anatomy-pin-h) - 370px), 520px);
    }

    .js .cupx-anatomy-pin .cupx-lead {
        display: none;
    }

    .js .cupx-anatomy-lead-after {
        display: block;
        align-self: stretch;
        margin: 0 0 24px;
    }
}

/* ── Сертификаты ─────────────────────────────────────────────────── */

/* Строка, а не карточки. Плашка размером с лист бумаги тянула на себя
   больше внимания, чем сами доводы над ней, хотя это к ним подпись. */
.cupx-cert-line {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px 28px;
    margin-top: 26px;
    text-align: center;
}

.cupx-cert-item {
    display: inline-flex;
    align-items: baseline;
    gap: 9px;
}

.cupx-cert-item strong {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.08em;
    color: var(--cup-ink);
}

.cupx-cert-item span {
    font-size: 13px;
    color: var(--ink-muted);
}

/* Подчёркивание только у тех, за которыми лежит скан: иначе непонятно,
   какую строку можно нажать, а какую нет. */
a.cupx-cert-item strong {
    text-decoration: underline;
    text-decoration-color: rgba(43, 138, 99, 0.4);
    text-underline-offset: 4px;
    transition: text-decoration-color 0.2s ease;
}

a.cupx-cert-item:hover strong {
    text-decoration-color: currentColor;
}

/* ── 7. Галерея ──────────────────────────────────────────────────── */

/* Заголовок над лентой: сама лента идёт от кромки до кромки, а он
   держится контейнера страницы, как заголовки остальных секций. */
/* У ленты работ своей заливки нет, но отступы ей нужны те же: без
   нижнего она упиралась в тёмный блок отзывов вплотную. */
.cupx-gallery {
    background: var(--cupx-mist);
    padding-block: var(--cupx-rhythm);
}

.cupx-gallery-head {
    padding-block: 0 clamp(28px, 3vw, 44px);
}

/* Лента заказчиков. Карточки квадратные со скруглением, как у образца:
   снимок тиража во всю карточку, название сверху, знак заказчика в
   нижнем углу. Едет она средствами общей бегущей строки — .cupx-marquee
   выше, — здесь только выравнивание дорожки по верху. */
.cupx-clients-row {
    /* Выравнивание по верху: `stretch` растянул бы карточку на высоту
       дорожки и отменил её квадратную пропорцию. */
    align-items: flex-start;
    /* Запас под увеличение карточки под курсором: лента обрезает всё, что
       выходит за её край, и без запаса у карточки срезало бы верх и низ.
       Отрицательное поле ниже возвращает ленту на прежнее место. */
    padding-block: 14px;
}

.cupx-gallery .cupx-marquee {
    margin-block: -14px;
}

/* Квадрат со скруглёнными углами. Радиус крупный — отступление от общей
   острой геометрии сайта, уже сделанное на этой странице целиком. */
.cupx-client-card {
    position: relative;
    flex: none;
    width: min(360px, 72vw);
    aspect-ratio: 1 / 1;
    margin: 0;
    border-radius: 26px;
    overflow: hidden;
    background: var(--paper-deep);
    scroll-snap-align: start;
    transition: transform 0.45s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Под курсором подрастает карточка целиком, а не снимок внутри неё:
   приближенный кадр обрезался рамкой, и казалось, что поехала картинка,
   а не выделилась карточка. 3% укладываются в просвет между карточками —
   соседей увеличенная не задевает. */
.cupx-client-card:hover {
    z-index: 1;
    transform: scale(1.03);
}

/* Прямой потомок — это снимок тиража. Знак заказчика лежит глубже,
   внутри плашки, и под эти правила попадать не должен: он растягивался
   бы на всю карточку по `cover`. */
.cupx-client-card > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

@media (prefers-reduced-motion: reduce) {
    .cupx-client-card {
        transition: none;
    }
}

/* Знак заказчика — сверху по центру, на «жидком стекле». Названия
   на карточке нет: его заменяет сам знак, а вместе с подписью ушло
   и затемнение верха, которое держало белый текст.
 *
 * Стекло светлое, а не тёмное: знаки приходят от самих заведений и почти
 * всегда цветные — зелёный EVOS и красный Oqtepa на тёмном тонули.
 * Снимок под подложкой размыт и чуть насыщен, по верхней кромке — блик,
 * снизу — мягкое внутреннее свечение, как у толстого стекла. */
.cupx-card-mark {
    position: absolute;
    top: 18px;
    left: 50%;
    z-index: 2;
    display: grid;
    place-items: center;
    /* Высота не жёсткая, а нижняя граница: знаку можно задать свою
       (`logo_height` в config/clients.php), и плашка вырастет под него. */
    min-height: 58px;
    min-width: 58px;
    padding: 11px 24px;
    overflow: hidden;
    isolation: isolate;
    border: 1px solid rgba(255, 255, 255, 0.72);
    border-radius: 999px;
    background: linear-gradient(135deg,
        rgba(255, 255, 255, 0.8) 0%,
        rgba(255, 255, 255, 0.46) 46%,
        rgba(255, 255, 255, 0.66) 100%);
    box-shadow:
        inset 0 1px 1px rgba(255, 255, 255, 0.95),
        inset 0 -10px 18px rgba(255, 255, 255, 0.3),
        0 12px 30px rgba(12, 34, 26, 0.22),
        0 2px 6px rgba(12, 34, 26, 0.12);
    transform: translateX(-50%);
    -webkit-backdrop-filter: blur(16px) saturate(170%);
    backdrop-filter: blur(16px) saturate(170%);
}

/* Блик на верхней половине стекла. */
.cupx-card-mark::before {
    content: "";
    position: absolute;
    inset: 0 0 45%;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(90% 120% at 30% 0%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 70%);
    pointer-events: none;
}

/* Отсвет, который пробегает по стеклу, когда карточку наводят. */
.cupx-card-mark::after {
    content: "";
    position: absolute;
    top: -20%;
    bottom: -20%;
    left: -70%;
    z-index: -1;
    width: 45%;
    background: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0));
    transform: skewX(-20deg);
    transition: left 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
    pointer-events: none;
}

.cupx-client-card:hover .cupx-card-mark::after {
    left: 125%;
}

@media (prefers-reduced-motion: reduce) {
    .cupx-card-mark::after {
        display: none;
    }
}

/* Высота задана прямо, ширина считается от неё. Так знак ложится
   одинаково при любой форме файла, а плашка растягивается под него.
 *
 * Ни `height: 100%`, ни `height: auto` здесь не годились. У SVG
 * заказчиков собственных размеров внутри файла нет, только viewBox,
 * поэтому при автоширине знак занимал ту ширину, что давала плашка,
 * — а её ширину в этот момент определял он сам. Получался круг:
 * вытянутые знаки ужимались до 24 пикселей, квадратные, наоборот,
 * распирали плашку до 116 и вылезали за карточку. */
.cupx-card-mark img {
    width: auto;
    height: var(--mark-h, 34px);
    /* Предел ширины с запасом: у YAPONAMAMA знак вытянутый, и при 132px
       он упирался в ширину раньше, чем набирал заданную высоту, — часть
       плашки оставалась пустой. */
    max-width: 152px;
    object-fit: contain;
}

@media (prefers-reduced-motion: reduce) {
    .cupx-client-card > img {
        transition: none;
    }
}

/* Лента из одних знаков — на боевом сайте, пока он витрина одного Cup
   (components/cp/cup/gallery). Карточка та же, только ниже квадрата
   и белая: знак крупно по центру, как у стекла со знаком, но без снимка
   под ним. Бегущая лента, скругление и увеличение под курсором —
   от карточки со снимком. */
.cupx-client-card--mark {
    display: grid;
    place-items: center;
    width: min(280px, 60vw);
    height: clamp(120px, 11vw, 150px);
    aspect-ratio: auto;
    background: var(--cupx-white, #fff);
    box-shadow:
        0 0 0 1px var(--line),
        0 18px 36px -30px rgba(12, 34, 26, 0.45);
}

/* Правило выше (`.cupx-client-card > img`) растягивает снимок на всю
   карточку по cover — знак так вышел бы обрезанным. Высота — от той же
   переменной, что у знака на стекле, в полтора раза крупнее. */
.cupx-client-card--mark > img {
    width: auto;
    height: calc(var(--mark-h, 34px) * 1.5);
    max-width: 68%;
    object-fit: contain;
}

.cupx-gallery-mid {
    display: flex;
    align-items: center;
    gap: 18px;
    padding-block: 16px;
}

.cupx-pill {
    flex: none;
    padding: 10px 22px;
    /* Подпись в ленте — 15px белым: светлого зелёного ей не хватает. */
    background: var(--cup-ink);
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    white-space: nowrap;
}

.cupx-pill--ink {
    background: var(--cup-deep);
}

.cupx-pill--wash {
    /* Бежевый `--paper-deep` в зелёном ряду читался как пятно чужой
       палитры. Белая плашка — тот же третий тон, но внутри системы. */
    background: var(--cup-paper);
    color: var(--cup-ink);
    box-shadow: inset 0 0 0 1px rgba(43, 138, 99, 0.22);
}

/* ── 8. Нам доверяют ─────────────────────────────────────────────── */

.cupx-client {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 88px;
    padding-inline: 18px;
    font-size: 19px;
    font-weight: 700;
    letter-spacing: 0.02em;
    /* Было `--ink-faint`: 3.2:1 с бумагой. Имена заказчиков — не подпись
       к картинке, их читают, и контраста подписи им мало. */
    color: var(--ink-muted);
    white-space: nowrap;
    transition: color 0.3s ease;
}

.cupx-client:hover {
    color: var(--cup-ink);
}

/* ── 9. Отзывы ───────────────────────────────────────────────────── */

.cupx-reviews {
    background: var(--cupx-white);
    color: #fff;
}

/* ── Лента отзывов ───────────────────────────────────────────────── */

/* Карточки на белой секции: дымчатая подложка с тонкой рамкой. Прежде
   секция была тёмно-зелёной, а карточки — полупрозрачным слоем поверх
   неё; после перекраски страницы в два фона от того оформления остался
   бы белый текст на белом. */
.cupx-reviews-marquee {
    margin-top: clamp(28px, 3.4vw, 48px);
}

.cupx-reviews-row {
    align-items: stretch;
}

.cupx-review-card {
    flex: none;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 16px;
    width: min(420px, 78vw);
    margin: 0;
    padding: clamp(24px, 2.6vw, 34px);
    border-radius: 24px;
    border: 1px solid var(--line);
    background: var(--cupx-mist);
}

/* Звёзды. Незакрашенные не убираем, а гасим: по пустым местам видно,
   из скольких оценка, и ряд не прыгает по ширине от карточки к карточке. */
.cupx-review-stars {
    display: flex;
    gap: 3px;
}

.cupx-review-stars svg {
    width: 17px;
    height: 17px;
    fill: #dedbd5;
}

/* На белом жёлтый берём темнее прежнего: светлое золото, заметное
   на тёмно-зелёном, здесь давало 1.7:1 и читалось как выцветшее. */
.cupx-review-stars svg.is-on {
    fill: #d99b12;
}

/* Кавычка нарисована самим шрифтом и вынесена в поле слева: в строке
   она съедала бы первое слово, а над текстом читается как значок. */
.cupx-review-card blockquote {
    position: relative;
    margin: 0;
    padding-top: 8px;
    font-size: clamp(15px, 1.4vw, 17px);
    line-height: 1.55;
    color: var(--ink-soft);
}

.cupx-review-card blockquote::before {
    content: "“";
    position: absolute;
    top: -6px;
    left: -2px;
    font-size: 46px;
    line-height: 1;
    color: var(--line-strong);
}

.cupx-review-card figcaption {
    display: flex;
    align-items: center;
    gap: 14px;
    /* Подпись прижата к низу карточки: карточки в ленте одной высоты,
       и без этого подписи стояли бы на разной, вслед за длиной цитаты. */
    margin-top: auto;
    padding-top: 8px;
}

/* Снимок тиража кружком, как аватар: он здесь не для разглядывания,
   а чтобы у отзыва было лицо. */
.cupx-review-shot {
    flex: none;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--paper-deep);
}

.cupx-review-shot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.cupx-review-who {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.cupx-review-who b {
    font-size: 15px;
    font-weight: 600;
    color: var(--ink);
}

.cupx-review-who span {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

/* ── 10. Итоговый призыв ─────────────────────────────────────────── */

.cupx-final {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr);
    align-items: center;
    gap: clamp(28px, 4vw, 64px);
    padding: clamp(34px, 4vw, 64px);
    /* Тот же тёмный вариант, что и в панели героя: блок несёт абзац
       и телефон мелким кеглем поверх заливки. */
    background: var(--cup-ink);
    color: #fff;
}

.cupx-final h2 {
    font-size: clamp(28px, 3.4vw, 46px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.03em;
}

.cupx-final p {
    margin-top: 18px;
    max-width: 44ch;
    font-size: 16px;
    line-height: 1.7;
    color: rgba(255, 255, 255, 0.86);
}

.cupx-final-media {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 18px;
    overflow: hidden;
    /* Светлая подложка под снимком — та же, что под продукцией в карточках
       и в блоке про материал. Она нужна не для красоты: у снимка запечена
       серая тень, и прямо на зелёном она читалась как мутный прямоугольник
       под стаканом. */
    background: var(--cup-wash);
}

/* ── Адаптив ─────────────────────────────────────────────────────── */

@media (max-width: 1360px) {
    .cupx-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 1100px) {
    .cupx-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Анатомия: подписи уходят под сцену двумя столбцами. Линиям идти
       некуда, номера на деталях остаются и связывают подпись с деталью. */
    .cupx-anatomy {
        --part-shift: 0px;
        --anatomy-stage-h: min(520px, 110vw);
    }

    .cupx-anatomy-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 22px clamp(16px, 4vw, 40px);
    }

    .cupx-anatomy-stage {
        grid-column: 1 / -1;
        justify-self: center;
        order: -1;
    }

    .cupx-anatomy-col {
        display: grid;
        align-content: start;
        gap: 18px;
    }

    .cupx-anatomy-part {
        position: static;
        width: auto;
    }

    .cupx-anatomy-line {
        display: none;
    }
}

@media (max-width: 900px) {
    .cupx-hero-inner,
    .cupx-about,
    .cupx-final {
        grid-template-columns: minmax(0, 1fr);
    }

    .cupx-design-band {
        grid-template-columns: minmax(0, 1fr);
    }

    .cupx-gallery-row .shot,
    .cupx-gallery-row .cupx-placeholder {
        width: 190px;
        height: 190px;
    }
}

@media (max-width: 560px) {
    .cupx-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* В одну колонку квадратная подложка съедает целый экран на карточку:
       пять позиций подряд превращаются в пять экранов пролистывания. */
    .cupx-card-stage {
        aspect-ratio: 4 / 3;
    }

    /* Стрелки остаются: они под кадром, а не по его краям, и стакану
       не мешают. */
    .cupx-stage-arrows {
        gap: 10px;
    }

    .cupx-slides {
        min-height: calc(330px + var(--cupx-headroom));
    }

    .cupx-gallery-row .shot,
    .cupx-gallery-row .cupx-placeholder {
        width: 150px;
        height: 150px;
    }

}

/* ── Появление ───────────────────────────────────────────────────── */

/* Страница собирается сверху вниз (очередь — cup-page.js, «Появление»).
 *
 * Начальное положение частей задано только для ещё не открытой секции
 * (:not(.is-visible)): как только секция открылась, оно перестаёт
 * действовать, и часть едет к своему обычному виду по переходу из
 * правила «is-visible». Прежде оба правила весили одинаково, и нижнее —
 * начальное — побеждало: часть проявлялась на месте сдвига, а сдвиг
 * снимался рывком в конце.
 * Проявляется содержимое секции, а не сама секция: фон виден сразу,
 * иначе на месте ещё не открытой секции стояла бы белая дыра.
 *
 * Части секции — .cupx-rv, у каждой номер --rv по порядку чтения;
 * заголовки — .cupx-rv-words, они поднимаются по словам. Кривая одна
 * на всё — «экспонента на выходе»: резкий старт и долгое мягкое
 * торможение, без отскоков. Шаг между частями — 90 мс. */
.cupx {
    --rv-ease: cubic-bezier(0.16, 1, 0.3, 1);
    --rv-fade: cubic-bezier(0.22, 0.61, 0.36, 1);
    --rv-step: 90ms;
}

.js [data-cup-reveal]:not(.is-visible) .cupx-rv {
    opacity: 0;
    transform: translate3d(0, 38px, 0);
}

.js [data-cup-reveal].is-visible .cupx-rv {
    opacity: 1;
    transform: none;
    transition: opacity 0.8s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step)),
                transform 1.2s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step)),
                filter 1s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step)),
                clip-path 1.3s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step));
}

/* ── Заголовки по словам ──
 *
 * Слово в маске: выезжает снизу из-под нижней кромки строки с лёгким
 * наклоном, который выпрямляется по дороге. Поля маски — под диакритику
 * и выносные («й», «у», «Q»): без них маска срезала бы их, пока слово
 * стоит на месте. */
.cupx-w {
    display: inline-block;
    overflow: hidden;
    vertical-align: top;
    padding: 0.1em 0.04em 0.16em;
    margin: -0.1em -0.04em -0.16em;
}

.cupx-w-in {
    display: inline-block;
}

.js [data-cup-reveal]:not(.is-visible) .cupx-rv-words .cupx-w-in {
    transform: translate3d(0, 115%, 0) rotate(5deg);
    transform-origin: 0 100%;
}

.js [data-cup-reveal].is-visible .cupx-rv-words .cupx-w-in {
    transform: none;
    transition: transform 1.15s var(--rv-ease)
                calc(var(--rv, 0) * var(--rv-step) + var(--w, 0) * 55ms);
}

/* Слова встали — маска больше не нужна: при смене шрифта или масштаба
   страницы она могла бы подрезать край буквы. */
.is-settled .cupx-rv-words .cupx-w {
    overflow: visible;
}

/* ── Подводки ── проявляются из лёгкого размытия. */
.js [data-cup-reveal]:not(.is-visible) .cupx-lead.cupx-rv,
.js [data-cup-reveal]:not(.is-visible) .cupx-studio-now.cupx-rv,
.js [data-cup-reveal]:not(.is-visible) .cupx-crumbs.cupx-rv {
    filter: blur(8px);
    transform: translate3d(0, 22px, 0);
}

.js [data-cup-reveal].is-visible .cupx-lead.cupx-rv,
.js [data-cup-reveal].is-visible .cupx-studio-now.cupx-rv,
.js [data-cup-reveal].is-visible .cupx-crumbs.cupx-rv {
    filter: none;
}

/* ── Карточки ──
 *
 * Рамка всплывает, а снимок в ней чуть позже проявляется из крупного
 * и размытого — изделие «наводится на резкость». */
.js [data-cup-reveal]:not(.is-visible) .cupx-card.cupx-rv {
    transform: translate3d(0, 64px, 0) scale(0.96);
}

.js [data-cup-reveal]:not(.is-visible) .cupx-card.cupx-rv .cupx-card-stage > * {
    opacity: 0;
    transform: translate3d(0, 26px, 0) scale(1.14);
    filter: blur(10px);
}

.js [data-cup-reveal].is-visible .cupx-card.cupx-rv .cupx-card-stage > * {
    opacity: 1;
    transform: none;
    filter: none;
    transition: opacity 0.9s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step) + 180ms),
                transform 1.4s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step) + 180ms),
                filter 1.1s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step) + 180ms);
}

.js [data-cup-reveal]:not(.is-visible) .cupx-card.cupx-rv .cupx-card-body > * {
    opacity: 0;
    transform: translate3d(0, 14px, 0);
}

.js [data-cup-reveal].is-visible .cupx-card.cupx-rv .cupx-card-body > * {
    opacity: 1;
    transform: none;
    transition: opacity 0.7s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step) + 320ms),
                transform 1s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step) + 320ms);
}

/* ── Окна с роликами, карта, галерея позиции ──
 *
 * Открываются шторкой снизу вверх, а кадр внутри при этом оседает
 * из крупного — как будто камера отъезжает. */
.js [data-cup-reveal]:not(.is-visible) :is(.cupx-reel-wide, .cupx-reel-slot, .cupx-form-map).cupx-rv {
    opacity: 1;
    transform: translate3d(0, 44px, 0);
    clip-path: inset(100% 0 0 0 round 18px);
}

.js [data-cup-reveal].is-visible :is(.cupx-reel-wide, .cupx-reel-slot, .cupx-form-map).cupx-rv {
    clip-path: inset(0 0 0 0 round 18px);
}

.js [data-cup-reveal]:not(.is-visible) .cupx-form-map.cupx-rv {
    clip-path: inset(100% 0 0 0 round 26px);
}

.js [data-cup-reveal].is-visible .cupx-form-map.cupx-rv {
    clip-path: inset(0 0 0 0 round 26px);
}

.js [data-cup-reveal]:not(.is-visible) .cupx-reel-wide.cupx-rv video {
    transform: scale(1.18);
}

.js [data-cup-reveal].is-visible .cupx-reel-wide.cupx-rv video {
    transform: none;
    transition: transform 1.8s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step));
}

/* Лента заказчиков въезжает справа — по ходу своего движения. Секция
   режет её по горизонтали: иначе, пока лента сдвинута, страница
   получала полосу прокрутки вбок. clip, а не hidden, — без своей
   прокрутки у секции. */
.js [data-cup-reveal]:not(.is-visible) .cupx-marquee.cupx-rv {
    transform: translate3d(12vw, 0, 0);
}

.cupx-gallery {
    overflow-x: clip;
}

/* Стаканы первого экрана и студии поднимаются крупнее и медленнее
   остального: это главный предмет экрана. */
.js [data-cup-reveal]:not(.is-visible) :is(.cupx-showroom-stage, .cupx-studio-stage, .cupx-item-gallery).cupx-rv {
    transform: translate3d(0, 70px, 0) scale(0.94);
}

.js [data-cup-reveal].is-visible :is(.cupx-showroom-stage, .cupx-studio-stage, .cupx-item-gallery).cupx-rv {
    transition: opacity 1s var(--rv-fade) calc(var(--rv, 0) * var(--rv-step)),
                transform 1.6s var(--rv-ease) calc(var(--rv, 0) * var(--rv-step));
}

/* ── Шапка ── на страницах Cup опускается сверху при загрузке. */
.js body.cupx > header {
    animation: cupx-header-in 0.9s var(--rv-ease, ease) both;
}

@keyframes cupx-header-in {
    from {
        opacity: 0;
        transform: translate3d(0, -100%, 0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .js [data-cup-reveal] :is(.cupx-rv, .cupx-rv-words .cupx-w-in, .cupx-rv .cupx-card-stage > *, .cupx-rv .cupx-card-body > *, .cupx-rv video) {
        opacity: 1 !important;
        transform: none !important;
        filter: none !important;
        clip-path: none !important;
        transition: none !important;
    }

    .js body.cupx > header {
        animation: none;
    }
}

.cupx-gallery-note {
    margin-top: 18px;
    padding-inline: clamp(20px, 5vw, 76px);
    font-size: 13px;
    line-height: 1.5;
    /* Оговорка про съёмку — не украшение, её читают. `--ink-faint`
       давал 3.65:1 при кегле 13px. */
    color: var(--ink-muted);
    text-align: center;
}

/* ── Снимки продукции ────────────────────────────────────────────── */

.cupx-final-media img {
    /* На исходном снимке изделие занимает меньше половины кадра, всё
       остальное — белое поле. При `contain` стакан выходил вчетверо
       меньше блока и висел в пустоте; кадрируем поле по месту. */
    width: 100%;
    height: clamp(240px, 26vw, 340px);
    object-fit: cover;
    object-position: 48% 44%;
}

/* Снимок в карточке дышит внутри подложки, а не упирается в её края. */
.cupx-card-stage img {
    max-height: 100%;
    max-width: 100%;
    width: auto;
    object-fit: contain;
    transition: transform 0.4s ease;
}

.cupx-card:hover .cupx-card-stage img {
    transform: translateY(-6px);
}


/* ── Видеополоса ─────────────────────────────────────────────────── */

/* Лента карточек в один ряд, как у Apple: высота у всех одна, ширину
   задаёт пропорция ролика. Прежняя сетка растягивала широкий кадр
   на полстраницы — блок занимал целый экран, хотя это перебивка,
   а не главный экран.
 *
 * Ряд прокручивается вбок, поэтому вертикальных можно ставить сколько
 * угодно: не помещающиеся уезжают за кромку, а не жмут соседей. */
/* Обёртка полосы: заголовок и ряд кадров на общей подложке. Цвет стоит
   здесь, а не на ряду, — иначе светлая заливка обрывалась бы по верхней
   кромке карточек, а заголовок висел бы над ней на фоне страницы. */
.cupx-reel-section {
    background: var(--cupx-mist);
    padding-block: var(--cupx-rhythm);
}

/* Заголовок отступ сверху не добавляет — его даёт секция. Своё у него
   только расстояние до ленты кадров. */
.cupx-reel-head {
    padding-block: 0 clamp(28px, 3vw, 44px);
}

.cupx-reel {
    display: flex;
    /* Просветы между карточками узкие: это одна полоса кадров, а не
       четыре отдельных блока. Ширину строки ряд добирает полями по краям
       (см. ::before/::after ниже), а не разрывами внутри. */
    gap: clamp(12px, 1.4vw, 26px);
    padding: 0;
    overflow-x: auto;
    /* Ряд больше не растягивается на всю строку, поэтому ставим его
       посередине. `safe` — чтобы при переполнении он не уезжал левым
       краем за пределы экрана, откуда его не прокрутить. */
    justify-content: safe center;
    scroll-snap-type: x proximity;
    /* Поля внутри ленты, а не на секции: иначе первая карточка упирается
       в кромку экрана при прокрутке вбок. */
    scroll-padding-inline: clamp(20px, 4.5vw, 76px);
    /* Полосу прокрутки прячем: ряд листается колесом и пальцем, а тонкая
       белая нить под тёмным блоком читается как случайная линия. */
    scrollbar-width: none;
}

.cupx-reel::-webkit-scrollbar {
    display: none;
}

.cupx-reel::before,
.cupx-reel::after {
    content: "";
    flex: none;
    /* Поля по краям полосы — шире, чем просветы внутри ряда: так ряд
       читается одной группой, отодвинутой от кромок экрана, а не
       четырьмя карточками, разбросанными по строке. */
    width: clamp(28px, 6.5vw, 140px);
}

/* Высота общая — карточки стоят в одну линию по верху и низу, а не
   лесенкой. А ширину каждая берёт из пропорций того, что показывает:
   широкая карточка — 16:9, как сам ролик, вертикальные окна — 9:16.
 *
 * Раньше ширину раздавал флекс долями строки, и на широком мониторе
 * ролик растягивался в длинную полосу: `cover` срезал ему верх и низ,
 * и от кадра оставалась лента. Теперь строку карточки не делят —
 * лишнее место остаётся по краям, а когда его не хватает, ряд
 * прокручивается вбок, как и задумано.
 *
 * Высота 320-520: полоса стала крупнее прежнего, потому что окон в ней
 * теперь три вместо пяти — мелкими они читались как превью, а не как
 * кадры с производства. */
.cupx-reel-wide,
.cupx-reel-slot {
    position: relative;
    height: clamp(320px, 30vw, 520px);
    overflow: hidden;
    border-radius: 18px;
    /* Подложка карточки чуть темнее полосы: пока ролик не загрузился,
       на её месте должен быть виден прямоугольник, а не пустое место.
       Прежде здесь стоял тёмно-зелёный — под светлой полосой он читался
       как дыра. */
    background: #e6e6ea;
    scroll-snap-align: start;
}

/* На десктопе карточки максимально высокие, но так, чтобы ряд влезал
   в экран: ширина ряда = высота × 4.18 (16:9 + три окна 4:5) плюс три
   просвета и два поля. 20px — запас на полосу прокрутки страницы.
   На 2K упирается в прежние 520px, на Full HD ряд больше не уезжает
   в прокрутку. */
@media (min-width: 1200px) {
    .cupx-reel-wide,
    .cupx-reel-slot {
        height: min(520px, calc((100vw - 20px - 3 * clamp(12px, 1.4vw, 26px) - 2 * clamp(28px, 6.5vw, 140px)) / 4.18));
    }

    /* Поля — тоже флекс-элементы и получают просвет рядом с собой.
       Вычитаем его из ширины поля, иначе ряд шире расчёта и не по центру. */
    .cupx-reel::before,
    .cupx-reel::after {
        width: calc(clamp(28px, 6.5vw, 140px) - clamp(12px, 1.4vw, 26px));
    }
}

/* `flex: none` — чтобы ряд не растянул карточку сверх её пропорции
   и не сжал ниже неё. Ширина считается от высоты через aspect-ratio. */
.cupx-reel-wide {
    flex: none;
    aspect-ratio: 1920 / 1080;
}

.cupx-reel-slot {
    flex: none;
    aspect-ratio: 1080 / 1350;
}

/* Окно — кнопка включения звука, поэтому с него снимаем всё кнопочное
   оформление браузера. Курсор оставляем: он единственный намекает, что
   по кадру можно нажать. */
button.cupx-reel-slot {
    display: block;
    padding: 0;
    border: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

button.cupx-reel-slot:focus-visible {
    outline: 2px solid var(--cup, #2b8a63);
    outline-offset: 3px;
}

/* Значок звука. Кружок под ним тёмный и полупрозрачный: кадры разные,
   и на светлом белый значок пропадал бы. */
.cupx-reel-sound {
    position: absolute;
    right: 12px;
    bottom: 12px;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 999px;
    background: rgba(20, 22, 26, 0.55);
    backdrop-filter: blur(6px);
    color: #fff;
    transition: background-color 0.2s ease;
}

.cupx-reel-slot:hover .cupx-reel-sound {
    background: rgba(20, 22, 26, 0.78);
}

.cupx-reel-sound svg {
    width: 19px;
    height: 19px;
}

/* Перечёркнутый динамик, пока звука нет; волны — когда он включён.
   Обе группы лежат в разметке, переключается видимость. */
.cupx-reel-sound-on {
    display: none;
}

.cupx-reel-slot[aria-pressed="true"] .cupx-reel-sound {
    background: var(--cup, #2b8a63);
}

.cupx-reel-slot[aria-pressed="true"] .cupx-reel-sound-off {
    display: none;
}

.cupx-reel-slot[aria-pressed="true"] .cupx-reel-sound-on {
    display: block;
}

.cupx-reel-wide video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Окно держит все свои ролики стопкой и показывает один. Пропорция
   задана окну, а не ролику: иначе при смене кадра лента прыгала бы
   по высоте вслед за исходником. */
/* Кадры сменяются сдвигом, а не растворением: прежний уезжает влево,
   новый приходит справа. Ждут своей очереди они за правым краем окна —
   всё, что вне его границ, окно режет (overflow: hidden выше). */
.cupx-reel-slot :is(video, img) {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: translateX(100%);
    transition: transform 0.8s cubic-bezier(0.65, 0, 0.35, 1);
}

.cupx-reel-slot :is(video, img).is-active {
    transform: translateX(0);
}

.cupx-reel-slot :is(video, img).is-leaving {
    transform: translateX(-100%);
}

/* Уехавший кадр возвращается в очередь справа мгновенно — иначе он
   проехал бы обратно через всё окно на глазах у зрителя. */
.cupx-reel-slot :is(video, img).is-instant {
    transition: none;
}

/* Кому движение мешает — кадр просто подменяется на месте. */
@media (prefers-reduced-motion: reduce) {
    .cupx-reel-slot :is(video, img) {
        transition: none;
    }
}

/* Вертикальные окна лежат прямо в ряду, без обёртки: обёртка ломала бы
   общую высоту и прокрутку. */
.cupx-reel-talls {
    display: contents;
}

.cupx-reel .cupx-placeholder {
    height: 100%;
}

/* ── Якоря ───────────────────────────────────────────────────────── */

/* Переход к секции по ссылке ставит её верх ровно под шапку: воздух над
   заголовком даёт собственный отступ секции. Высоту шапки держит
   cup-page.js в --cupx-header-h; запас — на кадр до первого запуска
   скрипта (форма после отправки открывается сразу с #request).

   Прежде здесь стояли 130 пикселей под шапку со служебной строкой, и они
   складывались с общими 150 из слоя редизайна (html, scroll-padding-top):
   раздел вставал на треть экрана ниже шапки. */
html:has(> body.cupx) {
    scroll-padding-top: var(--cupx-header-h, 81px);
}

/* ── «Рассмотрите ближе» ─────────────────────────────────────────── */

/* Витрина в блоке дизайна: ряд крупных карточек, кружки цветов под ним.
 * Раскладка снята с apple.com/imac.
 *
 * Цвет живёт одной переменной на весь блок: кружок меняет её, а сцены
 * всех карточек перекрашиваются разом. Перебирать карточки скриптом
 * не нужно — переход считает CSS. */
.cupx-look {
    margin-top: clamp(48px, 6vw, 88px);
}

/* Ряд карточек. Прокрутка своя, со снапом по карточке: стрелки только
   доводят её до следующей, а не подменяют собой. */
.cupx-look-rail {
    display: flex;
    align-items: start;
    gap: clamp(12px, 1.4vw, 24px);
    overflow-x: auto;
    scroll-behavior: smooth;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    /* Поля те же, что у контейнера страницы: первая карточка встаёт
       по одной линии с заголовком над ней. */
    padding-inline: clamp(20px, 4.5vw, 76px);
    scroll-padding-inline: clamp(20px, 4.5vw, 76px);
}

.cupx-look-rail::-webkit-scrollbar {
    display: none;
}

.cupx-look-rail:focus-visible {
    outline: 2px solid var(--cup);
    outline-offset: 4px;
}

.cupx-look-card {
    flex: none;
    /* Шире окна карточка быть не должна: на телефоне ряд иначе
       прокручивается вбок внутри и без того узкого экрана. */
    width: min(680px, 82vw);
    margin: 0;
    scroll-snap-align: start;
}

/* Сцена — та самая крашеная подложка. Радиус крупный, как у образца:
   здесь отступление от общей острой геометрии сайта уже сделано
   на этой странице целиком. */
/* Сцена задаёт размер, снимок в неё вписывается. Прежде было наоборот:
   изделия лежали в сетке как есть, а кадры у них разной высоты — от
   квадратного стакана до вытянутого набора, — и карточки в ряду выходили
   то короче, то вдвое длиннее соседней. */
.cupx-look-stage {
    aspect-ratio: 4 / 3;
    padding: clamp(24px, 3vw, 56px);
    border-radius: 28px;
    background: var(--look-stage);
    overflow: hidden;
    transition: background-color 0.55s cubic-bezier(0.4, 0, 0.2, 1);
}

/* `contain` по всей рамке: изделие занимает её целиком по меньшей
   стороне и не выходит за края, какой бы формы ни был исходник. */
.cupx-look-stage img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    /* Тень под изделием — от самой сцены, не впечатана в снимок:
       кадры взяты обрезанные, без собственной тени. */
    filter: drop-shadow(0 18px 26px rgba(21, 23, 28, 0.18));
    transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Короткий «вдох» при смене цвета: изделие чуть подаётся вперёд
   и возвращается. Без него перекраска подложки читается как загрузка
   страницы, а не как выбор. */
.cupx-look.is-switching .cupx-look-stage img {
    transform: scale(1.045);
}

/* Подвал: только стрелки. Выбор цвета из потока убран — он висит
   поверх страницы, см. .cupx-look-picker ниже. */
.cupx-look-foot {
    display: flex;
    justify-content: flex-end;
    margin-top: clamp(20px, 2.4vw, 32px);
}

/* Плавающая панель выбора цвета. Прижата к нижней кромке окна по центру
   и показывается только пока витрина на экране: всплывает снизу, когда
   до неё долистали, и уходит обратно вниз, когда её миновали.
 *
 * `pointer-events` снимаем в спрятанном состоянии — иначе невидимая
 * панель продолжала бы ловить клики по низу экрана на всей странице. */
.cupx-look-picker {
    position: fixed;
    left: 50%;
    bottom: clamp(16px, 2.5vw, 32px);
    z-index: 40;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    /* Сама обёртка ничем не залита: подложка есть только под кружками
       (см. .cupx-look-swatches). Подпись стоит над ней прямо на странице,
       как у образца, — рамка вокруг двух строк выглядела бы диалогом. */
    /* Спрятанное положение: чуть ниже кромки и без объёма. Сдвиг по X
       вынесен в ту же строку, иначе центрирование слетит при анимации. */
    transform: translate(-50%, calc(100% + clamp(16px, 2.5vw, 32px)));
    opacity: 0;
    pointer-events: none;
    /* Пружина с перелётом: панель выходит чуть выше места и оседает.
       Ровный выезд читался как «выползло», а не как «появилось». */
    transition: transform 0.62s cubic-bezier(0.34, 1.4, 0.5, 1),
                opacity 0.32s ease;
}

.cupx-look-picker.is-visible {
    transform: translate(-50%, 0);
    opacity: 1;
    pointer-events: auto;
}

/* Подпись и кружки входят не вместе с панелью, а следом за ней и друг
   за другом. Задержка у каждого кружка своя: `--i` проставлен в разметке.
 *
 * Приём тот же, что у образца: сначала приезжает подложка, потом на ней
 * по очереди проявляются кружки — так панель читается как собравшаяся,
 * а не как целиком нарисованная. */
/* Подложка ровно по кружкам: скруглённая «таблетка» матового стекла. */
.cupx-look-swatches {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    max-width: 100%;
    padding: 10px 14px;
    border-radius: 999px;
    background: rgba(251, 250, 247, 0.82);
    border: 1px solid var(--line);
    box-shadow: 0 18px 40px rgba(21, 23, 28, 0.16);
    backdrop-filter: blur(18px) saturate(1.4);
    -webkit-backdrop-filter: blur(18px) saturate(1.4);
}

/* Кружок цвета: две половины — корпус и оборот, как у образца. */
.cupx-look-swatch {
    width: 34px;
    height: 34px;
    padding: 3px;
    border: 0;
    border-radius: 999px;
    background: none;
    cursor: pointer;
    opacity: 0;
    transition: transform 0.25s ease,
                opacity 0.3s ease calc(0.16s + var(--i, 0) * 0.045s);
}

/* Подскок вынесен на сам круг, а не на кнопку: на кнопке он спорил бы
   с увеличением под курсором — свойство одно, и последнее правило
   стирало бы предыдущее. */
.cupx-look-swatch span {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(100deg, var(--look-front) 0 50%, var(--look-back) 50% 100%);
    box-shadow: inset 0 0 0 1px rgba(21, 23, 28, 0.12);
    /* Обводка выбранного — на самом круге, а не на кнопке вокруг него.
       Круг живёт своим слоем (у него трансформ подскока), кнопка — своим,
       и на дробных пикселях панели, отцентрованной сдвигом на −50%, слои
       расходились на полпикселя: просвет между обводкой и кругом с одной
       стороны пропадал, с другой был виден, и обводка стояла криво.
       Outline рисуется тем же слоем, что и круг, и повторяет его
       скругление — разойтись им не из-за чего. */
    outline: 2px solid transparent;
    outline-offset: 2px;
    transform: scale(0.4) translateY(10px);
    /* Перелёт заметно сильнее, чем у панели: кружок маленький, и на нём
       мягкая пружина не читается вовсе. Обводка меняется сразу, без
       очереди появления. */
    transition: transform 0.5s cubic-bezier(0.34, 1.62, 0.56, 1) calc(0.16s + var(--i, 0) * 0.045s),
                outline-color 0.2s ease 0s;
}

.cupx-look-picker.is-visible .cupx-look-swatch {
    opacity: 1;
}

.cupx-look-picker.is-visible .cupx-look-swatch span {
    transform: scale(1) translateY(0);
}

/* Уходит панель целиком и разом: по очереди красиво приходить, а
   уходить по очереди — значит держать на экране огрызок ряда. */
.cupx-look-picker:not(.is-visible) .cupx-look-swatch,
.cupx-look-picker:not(.is-visible) .cupx-look-swatch span {
    transition-delay: 0s;
    transition-duration: 0.18s;
}

.cupx-look-swatch:hover {
    transform: scale(1.12);
}

/* Нажатие проседает: без отклика кружок кажется картинкой. */
.cupx-look-swatch:active {
    transform: scale(0.94);
    transition-duration: 0.08s;
}

.cupx-look-swatch[aria-checked="true"] span {
    outline-color: var(--ink);
}

/* Фокус с клавиатуры — зелёная обводка на том же круге. Своя обводка
   у кнопки легла бы вторым кольцом в пиксель от первого. */
.cupx-look-swatch:focus-visible {
    outline: none;
}

.cupx-look-swatch:focus-visible span {
    outline-color: var(--cup);
}

.cupx-look-arrows {
    display: flex;
    gap: 10px;
}

.cupx-look-arrows button {
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 999px;
    /* Тот же залитый зелёный кружок, что на первом экране: стрелки
       по разделу должны быть одной кнопкой, а не тремя разными. */
    background: var(--cup-ink);
    color: #fff;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}

.cupx-look-arrows button svg {
    width: 18px;
    height: 18px;
}

.cupx-look-arrows button:hover {
    background: var(--cup);
    color: #fff;
}

/* Доехали до края — кнопка гаснет, но остаётся на месте: ряд, из
   которого кнопка исчезает, дёргается на каждой прокрутке. */
.cupx-look-arrows button[disabled] {
    opacity: 0.35;
    cursor: default;
}

.cupx-look-arrows button[disabled]:hover {
    background: var(--cup-ink);
    color: #fff;
}

@media (max-width: 720px) {
    /* На телефоне ряд листается пальцем, и стрелки только занимают место. */
    .cupx-look-arrows {
        display: none;
    }

    /* Панель во всю ширину за вычетом полей: семь кружков в ряд
       на узком экране иначе не помещаются и переносятся в два ряда. */
    .cupx-look-picker {
        left: 12px;
        right: 12px;
        transform: translateY(calc(100% + clamp(16px, 2.5vw, 32px)));
    }

    .cupx-look-picker.is-visible {
        transform: translateY(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .cupx-look-rail {
        scroll-behavior: auto;
    }

    /* Панель по-прежнему появляется и исчезает, но без выезда снизу
       и без очереди: остаётся только проявление. */
    .cupx-look-picker {
        transition: opacity 0.2s ease;
        transform: translate(-50%, 0);
    }

    .cupx-look-picker.cupx-studio-picker {
        transform: none;
    }

    .cupx-look-swatch,
    .cupx-look-swatch span {
        transition-delay: 0s;
        transform: none;
    }

    .cupx-look-swatch span {
        transform: scale(1);
    }

    .cupx-look-stage,
    .cupx-look-stage img {
        transition: none;
    }

    .cupx-look.is-switching .cupx-look-stage img {
        transform: none;
    }
}

/* ── Студия дизайна ──────────────────────────────────────────────── */

/* Блок «Дизайн стакана»: слева слова и имя макета, справа стакан, по
 * которому кисть проявляет печать. Идея — из передачи Centris_Design_Block,
 * оформление наше: стакан стоит прямо на странице, без подложки и плашек
 * поверх, кружки — та же всплывающая панель, что была у витрины. */
.cupx-studio {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    align-items: center;
    gap: clamp(32px, 5vw, 96px);
}

.cupx-studio-copy .cupx-lead {
    max-width: 44ch;
}

/* Имя макета — крупно и тонко, форма стакана — мелкой строкой под ним.
   Меняются с коротким проявлением: без него подмена слова читалась
   как опечатка, исправленная на глазах. */
.cupx-studio-now {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: clamp(28px, 3.4vw, 48px);
    padding-top: clamp(20px, 2.4vw, 28px);
    border-top: 1px solid var(--line);
}

.cupx-studio-name {
    font-size: clamp(30px, 3.6vw, 52px);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.035em;
    color: var(--ink);
}

.cupx-studio-kind {
    font-size: 14px;
    letter-spacing: 0.02em;
    color: var(--ink-faint);
}

/* История заказа — под подписью. Все абзацы лежат в одной клетке
   сетки, виден один: блок высотой с самую длинную историю, и смена
   кружка не двигает ни кнопку, ни колонку. */
.cupx-studio-stories {
    display: grid;
    margin-top: 12px;
}

.cupx-studio-story {
    grid-area: 1 / 1;
    max-width: 48ch;
    font-size: 15px;
    line-height: 1.6;
    color: var(--ink-muted);
    visibility: hidden;
    opacity: 0;
}

.cupx-studio-story.is-active {
    visibility: visible;
    opacity: 1;
}

.cupx-studio-name,
.cupx-studio-kind,
.cupx-studio-story.is-active {
    transition: opacity 0.2s ease, transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.cupx-studio.is-switching .cupx-studio-name,
.cupx-studio.is-switching .cupx-studio-kind,
.cupx-studio.is-switching .cupx-studio-story.is-active {
    opacity: 0;
    transform: translateY(8px);
}

.cupx-studio-cta {
    margin-top: clamp(24px, 3vw, 40px);
}

.cupx-studio-cta svg {
    transition: transform 0.3s ease;
}

.cupx-studio-cta:hover svg {
    transform: translateX(4px);
}

/* Сцена — просто место под стакан: подложку и плашки поверх убрали,
   и холст занимает её целиком. Снимки прозрачные, поэтому стакан стоит
   прямо на белом фоне раздела.
 *
 * Режем только по горизонтали: постер со своими прозрачными полями шире
 * сцены и на телефоне давал странице прокрутку вбок. По вертикали не
 * режем — тень холста уходит ниже его кромки. */
.cupx-studio-stage {
    position: relative;
    aspect-ratio: 7 / 6;
    isolation: isolate;
    overflow-x: clip;
}

.cupx-studio-view {
    position: absolute;
    inset: 0;
    touch-action: pan-y;
    cursor: crosshair;
    outline: none;
    -webkit-tap-highlight-color: transparent;
}

.cupx-studio-view[data-reveal="false"] {
    cursor: pointer;
}

.cupx-studio-view:focus-visible {
    box-shadow: inset 0 0 0 2px var(--cup);
    border-radius: 28px;
}

.cupx-studio-view canvas {
    display: block;
    width: 100%;
    height: 100%;
    pointer-events: none;
    filter: drop-shadow(0 26px 22px rgba(21, 23, 28, 0.14));
}

/* Белый стакан до загрузки движка: сцена не пустует, пока тянутся
   снимки, и подмена на холст не видна — кадр тот же. */
.cupx-studio-poster {
    position: absolute;
    left: 50%;
    top: 50%;
    width: auto;
    height: min(118%, 720px);
    max-width: none;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    pointer-events: none;
    transition: opacity 0.4s ease;
}

.cupx-studio-stage[data-ready="true"] .cupx-studio-poster {
    opacity: 0;
}

.cupx-studio-error {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 3;
    transform: translate(-50%, -50%);
    margin: 0;
    padding: 12px 18px;
    border-radius: 14px;
    background: #fff;
    font-size: 14px;
    color: var(--ink-soft);
    box-shadow: 0 12px 30px rgba(21, 23, 28, 0.12);
    white-space: nowrap;
}

.cupx-studio-error button {
    border: 0;
    background: none;
    padding: 0 0 0 4px;
    font: inherit;
    color: var(--cup-ink);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

/* ── Подсказка «нажмите» ──
 *
 * Тонкое белое кольцо с точкой посередине ездит по стакану вместе
 * с кистью: место ему каждый кадр ставит cup-studio.js (transform
 * у обёртки), а здесь — только вид и отклик. Прежде здесь была цветная
 * кнопка с рукой-указателем — владелец счёл её слишком заметной.
 *
 * Цвета своего у кольца нет: белая линия и под ней волосяная тёмная —
 * так его видно и на тёмной печати, и на белой бумаге, и оно ни с каким
 * макетом не спорит. Обёртка нулевого размера стоит точкой кисти,
 * кольцо, точка и волна отцентрованы на ней отрицательными полями. */
.cupx-studio-tap {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
    width: 0;
    height: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.35s ease;
    will-change: transform;
}

.cupx-studio-tap.is-on {
    opacity: 1;
}

/* Переход между кистью и курсором — короткий перелёт, а не скачок. */
.cupx-studio-tap.is-glide {
    transition: opacity 0.35s ease, transform 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.cupx-studio-tap-ring,
.cupx-studio-tap-wave {
    position: absolute;
    left: -17px;
    top: -17px;
    width: 34px;
    height: 34px;
    border: 1.5px solid rgba(255, 255, 255, 0.96);
    border-radius: 50%;
}

.cupx-studio-tap-ring {
    box-shadow: 0 0 0 1px rgba(21, 23, 28, 0.16),
                inset 0 0 0 1px rgba(21, 23, 28, 0.1),
                0 4px 14px rgba(21, 23, 28, 0.14);
    transform: scale(0.5);
    transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cupx-studio-tap.is-on .cupx-studio-tap-ring {
    transform: scale(1);
}

.cupx-studio-tap-dot {
    position: absolute;
    left: -4px;
    top: -4px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 0 0 1px rgba(21, 23, 28, 0.18),
                0 2px 6px rgba(21, 23, 28, 0.3);
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Под мышью кольцо — сам курсор. Системный курсор над стаканом
   прячем — два указателя в одной точке спорили бы. */
.cupx-studio-view.is-cursor {
    cursor: none;
}

/* «Нажатие»: кольцо сжимается к точке быстро, а отпускает с пружиной —
   общим переходом выше. */
.cupx-studio-tap.is-press .cupx-studio-tap-ring {
    transform: scale(0.68);
    transition-duration: 0.12s;
}

.cupx-studio-tap.is-press .cupx-studio-tap-dot {
    transform: scale(0.7);
    transition-duration: 0.12s;
}

/* Макет раскрыт — кольцо не гаснет, а расходится и тает вместе
   с краской. */
.cupx-studio-tap.is-burst .cupx-studio-tap-ring {
    transform: scale(2.2);
    transition: transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.cupx-studio-tap.is-burst {
    transition: opacity 0.3s ease;
}

/* Волна от нажатия — одна, такая же тонкая, как кольцо. */
.cupx-studio-tap-wave {
    box-shadow: 0 0 0 1px rgba(21, 23, 28, 0.12);
    opacity: 0;
}

.cupx-studio-tap.is-wave .cupx-studio-tap-wave {
    animation: cupx-tap-wave 1.05s cubic-bezier(0.2, 0.65, 0.3, 1) both;
}

@keyframes cupx-tap-wave {
    0% {
        opacity: 0.95;
        transform: scale(0.9);
    }
    100% {
        opacity: 0;
        transform: scale(2.7);
    }
}

/* Стакан при раскрытии: короткий толчок — просел под пальцем и
   подался навстречу, пока его заливает краска. */
.cupx-studio-view canvas {
    transform-origin: 50% 58%;
}

.cupx-studio-stage.is-pop .cupx-studio-view canvas {
    animation: cupx-studio-pop 0.95s cubic-bezier(0.25, 0.75, 0.3, 1);
}

@keyframes cupx-studio-pop {
    0% { transform: scale(1); }
    14% { transform: scale(0.972); }
    48% { transform: scale(1.028); }
    100% { transform: scale(1); }
}

/* Капля из палитры ударила в стакан: он коротко вздрагивает — слабее,
   чем от нажатия, это отклик, а не раскрытие. */
.cupx-studio-stage.is-hit .cupx-studio-view canvas {
    animation: cupx-studio-hit 0.6s cubic-bezier(0.25, 0.75, 0.3, 1);
}

@keyframes cupx-studio-hit {
    0% { transform: scale(1); }
    20% { transform: scale(0.984); }
    55% { transform: scale(1.012); }
    100% { transform: scale(1); }
}

/* Слой, на котором летит капля из кружка палитры в стакан: холст во всё
   окно поверх страницы, живёт только время полёта. Холст, а не элемент:
   капля с хвостом рисуется одной фигурой и остаётся чёткой при любом
   растяжении. В body, а не в секции: у обёртки секции при въезде бывает
   трансформ, и fixed считался бы от неё. */
.cupx-studio-flight {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 60;
    pointer-events: none;
}

/* ── Палитра студии — в блоке ──
 *
 * Своя строка сетки под текстом и стаканом, по центру блока. Прежде
 * панель была fixed у нижней кромки окна (.cupx-look-picker выше) — здесь
 * положение перебито, а появление то же: пружина снизу и кружки по
 * очереди (is-visible ставит cup-studio.js). */
.cupx-look-picker.cupx-studio-picker {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    z-index: 2;
    grid-column: 1 / -1;
    justify-self: center;
    margin-top: clamp(4px, 1.2vw, 20px);
    transform: translate3d(0, 44px, 0) scale(0.94);
}

.cupx-look-picker.cupx-studio-picker.is-visible {
    transform: none;
}

/* Промежуток сетки между колонками широкий (до 96px), а между строками
   палитре он не нужен: она стоит прямо под стаканом, отступ — свой. */
@media (min-width: 901px) {
    .cupx-studio {
        row-gap: 0;
    }
}

/* Палитра студии — девять кружков. Панель шириной по кружкам:
   без `max-content` fixed-блок с `left: 50%` получает в ширину лишь
   половину окна, и на экранах уже 830px ряд переносился бы на два. */
@media (min-width: 721px) {
    .cupx-studio-picker {
        width: max-content;
        max-width: calc(100vw - 32px);
    }
}

/* На телефоне все девять в ряд не встают, а два ряда в плавающей
   панели закрывали бы полэкрана. Кружки едут лентой, край ленты
   тает — видно, что дальше есть ещё; выбранный скрипт держит
   посередине. */
@media (max-width: 720px) {
    /* Поля шире затухания края: пока лента стоит в начале или в конце,
       тает пустое поле, а не крайний кружок. */
    .cupx-studio-picker .cupx-look-swatches {
        position: relative;
        flex-wrap: nowrap;
        justify-content: flex-start;
        padding-inline: 20px;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
        -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
        mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 18px), transparent 100%);
    }

    .cupx-studio-picker .cupx-look-swatches::-webkit-scrollbar {
        display: none;
    }

    .cupx-studio-picker .cupx-look-swatch {
        flex: none;
    }
}

@media (max-width: 900px) {
    /* minmax(0, …): лента кружков шире экрана и распирала бы колонку —
       вместе с ней и стакан, и страница уезжала вбок. Лента листается
       внутри себя. */
    .cupx-studio {
        grid-template-columns: minmax(0, 1fr);
    }

    .cupx-look-picker.cupx-studio-picker {
        min-width: 0;
        max-width: 100%;
    }

    /* На узком экране порядок: заголовок и слова, сцена, имя и кнопка
       под ней. Имя макета должно стоять рядом с кружками, которые его
       меняют, а не на экран выше. */
    .cupx-studio-copy {
        display: contents;
    }

    .cupx-studio-copy .cupx-heading { order: 1; }
    .cupx-studio-copy .cupx-lead { order: 2; margin-top: 16px; }
    .cupx-studio-stage { order: 3; margin-top: 28px; aspect-ratio: 4 / 3; }
    /* Палитра — сразу под стаканом: кружок и то, что он меняет, рядом. */
    .cupx-look-picker.cupx-studio-picker { order: 4; justify-self: stretch; margin-top: 12px; }
    .cupx-studio-now { order: 5; margin-top: 24px; padding-top: 0; border-top: 0; }
    .cupx-studio-cta { order: 6; justify-self: start; margin-top: 20px; }
}

/* На телефоне сцена квадратная: в 4:3 высокий стакан выходил мельче,
   чем был в прежней сцене. */
@media (max-width: 520px) {
    .cupx-studio-stage {
        aspect-ratio: 1;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cupx-studio-name,
    .cupx-studio-kind,
    .cupx-studio-story.is-active {
        transition: none;
    }

    /* Кольцо-подсказка стоит на месте кисти и не нажимает само:
       ни волн, ни толчков, ни расхождения — только проявление. */
    .cupx-studio-tap,
    .cupx-studio-tap.is-glide {
        transition: opacity 0.2s ease;
    }

    .cupx-studio-tap .cupx-studio-tap-ring,
    .cupx-studio-tap .cupx-studio-tap-dot {
        transform: none;
        transition: none;
    }

    .cupx-studio-tap-wave {
        display: none;
    }

    .cupx-studio-stage.is-pop .cupx-studio-view canvas,
    .cupx-studio-stage.is-hit .cupx-studio-view canvas {
        animation: none;
    }
}

/* ── Форма заявки ────────────────────────────────────────────────── */

/* Последний блок страницы. Разметка формы общая для всего сайта
 * (x-request-form), и набрана она классами Tailwind. Пересобрать сборку
 * на рабочей машине нельзя — node не установлен, — поэтому оформление
 * здесь перекрывает те классы обычным CSS, в области `.cupx-form`.
 * На других страницах форма остаётся прежней. */
/* Белая: над ней дымчатая лента работ, под ней дымчатый подвал сайта,
   и фоны секций идут через одну. */
.cupx-form {
    background: var(--cupx-white);
    padding-block: var(--cupx-rhythm);
}

/* Слева заголовок, телефоны и форма, справа карта во всю высоту левой
   колонки: верх карты стоит вровень с заголовком, низ — с кнопкой.
   Так карта и форма читаются одним блоком «напишите или приезжайте»,
   а не картинкой, приставленной сбоку.
 *
 * Плашек у формы нет: плашка давала третий оттенок и ломала чередование
 * «белая — дымчатая». Границы держат дымчатые поля ввода. */
.cupx-form-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    align-items: stretch;
    gap: clamp(32px, 4.5vw, 80px);
}

.cupx-form-main .cupx-lead {
    margin-top: 18px;
}

/* Номер, под ним Telegram — так попросил владелец. Столбик короткий:
   номер здесь один, и форму он вниз почти не сдвигает. */
.cupx-form-contacts {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    margin-top: clamp(22px, 2.4vw, 32px);
}

.cupx-form-card {
    margin-top: clamp(28px, 3vw, 44px);
}

/* Позиция, с которой пришли на страницу заявки (карточка товара, сфера):
   плашкой над полями — видно, что выбор уже в заявке. На витрине она
   появляется, только пока каталог закрыт: тогда к форме ведут карточки. */
.cupx-form-subject {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 18px;
    padding: 14px 18px;
    border-radius: 14px;
    background: var(--cup-wash);
}

/* На витрине плашка стоит в разметке заранее и ждёт, пока карточка товара
   передаст ей позицию (cup-page.js). display: flex выше перебил бы
   браузерное правило для [hidden], поэтому прячем явно. */
.cupx-form-subject[hidden] {
    display: none;
}

.cupx-form-subject span {
    font-size: 13px;
    color: var(--ink-muted);
}

.cupx-form-subject strong {
    font-size: 16px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ink);
}

.cupx-form-map {
    position: relative;
    min-height: 420px;
    overflow: hidden;
    border-radius: 26px;
    background: #e6e6ea;
}

.cupx-form-map iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.cupx-form-phone {
    font-size: clamp(19px, 1.8vw, 24px);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--ink);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
    transition: color 0.2s ease;
}

.cupx-form-phone:hover {
    color: var(--cup-ink);
}

.cupx-form-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 15px;
    color: var(--ink-muted);
    text-decoration: none;
    transition: color 0.2s ease;
}

.cupx-form-link:hover {
    color: var(--cup-ink);
}

/* Telegram со знаком: подпись темнее прочих ссылок. */
.cupx-form-telegram {
    gap: 10px;
    font-size: 16px;
    font-weight: 500;
    color: var(--ink);
}

.cupx-form-telegram-logo {
    flex: none;
    width: 28px;
    height: 28px;
    transition: transform 0.2s ease;
}

.cupx-form-telegram:hover .cupx-form-telegram-logo {
    transform: scale(1.06);
}

/* ── Поля ────────────────────────────────────────────────────────── */

.cupx-form .field-label,
.cupx-form span.field-label {
    display: block;
    margin-bottom: 9px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

/* Рамка настоящая, а не внутренняя тень: тень в общем оформлении сайта
   рисует прямоугольник без скругления, и на скруглённом поле от неё
   оставались углы. */
.cupx-form .field {
    width: 100%;
    padding: 14px 16px;
    border: 1px solid var(--line);
    border-radius: 12px;
    /* Дымчатые: секция формы белая, и белое поле на белом фоне держала
       бы одна тонкая рамка. */
    background: var(--cupx-mist);
    box-shadow: none;
    font-size: 15px;
    color: var(--ink);
    transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
}

.cupx-form .field:hover {
    border-color: var(--line-strong, #c9c6c0);
}

.cupx-form .field:focus {
    outline: none;
    border-color: var(--cup);
    background: #fff;
    box-shadow: 0 0 0 3px rgba(43, 138, 99, 0.16);
}

.cupx-form textarea.field {
    min-height: 132px;
    line-height: 1.55;
}

.cupx-form .field-error {
    border-color: #c0392b;
    box-shadow: none;
}

.cupx-form .field-note {
    margin-top: 8px;
    font-size: 13px;
    color: #c0392b;
}

/* ── Мессенджер и макет ──────────────────────────────────────────── */

/* Обе плашки набраны в разметке внутренними тенями Tailwind. Целимся
   по вложенному полю, а не по классам: классы там длинные и меняются
   вместе с общей формой, а поле внутри — признак надёжный. */
.cupx-form label:has(input[type="radio"]),
.cupx-form label:has(input[type="file"]) {
    border: 1px solid var(--line);
    border-radius: 12px;
    background: #fff;
    box-shadow: none;
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.cupx-form label:has(input[type="radio"]):hover,
.cupx-form label:has(input[type="file"]):hover {
    border-color: var(--cup);
    box-shadow: none;
}

.cupx-form label:has(input[type="radio"]:checked) {
    border-color: var(--cup);
    background: var(--cup-wash);
    box-shadow: none;
}

.cupx-form input[type="radio"] {
    accent-color: var(--cup-ink);
}

/* ── Кнопки ──────────────────────────────────────────────────────── */

.cupx-form .btn-accent {
    padding: 15px 32px;
    border: 0;
    border-radius: 999px;
    background: var(--cup-ink);
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    box-shadow: none;
    transition: background-color 0.2s ease, transform 0.2s ease;
}

.cupx-form .btn-accent:hover {
    background: var(--cup);
    transform: translateY(-1px);
}

.cupx-form .btn-ghost {
    padding: 11px 20px;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink);
    font-size: 14px;
    background: #fff;
}

.cupx-form .btn-ghost:hover {
    border-color: var(--cup);
    background: var(--cup);
    color: #fff;
}

/* В одну колонку карта уходит под форму и получает свою высоту:
   растягиваться ей больше не по чему. */
@media (max-width: 900px) {
    .cupx-form-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .cupx-form-map {
        min-height: 320px;
        border-radius: 20px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cupx-form .btn-accent:hover {
        transform: none;
    }
}

/* ── Качество в деталях ──────────────────────────────────────────── */

/* 3D-стакан из передачи дизайнера: components/cp/cup/cinema, скрипт —
 * public/assets/cup-3d (исходник resources/js/cup-cinema). Стоит
 * на месте «Анатомии». Под сценой по решению владельца ничего нет:
 * подсказка, кнопки сцен и шкала сняты из разметки, их стили ниже
 * оставлены, чтобы вернуть можно было одной разметкой.
 *
 * В передаче сцена прилипала на весь экран. Владелец попросил, чтобы
 * блок не забирал экран целиком и соседние секции оставались видны.
 * Поэтому на компьютере (класс is-held) сцена — блок в ширину сетки
 * не выше 540px, без запаса высоты: когда он встаёт посередине экрана,
 * страницу держит скрипт, и колесо ведёт рассказ. На сенсорных экранах
 * (is-pinned) — обычное прилипание, как было у «Анатомии»: дорожка
 * длиннее экрана, сцена липнет под шапкой. Врезки «макро» и тёмной фазы
 * из передачи здесь нет.
 *
 * Без анимации (нет скрипта, низкий экран, «уменьшить движение»,
 * нет WebGL) это обычный блок: заголовок и стакан рядом, под ними
 * четыре подписи в ряд. */
.cupx-cinema {
    /* Высоту шапки скрипт уточняет на ходу. */
    --cinema-top: 81px;
    --cinema-pin-h: calc(100svh - var(--cinema-top));
    /* Дымчатая, как видеополоса выше и лента работ ниже: по решению
       владельца на стыках не должно быть шва. Чередование «белая —
       дымчатая» здесь нарушено намеренно. */
    background: var(--cupx-mist);
}

/* ── Обычный блок ── */

.cupx-cinema-stage {
    position: relative;
    display: grid;
    /* Пять колонок — по одной на решение: подписи стоят строкой под
       вступлением и стаканом. */
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 40px clamp(20px, 2.6vw, 40px);
    isolation: isolate;
}

.cupx-cinema-stories {
    display: contents;
}

.cupx-cinema-story--intro {
    grid-column: 1 / 3;
    grid-row: 1;
    align-self: center;
}

.cupx-cinema-story:not(.cupx-cinema-story--intro) {
    grid-row: 2;
}

.cupx-cinema-world {
    position: relative;
    grid-column: 3 / -1;
    grid-row: 1;
    height: clamp(300px, 32vw, 440px);
}

/* Мягкое пятно света за стаканом — тот же приём, что в «Анатомии».
   В обычном блоке стакан стоит на 38% ширины (staticPose в motion.ts). */
.cupx-cinema-world::before {
    content: "";
    position: absolute;
    left: 38%;
    top: 50%;
    width: min(100%, 520px);
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(43, 138, 99, 0.12) 0%, rgba(43, 138, 99, 0.045) 42%, transparent 68%);
    pointer-events: none;
}

/* Без скрипта стакан не нарисовать — вступление занимает всю строку. */
html:not(.js) .cupx-cinema-world,
.cupx-cinema.is-failed .cupx-cinema-world {
    display: none;
}

html:not(.js) .cupx-cinema-story--intro {
    grid-column: 1 / -1;
}

.cupx-cinema-status,
.cupx-cinema-error,
.cupx-cinema-foot,
.cupx-cinema-progress {
    display: none;
}

.cupx-cinema-status {
    z-index: 3;
    grid-column: 3 / -1;
    grid-row: 1;
    align-self: end;
    justify-self: center;
    font-size: 13px;
    color: var(--ink-faint);
}

.js .cupx-cinema:not(.is-ready):not(.is-failed) .cupx-cinema-status {
    display: block;
}

/* На месте стакана — честная подпись, почему его нет. */
.cupx-cinema.is-failed .cupx-cinema-error {
    display: flex;
    grid-column: 3 / -1;
    grid-row: 1;
    align-items: center;
    justify-content: center;
    min-height: 220px;
    padding: 24px;
    border: 1px dashed var(--line);
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink-faint);
    text-align: center;
}

/* Видна только в фокусе с клавиатуры и только при анимации. */
.cupx-cinema-skip {
    position: absolute;
    z-index: 6;
    left: 0;
    top: 0;
    transform: translateX(-200vw);
}

.cupx-cinema-skip:focus {
    transform: none;
}

.cupx-cinema:not(.is-live) .cupx-cinema-skip {
    display: none;
}

/* ── Подписи ── */

.cupx-cinema-story--intro .cupx-heading {
    font-size: min(clamp(32px, 3.6vw, 52px), var(--cupx-text-max));
    line-height: 1.04;
}

.cupx-cinema-over {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--cup-ink);
}

.cupx-cinema-num {
    flex: none;
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--cup);
    color: #fff;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0;
}

.cupx-cinema-title {
    margin-top: 18px;
    color: var(--ink);
    font-size: clamp(20px, 1.8vw, 26px);
    font-weight: 700;
    line-height: 1.12;
    letter-spacing: -0.02em;
}

.cupx-cinema-copy {
    margin-top: 14px;
    max-width: 38ch;
    font-size: 16px;
    line-height: 1.6;
    color: var(--ink-muted);
}

.cupx-cinema-story--intro .cupx-cinema-copy {
    margin-top: 20px;
    font-size: 18px;
}

.cupx-cinema-note {
    margin-top: 12px;
    max-width: 40ch;
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink-faint);
}

/* ── Переключатель сцен и шкала ── */

.cupx-cinema-hint {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-muted);
}

.cupx-cinema-nav {
    display: flex;
    gap: 2px;
    max-width: 100%;
    padding: 4px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.9);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
}

.cupx-cinema-nav button {
    min-height: 40px;
    padding: 0 18px;
    border-radius: 999px;
    color: var(--ink-muted);
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.25s ease, color 0.25s ease;
}

.cupx-cinema-nav button:hover {
    background: var(--cup-wash);
    color: var(--cup-ink);
}

.cupx-cinema-nav button[aria-current="step"] {
    background: var(--cup-ink);
    color: #fff;
}

.cupx-cinema-nav button:focus-visible {
    outline: 2px solid var(--cup);
    outline-offset: 2px;
}

.cupx-cinema-progress span {
    display: block;
    height: 100%;
    background: var(--cup);
    transform: scaleX(0);
    transform-origin: left;
}

/* ── Прилипание и анимация ── */

@media (prefers-reduced-motion: no-preference) and (min-height: 650px) {
    /* Компьютер: блок высотой как соседние секции. Холст со стаканом
       выходит за блок вверх и вниз на --cinema-bleed — в поля секции:
       фон у секции и соседей один, края холста не видны, а стакан
       по просьбе владельца крупнее при том же блоке и тех же подписях. */
    .js .cupx-cinema:not(.is-static) {
        --cinema-stage-h: clamp(440px, 36vw, 540px);
        --cinema-bleed: clamp(24px, 2.5vw, 48px);
    }

    /* Сенсорный экран: прилипание. Верхний отступ не нужен — сцена
       и так стоит посередине экрана. Нижний остаётся: под сценой
       строка доводов. */
    .js .cupx-cinema.is-pinned {
        --cinema-stage-h: clamp(440px, calc(var(--cinema-pin-h) - 120px), 620px);
        --cinema-bleed: 0px;
        padding-top: 0;
    }

    /* По 32svh на сцену: шесть сцен — 192svh (HELD_LENGTH в cinema.ts). */
    .js .cupx-cinema.is-pinned .cupx-cinema-track {
        height: calc(var(--cinema-pin-h) + 192svh);
    }

    .js .cupx-cinema.is-pinned .cupx-cinema-pin {
        position: sticky;
        top: var(--cinema-top);
        display: flex;
        flex-direction: column;
        justify-content: center;
        height: var(--cinema-pin-h);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-stage {
        display: block;
        height: var(--cinema-stage-h);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-world {
        position: absolute;
        inset: calc(-1 * var(--cinema-bleed, 0px)) 0;
        height: auto;
    }

    /* Пятно стоит там, где стакан. Место и приближение каждой сцены
       скрипт передаёт переменными (cinema.ts, syncGlow); без них —
       место из передачи, 69% ширины. */
    .js .cupx-cinema:not(.is-static) .cupx-cinema-world::before {
        left: var(--cinema-cup-x, 69%);
        top: var(--cinema-cup-y, 50%);
        width: calc(min(60%, 620px) * min(var(--cinema-cup-zoom, 1), 1.5));
    }

    /* Подписи лежат одна на другой в левой колонке; видна одна. */
    .js .cupx-cinema:not(.is-static) .cupx-cinema-stories {
        position: absolute;
        z-index: 2;
        top: 0;
        bottom: 0;
        left: 0;
        display: grid;
        align-items: center;
        width: min(42%, 480px);
        pointer-events: none;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-story {
        grid-area: 1 / 1;
        visibility: hidden;
        opacity: 0;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-story--intro {
        visibility: visible;
        opacity: 1;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-title {
        font-size: clamp(26px, 2.6vw, 38px);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-copy {
        font-size: 17px;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-status {
        position: absolute;
        left: 69%;
        bottom: 24px;
        transform: translateX(-50%);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-foot {
        position: absolute;
        z-index: 4;
        left: 0;
        right: 0;
        bottom: 22px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 24px;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-progress {
        position: absolute;
        z-index: 4;
        left: 0;
        right: 0;
        bottom: 0;
        display: block;
        height: 2px;
        background: rgba(21, 23, 28, 0.08);
    }
}

/* Телефон и узкий экран: стакан в верхней половине сцены, подпись под ним.
   Условия — те же, что MOBILE в скрипте. */
@media (prefers-reduced-motion: no-preference) and (min-height: 650px) and (max-width: 1023px),
       (prefers-reduced-motion: no-preference) and (min-height: 650px) and (max-aspect-ratio: 1/1) {
    /* Здесь всегда прилипание (is-pinned): сцена — на весь экран под шапкой. */
    .js .cupx-cinema.is-pinned {
        --cinema-stage-h: calc(var(--cinema-pin-h) - 32px);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-world::before {
        left: 50%;
        top: 30%;
        width: min(90%, 420px);
    }

    /* Пока идёт рассказ, стакан не заходит на подпись. */
    .js .cupx-cinema.is-live[data-scene]:not([data-scene="0"]) .cupx-cinema-world {
        clip-path: inset(0 0 47% 0);
    }

    /* Проценты подписей считаются от всей высоты сцены — от неё же
       отмерена и обрезка стакана выше. */
    .js .cupx-cinema:not(.is-static) .cupx-cinema-stories {
        right: 0;
        bottom: 0;
        display: block;
        width: auto;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-story {
        position: absolute;
        top: 55%;
        left: 0;
        right: 0;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-story--intro {
        top: 3%;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-story--intro .cupx-heading {
        font-size: min(clamp(30px, 8.4vw, 44px), var(--cupx-text-max));
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-title {
        margin-top: 14px;
        font-size: min(clamp(24px, 6.6vw, 32px), var(--cupx-text-max));
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-copy {
        margin-top: 12px;
        font-size: 15px;
        line-height: 1.5;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-status {
        left: 50%;
        bottom: 24px;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-hint {
        display: none;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-foot {
        bottom: 14px;
        justify-content: center;
    }

    .cupx-cinema-nav button {
        min-height: 36px;
        padding: 0 12px;
        font-size: 12px;
    }
}

/* Низкий телефон: подпись выше и короче, иначе она садится на кнопки. */
@media (prefers-reduced-motion: no-preference) and (min-height: 650px) and (max-height: 750px) and (max-width: 1023px),
       (prefers-reduced-motion: no-preference) and (min-height: 650px) and (max-height: 750px) and (max-aspect-ratio: 1/1) {
    .js .cupx-cinema:not(.is-static) .cupx-cinema-story {
        top: 52%;
    }

    .js .cupx-cinema.is-live[data-scene]:not([data-scene="0"]) .cupx-cinema-world {
        clip-path: inset(0 0 49% 0);
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-title {
        font-size: 26px;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-copy {
        font-size: 14px;
    }

    .js .cupx-cinema:not(.is-static) .cupx-cinema-note {
        display: none;
    }
}

/* Обычный блок на узком экране: вступление и стакан во всю ширину,
   подписи — по две в ряд, на телефоне — в столбик. */
@media (max-width: 1100px) {
    .cupx-cinema-stage {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .cupx-cinema-story--intro {
        grid-column: 1 / -1;
    }

    .cupx-cinema-world,
    .cupx-cinema-status,
    .cupx-cinema.is-failed .cupx-cinema-error {
        grid-column: 1 / -1;
        grid-row: 2;
    }

    .cupx-cinema-story:not(.cupx-cinema-story--intro) {
        grid-row: auto;
    }
}

@media (max-width: 600px) {
    .cupx-cinema-stage {
        grid-template-columns: minmax(0, 1fr);
        gap: 32px;
    }
}

/* ── Страница позиции ────────────────────────────────────────────── */

/* pages/cup-product — «Подробнее» в карточке продукции. Раскладка снята
 * с карточки товара newprint: галерея слева, описание справа, ниже
 * похожие позиции и форма. Оформление — этой витрины: зелёный первый
 * экран под прозрачной шапкой, кнопки-таблетки, моноширинные подписи.
 *
 * Первый экран — тот же .cupx-hero, что у витрины (шапка над ним
 * прозрачная), но градиент другой: светлое пятно стоит за галереей,
 * а не справа, где у витрины были стаканы. */
.cupx-item-hero {
    padding-block: calc(var(--hero-header) + clamp(20px, 2.6vw, 40px)) clamp(44px, 5vw, 80px);
    background:
        radial-gradient(46% 70% at 28% 56%, rgba(120, 214, 168, 0.2) 0%, rgba(120, 214, 168, 0) 66%),
        radial-gradient(ellipse at 51% 49%, #2f6f52 0%, #205a44 34%, #164a39 64%, #0e362c 100%);
    color: #f4f6ed;
}

/* ── Путь ── */

.cupx-crumbs ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 0;
    font-size: 13px;
    line-height: 1.4;
    color: rgba(244, 246, 237, 0.62);
}

.cupx-crumbs li {
    display: inline-flex;
    align-items: center;
    min-width: 0;
}

/* Разделитель — тонкая косая черта, а не стрелка: путь читается
   подписью, а не навигацией, которую надо нажимать. */
.cupx-crumbs li + li::before {
    content: "/";
    margin-inline: 10px;
    color: rgba(244, 246, 237, 0.3);
}

.cupx-crumbs a {
    transition: color 0.2s ease;
}

.cupx-crumbs a:hover {
    color: #fff;
}

.cupx-crumbs [aria-current] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: rgba(244, 246, 237, 0.9);
}

/* ── Галерея и описание ── */

.cupx-item-top {
    display: grid;
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
    align-items: start;
    gap: clamp(28px, 4.4vw, 80px);
    margin-top: clamp(20px, 2.4vw, 34px);
}

.cupx-item-gallery {
    min-width: 0;
}

/* Сцена — почти квадрат: в нём одинаково стоят высокий стакан, низкий
   баскет и 3D-модель, которую крутят во все стороны. Чуть ниже квадрата,
   чтобы на экране ноутбука (900 точек) первый экран с кнопкой заявки
   помещался целиком. Подложка — лёгкое светлое пятно и волосяная рамка:
   изделие висит на зелёном, как на витрине, а рамка держит кадр, чтобы
   стрелки и счётчик были к чему-то привязаны. */
.cupx-item-stage {
    position: relative;
    aspect-ratio: 1 / 0.92;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 28px;
    background:
        radial-gradient(circle at 50% 46%, rgba(255, 255, 255, 0.13) 0%, rgba(255, 255, 255, 0.04) 46%, rgba(255, 255, 255, 0) 72%),
        rgba(255, 255, 255, 0.025);
    touch-action: pan-y;
}

.cupx-item-frame {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 12% 13% 14%;
}

.cupx-item-frame[hidden] {
    display: none;
}

.cupx-item-frame img {
    position: relative;
    z-index: 1;
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    -webkit-user-drag: none;
    user-select: none;
}

/* Тень-подиум под изделием без фона — та же, что под стаканами первого
   экрана витрины: снимок иначе висит в пустоте. */
.cupx-item-frame--model::after,
.cupx-item-frame--shot::after,
.cupx-item-frame--design::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: 10%;
    width: 52%;
    height: 7%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(closest-side, rgba(6, 30, 21, 0.5), rgba(6, 30, 21, 0));
    pointer-events: none;
    transition: opacity 0.6s ease;
}

/* Снимок в заведении — прямоугольная фотография: лежит в кадре
   карточкой со скруглением, а не растягивается на весь квадрат. */
.cupx-item-frame--scene {
    padding: 9%;
}

.cupx-item-frame--scene img {
    width: 100%;
    border-radius: 18px;
    box-shadow: 0 30px 60px -28px rgba(4, 22, 15, 0.7);
}

/* Марка заказчика под его оформлением — мелкой подписью в углу. */
.cupx-item-frame figcaption {
    position: absolute;
    left: 22px;
    bottom: 20px;
    z-index: 2;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(244, 246, 237, 0.62);
}

/* Смена кадра: новый въезжает на пару десятков пикселей со стороны
   листания и проявляется. Старый просто уходит — два движущихся
   кадра сразу читаются как рывок. */
.cupx-item-frame.is-in {
    animation: cupx-item-in 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

.cupx-item-frame.is-in.is-back {
    animation-name: cupx-item-in-back;
}

@keyframes cupx-item-in {
    from { opacity: 0; transform: translateX(26px); }
    to { opacity: 1; transform: none; }
}

@keyframes cupx-item-in-back {
    from { opacity: 0; transform: translateX(-26px); }
    to { opacity: 1; transform: none; }
}

/* ── 3D-модель ──
 *
 * Холст лежит поверх снимка той же модели и проявляется, когда первый
 * кадр готов (cup-item.js ставит .is-live). Тень под моделью своя,
 * настоящая, — нарисованную стилями гасим. */
.cupx-item-model {
    position: absolute;
    inset: 0;
    z-index: 2;
    opacity: 0;
    transition: opacity 0.7s ease;
}

.cupx-item-model canvas {
    display: block;
    width: 100%;
    height: 100%;
    cursor: grab;
    touch-action: pan-y;
    outline: none;
}

.cupx-item-model canvas:active {
    cursor: grabbing;
}

.cupx-item-frame--model.is-live .cupx-item-model {
    opacity: 1;
}

.cupx-item-frame--model.is-live img,
.cupx-item-frame--model.is-live::after {
    opacity: 0;
    transition: opacity 0.7s ease;
}

/* Кольцо-подсказка: тонкая белая линия и точка, как в студии дизайна.
   Проходит по модели один раз и тянет её за собой (cup-item.js). */
.cupx-item-tap {
    position: absolute;
    left: 50%;
    top: 50%;
    z-index: 3;
    width: 0;
    height: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.35s ease;
}

.cupx-item-tap.is-on {
    opacity: 1;
}

.cupx-item-tap-ring,
.cupx-item-tap-dot {
    position: absolute;
    border-radius: 50%;
}

.cupx-item-tap-ring {
    left: -17px;
    top: -17px;
    width: 34px;
    height: 34px;
    border: 1.5px solid rgba(255, 255, 255, 0.96);
    box-shadow: 0 0 0 1px rgba(21, 23, 28, 0.16),
                inset 0 0 0 1px rgba(21, 23, 28, 0.1),
                0 4px 14px rgba(21, 23, 28, 0.14);
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cupx-item-tap-dot {
    left: -4px;
    top: -4px;
    width: 8px;
    height: 8px;
    background: #fff;
    box-shadow: 0 0 0 1px rgba(21, 23, 28, 0.18),
                0 2px 6px rgba(21, 23, 28, 0.3);
}

/* «Взяли» модель — кольцо сжимается к точке, «отпустили» — пружинит назад. */
.cupx-item-tap.is-press .cupx-item-tap-ring {
    transform: scale(0.7);
}

/* ── Стрелки, счётчик, миниатюры ── */

.cupx-item-arrow {
    position: absolute;
    top: 50%;
    z-index: 4;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-top: -22px;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

.cupx-item-arrow--prev {
    left: 16px;
}

.cupx-item-arrow--next {
    right: 16px;
}

.cupx-item-arrow svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.cupx-item-arrow:hover {
    border-color: #fff;
    background: #fff;
    color: var(--cup-ink);
}

.cupx-item-arrow:focus-visible,
.cupx-item-thumb:focus-visible {
    outline: 2px solid #dfedb4;
    outline-offset: 3px;
}

.cupx-item-count {
    position: absolute;
    right: 22px;
    bottom: 20px;
    z-index: 4;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    color: rgba(244, 246, 237, 0.62);
}

.cupx-item-count b {
    font-weight: 500;
    color: #f4f6ed;
}

/* Миниатюры — строкой под сценой. Не влезают — листаются вбок. */
.cupx-item-thumbs {
    display: flex;
    gap: 10px;
    margin-top: 14px;
    padding: 3px;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
}

/* Не влезли — край строки тает с той стороны, где есть ещё
   (классы ставит cup-item.js). */
.cupx-item-thumbs.has-more-end {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 56px), transparent);
}

.cupx-item-thumbs.has-more-start {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 56px), transparent);
    mask-image: linear-gradient(to left, #000 calc(100% - 56px), transparent);
}

.cupx-item-thumbs.has-more-start.has-more-end {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 56px, #000 calc(100% - 56px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 56px, #000 calc(100% - 56px), transparent);
}

.cupx-item-thumbs::-webkit-scrollbar {
    display: none;
}

.cupx-item-thumb {
    position: relative;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    padding: 8px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 16px;
    background: rgba(255, 255, 255, 0.06);
    scroll-snap-align: start;
    transition: border-color 0.25s ease, background-color 0.25s ease;
}

.cupx-item-thumb img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    opacity: 0.72;
    transition: opacity 0.25s ease;
}

.cupx-item-thumb--scene {
    padding: 0;
}

.cupx-item-thumb--scene img {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: cover;
}

.cupx-item-thumb:hover img,
.cupx-item-thumb[aria-pressed="true"] img {
    opacity: 1;
}

.cupx-item-thumb:hover {
    border-color: rgba(255, 255, 255, 0.36);
}

.cupx-item-thumb[aria-pressed="true"] {
    border-color: #f4f6ed;
    background: rgba(255, 255, 255, 0.14);
}

.cupx-item-thumb-mark {
    position: absolute;
    right: 6px;
    bottom: 4px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: #dfedb4;
}

/* ── Описание ── */

.cupx-item-info {
    min-width: 0;
    padding-top: clamp(4px, 1.4vw, 22px);
}

/* Не крупнее заголовка секции — самый крупный текст сайта (владелец). */
.cupx-item-info h1 {
    font-size: var(--cupx-text-max);
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.02em;
    color: #f4f6ed;
    text-wrap: balance;
}

.cupx-item-lead {
    margin-top: 18px;
    max-width: 52ch;
    font-size: 17px;
    line-height: 1.5;
    color: rgba(244, 246, 237, 0.92);
}

.cupx-item-about {
    margin-top: 12px;
    max-width: 56ch;
    font-size: 15px;
    line-height: 1.65;
    color: rgba(244, 246, 237, 0.7);
}

/* Свойства — две колонки с волосяной линией сверху у каждой строки,
   подпись моноширинным капсом, как подписи в студии и видеополосе. */
.cupx-item-specs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 28px;
    margin-top: 24px;
}

.cupx-item-specs > div {
    padding: 13px 0 14px;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.cupx-item-specs dt,
.cupx-item-volumes legend {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #b8cbac;
}

.cupx-item-specs dd {
    margin-top: 7px;
    font-size: 15px;
    line-height: 1.45;
    color: #f4f6ed;
}

/* Объём — таблетки. Выбранная заливается тем же светлым, что кнопка
   первого экрана: это один выбор — «этот объём, посчитайте». */
.cupx-item-volumes {
    min-width: 0;
    margin: 0;
    padding: 14px 0 0;
    border: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
}

.cupx-item-volumes legend {
    float: left;
    width: 100%;
    padding: 0;
}

.cupx-item-volume-list {
    clear: both;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 12px;
}

.cupx-item-volume {
    position: relative;
    cursor: pointer;
}

.cupx-item-volume input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.cupx-item-volume span {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    padding: 11px 18px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: 999px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    color: #f4f6ed;
    transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}

.cupx-item-volume small {
    font-size: 12px;
    font-weight: 500;
    opacity: 0.75;
}

.cupx-item-volume:hover span {
    border-color: #f4f6ed;
}

.cupx-item-volume input:checked + span {
    border-color: #dfedb4;
    background: #dfedb4;
    color: #153c2e;
}

.cupx-item-volume input:focus-visible + span {
    outline: 2px solid #dfedb4;
    outline-offset: 3px;
}

.cupx-item-volume-note {
    margin-top: 12px;
    font-size: 13px;
    line-height: 1.5;
    color: rgba(244, 246, 237, 0.55);
}

.cupx-item-actions {
    margin-top: 30px;
}

/* Кнопки — как на первом экране витрины: светлая таблетка и контур. */
.cupx-item-hero .cupx-btn {
    background: #dfedb4;
    color: #153c2e;
}

.cupx-item-hero .cupx-btn:hover {
    background: #eef6d4;
}

.cupx-item-hero .cupx-btn-ghost {
    border-color: rgba(255, 255, 255, 0.35);
    color: #f4f6ed;
}

.cupx-item-hero .cupx-btn-ghost:hover {
    border-color: #f4f6ed;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
}

.cupx-item-note {
    margin-top: 14px;
    font-size: 13px;
    line-height: 1.5;
    color: rgba(244, 246, 237, 0.55);
}

/* ── Конструкция ── */

.cupx-item-details {
    background: var(--cupx-white);
}

.cupx-item-features {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: clamp(20px, 3vw, 48px);
    margin-top: clamp(32px, 3.6vw, 52px);
}

.cupx-item-features li {
    padding-top: 22px;
    border-top: 1px solid var(--ink);
}

.cupx-item-feature-no {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 12px;
    letter-spacing: 0.1em;
    color: var(--cup-ink);
}

.cupx-item-features h3 {
    margin-top: 18px;
    font-size: 20px;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -0.01em;
    color: var(--ink);
}

.cupx-item-features p {
    margin-top: 10px;
    max-width: 40ch;
    font-size: 15px;
    line-height: 1.6;
    color: var(--ink-muted);
}

/* Объёмы в масштабе и «где подойдёт» — строкой ниже, двумя колонками. */
.cupx-item-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(32px, 5vw, 96px);
    margin-top: clamp(48px, 5.4vw, 80px);
}

.cupx-item-subhead {
    margin-bottom: 20px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

/* Силуэты стоят на общей линии прилавка — по ней и сравнивают высоту. */
.cupx-item-size-row {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    padding: 18px 20px 16px;
    border-radius: 22px;
    background: var(--cupx-mist);
}

.cupx-item-size {
    display: flex;
    flex: 1 1 0;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--cup-ink);
    cursor: pointer;
}

.cupx-item-size svg {
    width: 100%;
    max-width: 150px;
    height: auto;
    transition: opacity 0.3s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    transform-origin: 50% 93%;
}

.cupx-item-size > span {
    font-size: 15px;
    font-weight: 600;
    color: var(--ink);
}

.cupx-item-size small {
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-faint);
}

.cupx-item-size:hover svg {
    transform: translateY(-4px);
}

/* Объём выбран — остальные силуэты уходят в тень, выбранный остаётся
   в полном цвете. */
.cupx-item-size-row.has-pick .cupx-item-size svg {
    opacity: 0.35;
}

.cupx-item-size-row.has-pick .cupx-item-size[aria-pressed="true"] svg {
    opacity: 1;
}

.cupx-item-size[aria-pressed="true"] > span {
    color: var(--cup-ink);
}

.cupx-item-size:focus-visible {
    outline: 2px solid var(--cup-ink);
    outline-offset: 4px;
    border-radius: 12px;
}

.cupx-item-fits ul {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.cupx-item-fits li {
    padding: 10px 16px;
    border-radius: 999px;
    background: var(--cupx-mist);
    font-size: 14px;
    line-height: 1.2;
    color: var(--ink-soft);
}

/* ── Смотрите также ──
 *
 * Те же карточки, что в «Что мы делаем», но позиций на одну меньше —
 * пять в ряд. Уже — лентой, которая листается вбок: пять карточек
 * в сетке по три оставляли бы во втором ряду дыру. */
.cupx-item-more .cupx-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* ── Кнопка у нижней кромки (телефон) ── */

.cupx-item-bar {
    display: none;
}

/* ── Адаптив ── */

@media (max-width: 1360px) {
    .cupx-item-more .cupx-grid {
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-auto-columns: minmax(230px, calc((100% - 2px) / 3.3));
        overflow-x: auto;
        padding: 1px;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
    }

    .cupx-item-more .cupx-grid::-webkit-scrollbar {
        display: none;
    }

    .cupx-item-more .cupx-card {
        scroll-snap-align: start;
    }
}

@media (max-width: 1100px) {
    .cupx-item-more .cupx-grid {
        grid-auto-columns: minmax(220px, calc((100% - 2px) / 2.3));
    }
}

@media (max-width: 960px) {
    .cupx-item-top {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Сцена в одну колонку — не на весь экран: квадрат во всю ширину
       планшета съедал первый экран целиком, и описание уезжало вниз. */
    .cupx-item-stage {
        aspect-ratio: 5 / 4;
    }

    .cupx-item-features {
        grid-template-columns: minmax(0, 1fr);
        gap: 26px;
    }

    .cupx-item-facts {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 640px) {
    /* Название позиции в пути на телефоне переносилось второй строкой,
       начинаясь с косой черты, — а стоит оно и так крупно чуть ниже. */
    .cupx-crumbs li:last-child {
        display: none;
    }

    .cupx-item-stage {
        aspect-ratio: 1 / 1;
        border-radius: 22px;
    }

    .cupx-item-arrow {
        width: 38px;
        height: 38px;
        margin-top: -19px;
    }

    .cupx-item-arrow--prev {
        left: 10px;
    }

    .cupx-item-arrow--next {
        right: 10px;
    }

    .cupx-item-thumb {
        width: 58px;
        height: 58px;
        border-radius: 14px;
    }

    .cupx-item-specs {
        grid-template-columns: minmax(0, 1fr);
    }

    .cupx-item-actions .cupx-btn,
    .cupx-item-actions .cupx-btn-ghost {
        flex: 1 1 100%;
        justify-content: center;
    }

    .cupx-item-more .cupx-grid {
        grid-auto-columns: 76%;
    }

    /* Нижняя кнопка: название и «Запросить расчёт». Появляется, когда
       кнопка первого экрана ушла вверх, и прячется у самой формы. */
    .cupx-item-bar {
        position: fixed;
        left: 12px;
        right: 12px;
        bottom: calc(12px + env(safe-area-inset-bottom, 0px));
        z-index: 40;
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 8px 8px 8px 18px;
        border-radius: 999px;
        background: rgba(18, 59, 43, 0.92);
        -webkit-backdrop-filter: blur(14px);
        backdrop-filter: blur(14px);
        box-shadow: 0 12px 30px -12px rgba(4, 22, 15, 0.6);
        transform: translateY(calc(100% + 24px));
        transition: transform 0.4s cubic-bezier(0.22, 0.61, 0.36, 1);
    }

    .cupx-item-bar.is-on {
        transform: none;
    }

    .cupx-item-bar span {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 14px;
        font-weight: 600;
        color: #f4f6ed;
    }

    .cupx-item-bar .cupx-btn {
        flex: none;
        padding: 13px 20px;
        background: #dfedb4;
        color: #153c2e;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cupx-item-frame.is-in {
        animation: none;
    }

    .cupx-item-bar {
        transition: none;
    }
}
