/* ===========================================================================
   my-ui — слайдер (галерея снимков)

   Разметка — slider.md, поведение — slider.js.

   Классы состояний ставит скрипт:
     .ui-slider.is-single     в кадре один снимок (телефон) — режим шторки
     .ui-slider__slide.is-current   снимок, который виден сейчас
     .ui-slider__wipe         слой шторки, живёт только во время смены
     .ui-slider__wipe.is-riding     шторка поехала
     .ui-slider__dot.is-active      отметка текущего кадра

   Главное правило: при смене кадра не должно меняться НИЧЕГО, кроме обрезки
   и порядка слоёв. Ни display, ни position, ни размеры, ни слой композитинга —
   каждое из этих изменений даёт рывок в конце перехода.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Кадр и лента
   --------------------------------------------------------------------------- */

.ui-slider {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 12px;
}

/* Обойма обрезает ленту по скруглённому краю. Отдельный узел, а не сама
   лента: лента шириной в один кадр, соседние снимки лежат за её краем,
   и overflow: hidden на ней срезал бы их — вместо следующего снимка
   ехала бы пустота. */
.ui-slider__frame {
	position: relative;
	overflow: hidden;
	border-radius: var(--ui-radius-lg);
}

.ui-slider__track {
	position: relative;
	display: flex;
	/* Зазора между кадрами быть не должно: при листании лентой через экран
	   проезжала бы полоса фона страницы, а такого шва нет ни в одном
	   настоящем слайдере. Скругление — на обойме, не на кадрах, иначе
	   на стыке встречаются два круглых угла. */
	gap: 0;
	transition: transform var(--ui-base) ease;
}

.ui-slider__slide {
	flex: 0 0 100%;
	height: var(--ui-slide-h, 400px);
	background: var(--ui-card);
	cursor: pointer;
}

.ui-slider__slide img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Два кадра в ряд на большом экране — необязательный режим. */
.ui-slider--pair .ui-slider__track {
	gap: 20px;
}

.ui-slider--pair .ui-slider__slide {
	flex-basis: calc(50% - 10px);
}

/* ---------------------------------------------------------------------------
   2. Смена кадра шторкой (один кадр в поле зрения)

   Лента не едет вовсе: новый снимок открывается обрезкой от правого края
   к левому поверх прежнего — той же шторкой, какой появляются заголовки
   (reveal.css, .ui-reveal--wipe). Прежний кадр с места не двигается.
   --------------------------------------------------------------------------- */

.ui-slider.is-single .ui-slider__track {
	display: block;
	transition: none;
}

.ui-slider.is-single .ui-slider__slide {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	/* Высоту задаёт своё правило, ширину — left/right. Пропорцию, если она
	   стоит на кадре в общих стилях, здесь обязательно снять: у элемента
	   вне потока она считает ТО измерение, которое не задано явно, и молча
	   перебивает right/bottom. Кадр выходит другой ширины, чем слой шторки,
	   object-fit кадрирует иначе — и в конце перехода снимок скачет. */
	aspect-ratio: auto;
	opacity: 0;
	z-index: 0;
}

/* Первый кадр остаётся в потоке и задаёт ленте высоту. Иначе её пришлось бы
   прописывать числом вторым местом и держать в согласии руками. */
.ui-slider.is-single .ui-slider__slide:first-child {
	position: relative;
}

.ui-slider.is-single .ui-slider__slide.is-current {
	opacity: 1;
	z-index: 1;
}

/* Слой шторки — копия снимка поверх ленты. Каждое касание кладёт свой,
   поэтому несколько идут одновременно, одна поверх другой. Обрезать сами
   кадры для этого нельзя: снимков часто два, и на втором касании наезжать
   пришлось бы тому же узлу, который лежит основой, — он ушёл бы под
   обрезку, и в незакрытой части кадра просвечивала бы пустота. */
.ui-slider__wipe {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	overflow: hidden;
	background: var(--ui-card);
	clip-path: inset(0 0 0 100%);
	pointer-events: none;
}

.ui-slider__wipe img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Кривая и направление те же, что у шторки заголовков; длительность больше —
   снимок крупнее строки. Значение совпадает с WIPE_MS в slider.js. */
.ui-slider__wipe.is-riding {
	clip-path: inset(0 0 0 0);
	transition: clip-path 0.9s cubic-bezier(0.25, 0.55, 0.6, 0.9);
}

/* ---------------------------------------------------------------------------
   3. Управление: строка под кадром
   --------------------------------------------------------------------------- */

.ui-slider__bar {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 40px;
}

/* Стрелка без кружка: под кадром фон известен, и обводка только утяжеляет.
   Кружок нужен, только когда стрелка лежит поверх снимка. Цель касания
   остаётся 44×44 при знаке 22. */
.ui-slider__arrow {
	appearance: none;
	-webkit-appearance: none;
	display: flex;
	align-items: center;
	justify-content: center;
	width: var(--ui-touch);
	height: var(--ui-touch);
	padding: 0;
	border: 0;
	background: none;
	color: var(--ui-line);
	cursor: pointer;
	transition: color var(--ui-base) var(--ui-ease),
		transform var(--ui-base) var(--ui-ease);
}

.ui-slider__arrow svg {
	display: block;
	width: 22px;
	height: 22px;
}

/* :hover на тачскрине залипает — отклик даём на нажатие. */
.ui-slider__arrow:active {
	color: var(--ui-accent);
	transform: scale(0.88);
}

.ui-slider__arrow:focus-visible {
	outline: 2px solid var(--ui-accent);
	outline-offset: 2px;
	border-radius: var(--ui-pill);
}

.ui-slider__dots {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
}

/* Переход ширины стоит ТОЛЬКО на активном состоянии, и это не опечатка.
   Браузер берёт переход из того состояния, В КОТОРОЕ переходит. Значит,
   точка вырастает в полоску плавно, а полоска обратно не сжимается —
   сразу становится точкой. Деформируется только та отметка, которая
   становится текущей; точка — никогда.

   Анимировать ширину в обе стороны нельзя: тогда одновременно идут два
   встречных движения — одно растягивается, второе сжимается, и ряд
   читается как резиновый. */
.ui-slider__dot {
	width: 7px;
	height: 7px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--ui-line);
	cursor: pointer;
	transition: background-color var(--ui-base) var(--ui-ease);
}

.ui-slider__dot.is-active {
	width: 30px;
	border-radius: var(--ui-pill);
	background: var(--ui-accent);
	transition: width var(--ui-slow) var(--ui-ease),
		background-color var(--ui-base) var(--ui-ease);
}

/* ---------------------------------------------------------------------------
   4. Уменьшенное движение
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	.ui-slider__track,
	.ui-slider__wipe.is-riding,
	.ui-slider__arrow {
		transition: none;
	}

	.ui-slider__arrow:active {
		transform: none;
	}
}
