/*
 * theSpirit Slider — front-end and editor styles.
 *
 * Loaded as the block's `style` handle, so it applies on the front end and in
 * the editor (where only the placeholder rules at the bottom come into play).
 *
 * Colours are read from the theme's own presets with a hard-coded fallback, so
 * the slider follows a palette change in theme.json without being edited.
 */

.ts-slider {
	position: relative;
}

/*
 * Height
 * ---------------------------------------------------------------------------
 * "tallest" needs no JavaScript and no measuring. The slides are flex items on
 * one line of `.splide__list`, so the line's height is already the height of
 * the tallest slide's content, and `align-items: stretch` (the default) gives
 * every slide — including Splide's loop clones — exactly that height. The
 * track, being the flex line's container, follows.
 *
 * This also means the equal heights survive with JavaScript disabled or
 * before Splide mounts, and that the slider shrinks again when the content
 * gets shorter — a measured min-height written back onto the track could only
 * ever grow, because the next measurement would read the value it had just
 * imposed.
 */
.ts-slider__track {
	min-height: var(--tsslider-min-height, 0px);
}

.ts-slider--height-ratio .ts-slider__track {
	aspect-ratio: var(--tsslider-ratio, 16 / 9);
}

.ts-slider--height-fixed .ts-slider__track {
	height: var(--tsslider-height, 500px);
}

@media (max-width: 781px) {
	.ts-slider--height-fixed .ts-slider__track {
		height: var(--tsslider-height-mobile, 320px);
	}
}

/*
 * Slides
 * ---------------------------------------------------------------------------
 * The inner element always fills the slide, whatever the alignment — it is the
 * layer a background belongs on, so it has to reach the slide's edges even
 * when the content inside it is short. Where the content then sits within that
 * filled box is what the alignment setting decides.
 */
.ts-slider__slide {
	display: flex;
	box-sizing: border-box;
}

.ts-slider__inner {
	display: flex;
	flex-direction: column;
	width: 100%;
	box-sizing: border-box;
	padding: var(--tsslider-slide-padding, 0);
}

.ts-slider--align-top .ts-slider__inner {
	justify-content: flex-start;
}

.ts-slider--align-center .ts-slider__inner {
	justify-content: center;
}

.ts-slider--align-bottom .ts-slider__inner {
	justify-content: flex-end;
}

/*
 * "Fill": the content wrapper takes the whole remaining height instead of
 * shrink-wrapping its blocks, so a slide shorter than the tallest one is no
 * longer a small island of content floating in blank space.
 *
 * A slide built the usual way — one Group block carrying the background,
 * padding and colours — is matched by :only-child and stretches with the
 * wrapper, so its background covers the slide edge to edge. A slide holding
 * several top-level blocks keeps them at their natural heights and centres
 * them, because stretching each one individually would pull the text apart.
 */
.ts-slider--align-stretch .ts-slider__inner {
	justify-content: center;
}

/*
 * The fill follows a chain of single-child containers rather than just the
 * first one, because the block that actually carries the background is rarely
 * the outermost: the editor wraps a slide in a group, and the coloured group
 * sits inside that. Stretching only the outer, transparent wrapper would look
 * like nothing had happened.
 *
 * A link in the chain becomes a flex column only when it holds exactly one
 * block — hence :has(). Turning a container with several children into a flex
 * container would make those children flex items, and adjacent flex items do
 * not collapse their margins, so the slide's text would be spaced differently
 * here than the same blocks are on a page. With a single child there are no
 * sibling margins to collapse, so the flex context costs nothing.
 *
 * The chain stops at three levels. Below that are figures, buttons and list
 * items that also happen to hold one child, and stretching those would
 * distort them.
 *
 * Browsers without :has() simply centre the content — the behaviour this mode
 * replaced — so the fallback is the previous design, not a broken layout.
 */
.ts-slider--align-stretch .ts-slider__content:has( > :only-child ),
.ts-slider--align-stretch .ts-slider__content > :only-child:has( > :only-child ),
.ts-slider--align-stretch
	.ts-slider__content
	> :only-child
	> :only-child:has( > :only-child ) {
	display: flex;
	flex-direction: column;
	width: 100%;
}

/*
 * The wrapper has to grow first. Everything below it fills a share of a height
 * that only exists once this element has claimed the slide's spare space.
 */
.ts-slider--align-stretch .ts-slider__content:has( > :only-child ),
.ts-slider--align-stretch .ts-slider__content > :only-child,
.ts-slider--align-stretch .ts-slider__content > :only-child > :only-child,
.ts-slider--align-stretch
	.ts-slider__content
	> :only-child
	> :only-child
	> :only-child {
	flex: 1 1 auto;
}

/* Room for the controls, only when they are actually rendered. */
.ts-slider--has-arrows .ts-slider__inner {
	padding-left: var(--tsslider-arrow-space, 4rem);
	padding-right: var(--tsslider-arrow-space, 4rem);
}

.ts-slider--has-pagination .ts-slider__inner {
	padding-bottom: 3rem;
}

/*
 * No bottom reservation while filling: the point of that mode is that the
 * slide layer reaches the bottom edge, so the dots sit on top of it rather
 * than on a strip of page background below it.
 */
.ts-slider--align-stretch.ts-slider--has-pagination .ts-slider__inner {
	padding-bottom: 0;
}

/*
 * The content wrapper carries `is-layout-constrained`, so the max-width,
 * centring and alignwide/alignfull handling all come from the layout rules
 * WordPress already prints for every block theme. Nothing to redeclare here —
 * only the first/last margin reset that a constrained container normally gets
 * from its block styles.
 */
