/* ============================================================
   Блок «Витрина сайта (рамка устройства)» — case-showcase

   ГЕОМЕТРИИ РАМОК ЗДЕСЬ НЕТ И БЫТЬ НЕ ДОЛЖНО. Экран задаётся четырьмя
   процентами (--shot-x/y/w/h) и радиусом верхних углов (--shot-rx/ry),
   которые печатает PHP из массива $cs_frames. Два источника геометрии
   неминуемо разъедутся, поэтому в CSS только var().

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

   ПРО СПЕЦИФИЧНОСТЬ. Блок живёт внутри .case-body, где у темы есть свои
   правила на медиа. Самое опасное — .case-body > .row.case-split figure img
   (0,3,2): оно даёт картинке max-height: var(--case-media-max-h), и скрин
   высотой 9128px схлопнулся бы в ничто, окажись блок в половине ряда
   (сценарий Б). Поэтому у figure / device / shot / caption селекторы
   набирают ЧЕТЫРЕ класса — (0,4,0) перебивает (0,3,2) по числу классов.
   Там, где тема ничего не делает (панель, кнопки, ползунок), хватает двух.
   ============================================================ */


/* --- ПОСАДКА ПО ВЫСОТЕ (потолок высоты блока) ---
   Проблема, ради которой это сделано: рамка тянулась по МЕРЕ ШИРИНЫ
   (--case-wide = 1152px) и про высоту окна не знала. На 1440×1152 рамка
   ноутбука одна занимает 727px, плюс панель с подсказкой и подписью —
   блок перерастал типовое окно, и панель управления (стрелки, ползунок,
   «на весь экран») оказывалась ниже сгиба. Пользователь видел ноут, но не
   видел, чем его листать, и не понимал, что блок вообще интерактивный.

   Решение: фигура получает ВТОРОЙ потолок — не от ширины контейнера,
   а от свободной высоты. Высота рамки = ширина / пропорцию PNG, поэтому
   потолок высоты пересчитывается в потолок ширины умножением на --shot-ar
   (ширина/высота файла рамки; печатает PHP, где эти размеры и лежат).
   Ужимается при этом ВСЯ геометрия разом: экран внутри рамки задан
   процентами от её бокса, скрин — процентами от экрана, так что вырез
   никуда не съезжает и пропорции не рвутся.

   Слагаемые:
     --shot-vh     — высота окна. svh (не vh и не dvh): svh = окно при
                     ПОКАЗАННОЙ адресной строке, то есть худший случай;
                     на vh мобильный Safari отдал бы высоту без строки,
                     и панель снова уехала бы под неё.
     --shot-air    — воздух сверху/снизу, чтобы блок не упирался в края.
     --shot-chrome — высота арматуры под рамкой (панель + подсказка +
                     подпись с их отступами). Дефолт — прикидка на два
                     ряда текста; точное значение ставит JS замером
                     (высота фигуры минус высота рамки) и обновляет
                     на resize: посчитать в CSS её нельзя — она зависит
                     от того, во сколько строк лягут подсказка и подпись.
     --shot-floor  — пол: в очень низком окне блок перестаёт ужиматься,
                     иначе от витрины остался бы значок. 11rem подобраны
                     замером: у ноутбука пол не срабатывает никогда
                     (для этого окну надо быть ниже ~250px), а телефонная
                     рамка на коротком экране (375×560 и ниже) при 13rem
                     не влезала целиком, при 11rem влезает.
     --shot-cap    — потолок ширины (у телефона он свой, см. ниже).

   Ветки «если мобильный» тут нет намеренно: на узком высоком экране
   ширина контейнера и так меньше высотного потолка, и min() просто
   выбирает её — рамка остаётся во всю меру. */
.case-showcase {
	--shot-vh: 100vh;
	--shot-air: clamp(1rem, 4vh, 2rem);
	--shot-chrome: 8rem;
	--shot-floor: 11rem;
	--shot-cap: 100%;
}

@supports (height: 100svh) {
	.case-showcase {
		--shot-vh: 100svh;
	}
}