.ts-slider__content > *:first-child {
	margin-block-start: 0;
}

.ts-slider__content > *:last-child {
	margin-block-end: 0;
}

/*
 * Fade needs no CSS of its own. Splide leaves the slides as flex items in a row
 * and pulls each one back onto the first position with an inline
 * `translateX(-index * 100%)`, so they overlap without being taken out of flow
 * — which also means the row, and with it the track, keeps the height of the
 * tallest slide. Stacking them by any other means (grid, absolute positioning)
 * fights those transforms and pushes the slides off screen.
 */

/*
 * Arrows
 * ---------------------------------------------------------------------------
 * Only splide-core.min.css is bundled, so the controls are unstyled by
 * default and everything below is ours rather than an override of a theme.
 */
.ts-slider .splide__arrow {
	position: absolute;
	top: 50%;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	margin: 0;
	padding: 0;
	transform: translateY(-50%);
	border: 0;
	border-radius: 50%;
	background: var(--wp--preset--color--base, #fff);
	color: var(--wp--preset--color--modra, #27358b);
	box-shadow: 0 2px 12px rgba(0, 0, 0, 0.18);
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}

.ts-slider .splide__arrow svg {
	width: 1.25rem;
	height: 1.25rem;
	fill: currentColor;
}

.ts-slider .splide__arrow--prev {
	left: clamp(0.5rem, 2vw, 1.5rem);
}

/*
 * Splide ships one chevron and mirrors it for the previous arrow — a rule that
 * lives in the default theme stylesheet, which is not bundled here.
 */
.ts-slider .splide__arrow--prev svg {
	transform: scaleX(-1);
}

.ts-slider .splide__arrow--next {
	right: clamp(0.5rem, 2vw, 1.5rem);
}

.ts-slider .splide__arrow:hover:not(:disabled),
.ts-slider .splide__arrow:focus-visible {
	background: var(--wp--preset--color--zlata, #fcc62c);
	color: var(--wp--preset--color--contrast, #111);
}

.ts-slider .splide__arrow:focus-visible {
	outline: 2px solid var(--wp--preset--color--modra, #27358b);
	outline-offset: 3px;
}

.ts-slider .splide__arrow:disabled {
	opacity: 0.35;
	cursor: default;
}

@media (max-width: 600px) {
	.ts-slider {
		--tsslider-arrow-space: 2.75rem;
	}

	.ts-slider .splide__arrow {
		width: 2.25rem;
		height: 2.25rem;
	}

	.ts-slider .splide__arrow svg {
		width: 1rem;
		height: 1rem;
	}
}

/*
 * Pagination
 * ---------------------------------------------------------------------------
 * Splide appends the dots as a sibling of the track inside `.splide`, which is
 * positioned, so anchoring them to the bottom keeps them inside the slider
 * container rather than under it. The track carries `z-index: 0` from Splide's
 * own stylesheet and so opens a stacking context the slides cannot escape;
 * a higher z-index here therefore puts the dots above the slide layer.
 */
.ts-slider .splide__pagination {
	position: absolute;
	right: 0;
	bottom: 1rem;
	left: 0;
	z-index: 3;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ts-slider .splide__pagination li {
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * A slide's background is whatever the editor put in it, so the dots have to
 * read on both a white section and a dark photo. A solid dot carrying a light
 * ring covers both: the ring separates it from a dark background, the fill from
 * a light one.
 */
.ts-slider .splide__pagination__page {
	display: block;
	width: 0.5rem;
	height: 0.5rem;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--wp--preset--color--modra, #27358b);
	opacity: 0.4;
	box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.75);
	cursor: pointer;
	transition: background-color 0.2s ease, opacity 0.2s ease, transform 0.2s ease;
}

.ts-slider .splide__pagination__page:hover {
	opacity: 0.7;
}

.ts-slider .splide__pagination__page.is-active {
	background: var(--wp--preset--color--zlata, #fcc62c);
	opacity: 1;
}

.ts-slider .splide__pagination__page:focus-visible {
	outline: 2px solid var(--wp--preset--color--modra, #27358b);
	outline-offset: 3px;
}

/*
 * Editor placeholder
 * ---------------------------------------------------------------------------
 * The block does not run Splide in the editor — the canvas is an iframe without
 * the view script — so editor.js renders this summary instead.
 */
.ts-slider-placeholder {
	padding: 1.5rem;
	border: 1px dashed var(--wp--preset--color--bledoseda, #dee3e7);
	border-radius: 8px;
	background: var(--wp--preset--color--svetloseda, #f9fafb);
	color: var(--wp--preset--color--tmavoseda, #201d1d);
	text-align: left;
}

.ts-slider-placeholder__title {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin: 0 0 0.75rem;
	font-size: 0.9375rem;
	font-weight: 700;
	color: var(--wp--preset--color--modra, #27358b);
}

.ts-slider-placeholder__meta {
	margin: 0 0 0.75rem;
	font-size: 0.8125rem;
	color: var(--wp--preset--color--stredneseda, #848484);
}

.ts-slider-placeholder__list {
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: 0.875rem;
}

.ts-slider-placeholder__list li {
	padding: 0.35rem 0;
	border-top: 1px solid var(--wp--preset--color--bledoseda, #dee3e7);
}

.ts-slider-placeholder__list li:before {
	content: counter(list-item) ".";
	display: inline-block;
	min-width: 1.5rem;
	color: var(--wp--preset--color--stredneseda, #848484);
}

.ts-slider-placeholder__empty {
	margin: 0;
	font-size: 0.875rem;
	color: var(--wp--preset--color--stredneseda, #848484);
}