/* --- Мера ширины (§11 ТЗ) ---
   Базовое правило — «ширину задаёт то, во что блок положили»: в сценарии Б
   (блок в колонке ряда рядом с текстом) меру держит колонка, и поле
   «мера ширины» обязано молчать. Оно действует только в сценарии А —
   когда секция стоит прямым ребёнком .case-body.

   .case-body > section (0,1,1) навязывает всем встроенным секциям
   --case-wide; два класса (0,2,0) это перебивают. */
.case-showcase.case-native {
	max-width: 100%;
	margin-inline: auto;
}

.case-body > .case-showcase.case-showcase--w-col {
	max-width: var(--case-col);
}

.case-body > .case-showcase.case-showcase--w-wide {
	max-width: var(--case-wide);
}

.case-body > .case-showcase.case-showcase--w-full {
	max-width: var(--case-full);
}

/* Вертикальный ритм между блоками задаёт тема (.case-body > * + *),
   своих margin-top / padding-block у секции нет намеренно. */


/* --- Фигура ---
   Класс продублирован не по небрежности: см. «ПРО СПЕЦИФИЧНОСТЬ» в шапке —
   .case-body > .row.case-split figure (0,3,1) иначе выигрывает и навязывает
   width: fit-content вместе с max-width: 100%, а последнее убивает
   ограничение ширины телефонной рамки ниже. */
.case-showcase.case-native .case-showcase__figure.case-showcase__figure {
	width: 100%;
	/* фолбэк для браузера без min()/max(): просто ширина контейнера —
	   объявление ниже он отбросит целиком как невалидное */
	max-width: 100%;
	/* меньшее из двух: потолок ширины и потолок высоты (см. «ПОСАДКА
	   ПО ВЫСОТЕ»). --shot-ar приходит инлайном от PHP, поэтому calc
	   живёт здесь, а не в --shot-* на секции: подстановка var() внутри
	   пользовательского свойства происходит на ТОМ элементе, где оно
	   объявлено, и на секции --shot-ar ещё не виден. */
	max-width: min(
		var(--shot-cap, 100%),
		max(
			var(--shot-floor, 11rem),
			calc((var(--shot-vh, 100vh) - var(--shot-air, 2rem) - var(--shot-chrome, 8rem)) * var(--shot-ar, 1.585))
		)
	);
	margin: 0 auto;
}

/* Телефон уже ноутбука физически: на всю меру раздела он выглядел бы
   как афиша. Легаси лечило это transform: scale(1.45) на 425px — приём
   не переносим: scale на блоке в потоке ломает вертикальный ритм
   (место занимается по неотмасштабированному боксу) и режет тени.

   Задаётся через --shot-cap, а не max-width: потолок ширины должен
   участвовать в том же min(), что и потолок высоты, иначе одно
   правило молча перебивало бы другое. */
.case-showcase--phone {
	--shot-cap: 260px;
}

@media (min-width: 576px) {
	.case-showcase--phone {
		--shot-cap: 300px;
	}
}

@media (min-width: 992px) {
	.case-showcase--phone {
		--shot-cap: 320px;
	}
}


/* --- Рамка устройства ---
   Пропорцию держит сама картинка рамки: <img> с width/height в атрибутах
   и height: auto. Никаких aspect-ratio и фиксированных высот — иначе
   геометрия экрана (в процентах от этого бокса) поедет. */
.case-showcase .case-showcase__frame {
	position: relative;
}

.case-showcase.case-native .case-showcase__frame .case-showcase__device {
	display: block;
	width: 100%;
	max-width: 100%;
	height: auto;
	max-height: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
}


/* --- Экран ---
   Ложится ПОВЕРХ картинки рамки (абсолютный блок после <img>), координаты —
   проценты от бокса рамки, поэтому вырез совпадает при любой ширине.
   Скругление правит --shot-rx/ry из PHP: у обеих текущих рамок вырез
   замерен построчно и оказался идеальным прямоугольником, так что там нули,
   но переменные оставлены — рамка со скруглённым стеклом их включит,
   не трогая CSS. Скругляются только верхние углы: низ выреза всегда
   упирается в корпус (петля ноутбука / подбородок телефона). */
.case-showcase .case-showcase__screen {
	position: absolute;
	left: var(--shot-x, 0%);
	top: var(--shot-y, 0%);
	width: var(--shot-w, 100%);
	height: var(--shot-h, 100%);
	overflow: hidden;
	border-radius:
		var(--shot-rx, 0%) var(--shot-rx, 0%) 0 0 /
		var(--shot-ry, 0%) var(--shot-ry, 0%) 0 0;
	/* подложка до загрузки скрина: чуть мягче чистого «ink», чтобы
	   выключенный экран не выглядел дырой в странице */
	background-color: color-mix(in srgb, var(--ctx-ink) 92%, var(--ctx-surface));
	/* кольцо фокуса рисует тема (--focus-ring-color), от блока — только отступ */
	outline-offset: 3px;
}

/* ⚠️ …но на САМОМ экране этого кольца не видно, и это не придирка:
   --focus-ring-color = акцент палитры, подобранный контрастным к ФОНУ
   СТРАНИЦЫ, а экран — почти чёрный прямоугольник. На кейсе «Шаг за шагом»
   акцент светлой темы #4a3a1e, и 3px тёмно-коричневого по чёрному
   не читается вообще (проверено). Поэтому кольцо переносим на всю рамку:
   там оно лежит на фоне страницы, где контраст гарантирован самой системой
   токенов, и заодно видно, ЧТО именно сейчас под клавиатурой.
   Под @supports — чтобы браузер без :has() не остался вовсе без кольца
   (правило `outline: none` тогда просто не применится). */
@supports selector(:has(*)) {
	.case-showcase .case-showcase__screen:focus-visible {
		outline: none !important; /* перебить !important темы можно только так */
	}

	.case-showcase .case-showcase__frame:has(.case-showcase__screen:focus-visible) {
		outline: var(--focus-ring-width, 3px) solid var(--focus-ring-color, var(--ctx-accent));
		outline-offset: 3px;
	}
}

@supports not (color: color-mix(in srgb, red, blue)) {
	.case-showcase .case-showcase__screen {
		background-color: var(--ctx-ink);
	}
}

/* Экран кликабелен (пуск/пауза). touch-action: manipulation убирает
   300-мс ожидание двойного тапа — без него первый тап «залипает».
   Именно manipulation, а НЕ none: none отобрал бы у пользователя
   вертикальный свайп, а на 375px рамка занимает почти весь экран
   и он оказался бы заперт в блоке. */
.case-showcase:not(.case-showcase--static) .case-showcase__screen {
	cursor: pointer;
	touch-action: manipulation;
}

/* Скрин не длиннее экрана рамки — проматывать нечего, просто центрируем */
.case-showcase--static .case-showcase__screen {
	display: flex;
	align-items: center;
}


/* --- Сам скриншот ---
   Движение — transform, а не background-position (легаси): позиция фона
   анимируется перерисовкой всего слоя, трансформ уходит на композитор.
   translateY в процентах считается от высоты САМОГО элемента, поэтому
   --shot-travel приходит долей высоты скрина, а не пикселями. */
.case-showcase.case-native .case-showcase__screen .case-showcase__shot {
	display: block;
	width: 100%;
	max-width: none;
	height: auto;
	max-height: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	transform: translate3d(0, calc(var(--shot-p, 0) * -1 * var(--shot-travel, 0%)), 0);
	transition: transform var(--shot-duration, 0s) linear;
}

/* Композиторный слой держим только на время движения: постоянный
   will-change на картинке в 9000px — это лишняя текстура в памяти. */
.case-showcase.is-playing .case-showcase__shot {
	will-change: transform;
}

/* Фолбэк без JS: пока скрипт не пометил блок классом is-js, работает
   старое поведение по наведению — длительность берётся из --shot-full.
   Гасится сразу, как только блок ожил, иначе hover дрался бы с состоянием. */
@media (hover: hover) and (pointer: fine) {
	.case-showcase:not(.is-js):not(.case-showcase--static) .case-showcase__screen:hover .case-showcase__shot {
		--shot-p: 1;
	}
}


/* --- Панель управления ---
   Стрелки переехали из бортика рамки в панель под ней. Причина: у телефонной
   рамки бортика нет — в легаси стрелки висели на -22px НАРУЖУ и вылезали
   за блок, а поверх экрана на 375px они закрывают сам скрин. */
.case-showcase .case-showcase__bar {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: var(--case-gap, 0.75rem);
}

.case-showcase .case-showcase__btn {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 44×44 — минимальный тач-таргет; на десктопе ниже уменьшается до 40 */
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid var(--ctx-border);
	border-radius: 0.5rem;
	background-color: var(--ctx-surface);
	color: var(--ctx-ink);
	font-size: 1rem;
	line-height: 1;
	cursor: pointer;
	touch-action: manipulation;
	outline-offset: 3px;
	transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

/* :hover — только там, где есть настоящий курсор: на тач-устройствах
   он залипает после тапа и кнопка остаётся «нажатой». */
@media (hover: hover) and (pointer: fine) {
	.case-showcase .case-showcase__btn:hover:not(:disabled) {
		background-color: var(--ctx-accent);
		color: var(--ctx-on-accent);
		box-shadow: var(--macro-shadow-sm);
	}
}

.case-showcase .case-showcase__btn:active:not(:disabled),
.case-showcase .case-showcase__btn[aria-pressed="true"] {
	background-color: var(--ctx-accent);
	color: var(--ctx-on-accent);
	box-shadow: var(--macro-shadow-sm);
}

/* Цвет у выключенной кнопки не меняем — только прозрачность:
   перекрашивание читалось бы как ещё одно состояние. */
.case-showcase .case-showcase__btn:disabled {
	opacity: 0.45;
	cursor: default;
}

@media (min-width: 992px) {
	.case-showcase .case-showcase__btn {
		width: 40px;
		height: 40px;
	}
}


/* --- Ползунок позиции ---
   Единственный честный способ «потянуть пальцем»: браузер сам разводит
   горизонтальное перетаскивание бегунка и вертикальный свайп страницы. */
.case-showcase .case-showcase__range {
	flex: 1 1 auto;
	min-width: 0;
	height: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	-webkit-appearance: none;
	appearance: none;
	accent-color: var(--ctx-accent);
	cursor: pointer;
	outline-offset: 3px;
}

/* Заполненная часть дорожки в WebKit рисуется градиентом: своего
   ::-webkit-*-progress там нет. Долю ведёт --shot-ui — «живой» прогресс,
   который JS обновляет покадрово (--shot-p прыгает к цели сразу, он цель
   трансформа, а не текущее положение). */
.case-showcase .case-showcase__range::-webkit-slider-runnable-track {
	height: 0.25rem;
	border-radius: 0.25rem;
	background-image: linear-gradient(
		to right,
		var(--ctx-accent) calc(var(--shot-ui, 0) * 100%),
		var(--ctx-border) 0
	);
}

.case-showcase .case-showcase__range::-webkit-slider-thumb {
	-webkit-appearance: none;
	width: 1rem;
	height: 1rem;
	margin-top: -0.375rem;
	border: 0;
	border-radius: 50%;
	background-color: var(--ctx-accent);
	box-shadow: var(--macro-shadow-sm);
}

.case-showcase .case-showcase__range::-moz-range-track {
	height: 0.25rem;
	border-radius: 0.25rem;
	background-color: var(--ctx-border);
}

.case-showcase .case-showcase__range::-moz-range-progress {
	height: 0.25rem;
	border-radius: 0.25rem;
	background-color: var(--ctx-accent);
}

.case-showcase .case-showcase__range::-moz-range-thumb {
	width: 1rem;
	height: 1rem;
	border: 0;
	border-radius: 50%;
	background-color: var(--ctx-accent);
	box-shadow: var(--macro-shadow-sm);
}


/* --- Подсказка и подпись --- */

/* .case-body p (0,1,1) задаёт лонгридный размер — здесь нужен мельче */
.case-showcase .case-showcase__hint {
	margin: 0.5rem 0 0;
	font-size: 0.8125rem;
	line-height: 1.45;
	color: var(--ctx-muted);
}

/* Подпись — те же значения, что у .case-body figcaption; width/min-width
   возвращаем себе у рядов case-split/case-media/case-gallery, где тема
   обнуляет ширину подписи, чтобы она не раздувала figure. */
.case-showcase.case-native .case-showcase__figure .case-showcase__caption {
	width: auto;
	min-width: 0;
	margin-top: 0.625rem;
	font-size: 0.875rem;
	line-height: 1.45;
	color: var(--ctx-muted);
	text-align: left;
}

/* Подсказка пустого блока — видна только в редакторе */
.case-showcase__hint--empty {
	margin: 0;
	padding: 1rem;
	border: 1px dashed var(--ctx-border);
	border-radius: 0.5rem;
	color: var(--ctx-muted);
}


/* --- Полноэкранный просмотр ---
   Штатный модал Bootstrap 5 (bundle уже в очереди темы). Готового лайтбокса
   в проекте нет, внешние CDN запрещены, нативный Fullscreen API отклонён:
   на iPhone Safari requestFullscreen для элемента не работает. */
/* !important здесь единственный на весь блок и вынужденный: тема объявляет
   .modal-content { border-radius: 2.25rem !important } глобально (style.css:44),
   а в полноэкранном режиме скруглённые углы срезают углы скриншота и открывают
   страницу под модалом. Перебить !important можно только !important. */
.case-showcase-modal .modal-content {
	border: 0;
	border-radius: 0 !important;
	background-color: var(--ctx-surface);
	color: var(--ctx-ink);
}

.case-showcase-modal .modal-header {
	border-bottom: 1px solid var(--ctx-border);
}

.case-showcase-modal .modal-title {
	margin: 0;
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.3;
	letter-spacing: 0;
	color: var(--ctx-ink);
}

/* Страховка на случай, если скрипт не успел (или не смог) вынести модал
   из .case-body: там .case-body h2 навешивает автонумерацию разделов
   (counter-increment: case-sec + ::before с номером), и заголовок модала
   утащил бы себе номер, сдвинув нумерацию всей страницы кейса.
   Три класса (0,3,0) перебивают .case-body h2 (0,1,1). */
.case-body .case-showcase-modal .modal-title {
	counter-increment: none;
	font-size: 1rem;
}

.case-body .case-showcase-modal .modal-title::before {
	content: none;
}

/* Прокрутка по обеим осям; overscroll-behavior: contain — чтобы докрутив
   до края, не начать листать страницу под модалом. */
.case-showcase-modal .modal-body {
	padding: 0;
	overflow: auto;
	overscroll-behavior: contain;
	background-color: var(--ctx-surface);
}

/* Натуральная величина — это и есть режим «рассмотреть». Горизонтальная
   прокрутка на узком экране здесь не баг, а условие читаемости. */
.case-showcase-modal .modal-body .case-showcase__full {
	display: block;
	width: auto;
	max-width: none;
	height: auto;
	max-height: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
}


/* --- prefers-reduced-motion ---
   Гард СВОЙ, и в CSS, и в JS: подключённый на сайте AOS этот медиазапрос
   не обрабатывает вовсе. 15–25-секундный проезд — ровно то движение,
   которое флаг и выключает; вместо него JS даёт мгновенный шаг на экран. */
@media (prefers-reduced-motion: reduce) {
	.case-showcase.case-native .case-showcase__screen .case-showcase__shot {
		transition: none;
	}

	.case-showcase .case-showcase__btn {
		transition: none;
	}

	.case-showcase:not(.is-js):not(.case-showcase--static) .case-showcase__screen:hover .case-showcase__shot {
		--shot-p: 0;
	}
}
