/* Shared slider chrome — template-parts/slider.php + assets/js/slider.js.
   Every value is read from the .fig's own slider library nodes:

   - arrows «Arrow Button» 3159:2048 — 64×64 (Default), 40×40 (mob=on),
     84×84 (Full HD=on); 1px inside stroke; icon «Arrow--left/right»
     3014:2433 / 3014:2422, a 24×24 box with an 18×15 glyph;
   - dots «Pagination Dots» 3327:12953 (light, Scene Gallery) and
     4277:27542 (dark, Performer Testimonials) — 16×16, gap 18, the
     active one filled with a 2px inner ring;
   - counter 4267:15995 — «1/3» in «S/S text (regular)» #272B30, inside
     the nav row 4267:15994 this component's own nav layout comes from
     (counter left, arrow pair right, space-between). The other counter in
     the file (3206:3682, «1/20» in «Menu,button» 600 #697482) belongs to
     the «ще цікаве» carousel label, a different layout — noted in
     designer-questions.md.

   Colour substitutions, all of the kind designer-questions.md already
   records for this palette:

   - arrow hover stroke + glyph: the .fig's #12AD99 (--color-primary-500)
     is 2.8:1 on white, under WCAG 1.4.11's 3:1 for a non-text UI
     component → --color-primary-600 (3.7:1), the same substitution
     event-card.css makes for its own #12AD99;
   - inactive dot: the .fig's #E1E5EA (--color-neutral-200) is 1.3:1 on
     the page — the dot IS the button, so its own boundary needs 3:1 →
     --color-neutral-500 (4.8:1), matching a11y-panel.css's substitution
     for the #D0D5DC toggle track. The ACTIVE dot keeps the .fig's
     #E1E5EA ring: it sits inside the dot, so it is decoration, and the
     ring is also what distinguishes «current» by shape and not by
     colour alone.
   - inactive ARROW keeps the .fig's #99A4B2: WCAG 1.4.11 exempts
     inactive components, and the button carries aria-disabled.

   Slide change — 300ms cubic-bezier(0,0,0.58,1), a development choice
   (client fix ПР-13, 23.09): fig-canvas.js interactions reports no
   ON_CLICK action on any slider arrow or dot in the working `design`
   page, so the file names no duration at all. The number is not
   arbitrary — the one carousel movement the .fig DOES draw is the person
   page's testimonial stack («Frame 1437255027» 3426:12092: blocks shift
   500px, 300ms, ease out), and person.css already implements exactly
   these values; the theme's own header reveal uses the same 300ms
   ease-out. The file's 600ms belong to a state change under the cursor,
   not to content travelling. Both values are custom properties on the
   root, so a consumer can retime its own slider without forking the
   component, and slider.js reads the duration from the same property
   instead of keeping a second copy of it. Recorded in
   designer-questions.md with the parallax's 80px and the header's 300ms.

   The other slider animation the .fig has is the arrow hover (600ms,
   cubic-bezier(0,0,0.58,1)), below. */

.c-slider {

	/* The slide change, in one place for CSS and for slider.js (which reads
	   `--c-slider-duration` off this element). Both are overridable per
	   consumer — see the ruling in the docblock above. */
	--c-slider-duration: 300ms;
	--c-slider-ease: cubic-bezier(0, 0, 0.58, 1);

	display: flex;
	flex-direction: column;

	/* Viewport → nav → dots. 24px is the .fig's own spacing in both
	   nodes that draw it: Behind The Scenes 4267:15954 (content 13011 →
	   nav 13035) and Scene Gallery 3327:12945 (photos 751 → dots 775). */
	gap: 24px;
}

.c-slider__viewport {
	position: relative;
	display: flex;
	flex-direction: column;

	/* Let the browser keep vertical panning while a horizontal drag is read as
	   a swipe; nothing here preventDefaults a scroll. */
	touch-action: pan-y;
}

.c-slider__track {

	/* The containing block for the slide that is leaving a one-per-view
	   slider (`data-podil-slider-leaving`, bottom of this file). */
	position: relative;
	display: flex;
	flex-direction: column;
}

.c-slider__slide {
	display: flex;
	flex-direction: column;
}

/* A class selector outranks base.css's `[hidden]`, so the slide that is not
   current has to be told again — this is what keeps the other slides out of
   the tab order and away from assistive tech. */
.c-slider__slide[hidden] {
	display: none;
}

.c-slider__figure {
	display: flex;
	flex-direction: column;
	gap: var(--c-slider-caption-gap, 20px);
	margin: 0;
}

.c-slider__caption {
	font-family: var(--font-body);
	font-size: var(--fs-m-text);
	font-weight: 400;
	line-height: var(--lh-m-text);
	letter-spacing: var(--ls-m-text);

	/* leadingTrim CAP_HEIGHT on the caption node (3126:3596 / 4255:14937). */
	text-box: trim-both cap alphabetic;
	color: var(--color-neutral-800);
}

.c-slider__nav {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.c-slider__counter {
	margin: 0;
	font-family: var(--font-body);
	font-size: var(--fs-s-text);
	font-weight: 400;
	line-height: var(--lh-s-text);
	letter-spacing: var(--ls-s-text);
	color: var(--color-neutral-800);
}

.c-slider__arrows {
	display: flex;

	/* 0 plus the -1px overlap below is how CSS writes the .fig's own
	   gap=-1 on this pair (4267:15996). */
	gap: 0;
}

.c-slider__arrow {
	display: flex;
	box-sizing: border-box;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	padding: 0;
	border: 0;
	background: var(--color-base-white);

	/* Figma "inside stroke" = inset box-shadow (global-constraints.md). */
	box-shadow: inset 0 0 0 1px var(--color-neutral-800);
	color: var(--color-neutral-800);
	cursor: pointer;

	/* The .fig's own auto-layout gap on the button frame; the visually
	   hidden label is out of flow, so the glyph stays centred. */
	gap: 10px;
	transition:
		box-shadow 600ms cubic-bezier(0, 0, 0.58, 1),
		color 600ms cubic-bezier(0, 0, 0.58, 1),
		background-color 600ms cubic-bezier(0, 0, 0.58, 1);
}

/* gap=-1 in the .fig's own arrow pair (4267:15996): the two buttons
   share one 1px stroke. */
.c-slider__arrow + .c-slider__arrow {
	margin-left: -1px;
}

.c-slider__arrow svg {
	display: block;
	width: 24px;
	height: 24px;
}

.c-slider__arrow:not([aria-disabled="true"]):hover {
	box-shadow: inset 0 0 0 1px var(--color-primary-600);
	color: var(--color-primary-600);
}

.c-slider__arrow[aria-disabled="true"] {
	box-shadow: inset 0 0 0 1px var(--color-neutral-400);
	color: var(--color-neutral-400);
	cursor: default;
}

.c-slider--dark .c-slider__arrow {
	background: transparent;
	box-shadow: inset 0 0 0 1px rgb(255 255 255);
	color: rgb(255 255 255);
}

.c-slider--dark .c-slider__arrow:not([aria-disabled="true"]):hover {
	background: rgb(255 255 255 / 20%);
	box-shadow: inset 0 0 0 1px rgb(255 255 255);
	color: rgb(255 255 255);
}

.c-slider--dark .c-slider__arrow[aria-disabled="true"] {
	box-shadow: inset 0 0 0 1px rgb(255 255 255 / 50%);
	color: rgb(255 255 255 / 50%);
}

.c-slider--dark .c-slider__counter {
	color: rgb(255 255 255);
}

/* 16×16 dots 18px apart. WCAG 2.2 2.5.8 is met through the spacing
   exception, not the size: 24px circles centred on neighbouring dots
   (34px apart) do not intersect. */
.c-slider__dots {
	display: flex;

	/* Hug width, centred — «Pagination Dots» 3327:12953 is a hug frame
	   centred in its section, not a full-width row. */
	align-self: center;
	gap: 18px;
}

/* ---- Options (ruling R18). Each one is a node in the file; see the docblock
   at the top of template-parts/slider.php for which. ---- */

/* `nav: 'edges'` — the two arrows at the left and right edges of the media,
   vertically centred: «Navigation Container» of «Що кажуть виконавці»
   3159:1964 and of the gallery 3327:12950 — 1392 wide inside a 1440 section,
   i.e. inset 24px, the pair spread `space-between`. */
.c-slider--nav-edges .c-slider__nav {
	position: absolute;
	z-index: 2;
	top: 50%;
	right: var(--c-slider-nav-inset, 24px);
	left: var(--c-slider-nav-inset, 24px);
	transform: translateY(-50%);
	pointer-events: none;
}

.c-slider--nav-edges .c-slider__arrows {
	display: contents;
}

.c-slider--nav-edges .c-slider__arrow,
.c-slider--nav-edges .c-slider__counter {
	pointer-events: auto;
}

.c-slider--nav-edges .c-slider__arrow + .c-slider__arrow {
	margin-left: 0;
}

/* The nav is absolute here, so the slider itself is the containing block and
   the viewport keeps the whole column height. */
.c-slider--nav-edges {
	position: relative;
}

/* `nav: 'heading'` — the template draws no arrows at all; the caller places
   them with `podil_slider_nav()`, as «За лаштунками» 3399:9584 does, beside
   its heading. This pair is a plain row wherever it lands. */
.c-slider__arrows--detached {
	display: flex;
	gap: 0;
}

/* `dots: 'overlay'` — centred over the media, 39px up from the bottom of the
   section in «Що кажуть виконавці» (3159:1997 at y 745 of an 800px
   frame). Consumers set their own offset without forking the component. */
.c-slider--dots-overlay {
	position: relative;
}

.c-slider--dots-overlay .c-slider__dots {
	position: absolute;
	z-index: 2;
	bottom: var(--c-slider-dots-offset, 24px);
	left: 50%;
	transform: translateX(-50%);
}

/* `counter: 'fraction-muted'` — the other counter the file uses, in the wide
   desktop rows: «1/20» in «Menu,button» 600 #697482 (3206:3682, «Враження»
   3199:3503), against `fraction`'s «S/S text» #272B30 (4267:15995). */
.c-slider--counter-fraction-muted .c-slider__counter {
	font-size: var(--fs-menu-button);
	font-weight: 600;
	line-height: var(--lh-menu-button);
	letter-spacing: var(--ls-menu-button);
	color: var(--color-neutral-500);
}

/* `per_view` > 1 — a track that moves one item per step instead of one slide
   shown at a time. The item width is the window divided by the count, minus
   the gaps it has to give back. */

/* `clip`, not `hidden`: `overflow: hidden` makes a scroll container, and a
   scroll container between a box and its scrollport silently stops the shared
   parallax's named view timeline (parallax.css, fix round 1 C2) — and a card
   inside a track slider is exactly where the macro asks for parallax
   («Parallax effect для карток» 4343:19688 / 4348:19860). `clip` cuts the same
   pixels and scrolls nothing, which is also what the slides outside the window
   need: they are `inert`, so nothing in them should ever be scrolled into
   view. */
.c-slider--track .c-slider__viewport {
	overflow: clip;
}

.c-slider--track .c-slider__track {
	--c-slider-index: 0;
	--c-slider-per-view: 1;
	--c-slider-gap: var(--c-slider-track-gap, 24px);
	--c-slider-gaps: calc((var(--c-slider-per-view) - 1) * var(--c-slider-gap));

	/* `peek: true` — px of the window the next item gets, gap included. The
	   fallback (not a declaration here) is what lets a consumer set it on the
	   slider root and have it reach this rule; 0 keeps every existing
	   consumer's item width unchanged. */
	--c-slider-item: calc((100% - var(--c-slider-gaps) - var(--c-slider-peek, 0px)) / var(--c-slider-per-view));
	--c-slider-step: calc(var(--c-slider-item) + var(--c-slider-gap));

	/* px the track is being dragged by right now; slider.js sets it inline
	   while a pointer is down and clears it on release, so the snap back to a
	   step is the same transition as a click on «Наступний». */
	--c-slider-drag: 0px;

	flex-direction: row;
	gap: var(--c-slider-gap);

	/* `translate` is taken: parallax.css uses it for the layer inside a card,
	   and the two compose only because they are different properties. */
	transform: translateX(calc(var(--c-slider-drag) - var(--c-slider-index) * var(--c-slider-step)));
	transition: transform var(--c-slider-duration) var(--c-slider-ease);
}

.c-slider--track .c-slider__slide {
	flex: 0 0 var(--c-slider-item);
	min-width: 0;
}

/* ---- Mouse: drag and horizontal wheel (client fix ПР-13) ---------------- */

/* The only affordance is a cursor, so it exists only where a pointer can show
   one — the 768 floor the theme's other hover-only affordances use.
   `data-podil-slider-draggable` is written by slider.js, and only while there
   is more than one step: at 1440 the person page's timeline shows every entry
   at once (person.css) and there is nothing to drag. */
@media (min-width: 768px) {

	[data-podil-slider-draggable="1"] .c-slider__viewport {
		cursor: grab;
	}
}

/* While a drag is on, the track follows the pointer — so it must not also be
   transitioning towards a step, and the press must not select a caption or
   drag a poster out of the page. The cursor is forced onto the descendants
   too: a card's own `cursor: pointer` would otherwise win under the hand that
   is holding the track. */
[data-podil-slider-dragging="1"] .c-slider__track {
	transition: none;
}

[data-podil-slider-dragging="1"] .c-slider__viewport,
[data-podil-slider-dragging="1"] .c-slider__viewport * {
	cursor: grabbing;
	user-select: none;
}

/* One slide in the window has no track to move: the others are `hidden`, and
   the gallery's neighbours deliberately hang off both edges of the frame
   («Left Photo» / «Right Photo» 4273:16077 / 4273:16076), so the window cannot
   be clipped to slide anything through it. The slide that is leaving therefore
   stays where it is, out of flow over the one that arrives, and dissolves.
   Out of flow is the point: the box the page — and every recorded spec-diff —
   measures stays the new slide's own, exactly as with an instant switch.
   slider.js adds the attribute after the switch, removes it when the animation
   is over, and never adds it at all with motion reduced. */
.c-slider__slide[data-podil-slider-leaving] {
	position: absolute;
	z-index: 1;
	top: 0;
	left: 0;
	width: 100%;
	animation: c-slider-leave var(--c-slider-duration) var(--c-slider-ease) both;
	pointer-events: none;
}

@keyframes c-slider-leave {

	from {
		opacity: 1;
	}

	to {
		opacity: 0;
	}
}

/* The focus ring of base.css is --color-primary-700, which is not guaranteed
   3:1 on a dark photo ground (WCAG 1.4.11). */
.c-slider--dark :focus-visible {
	outline-color: rgb(255 255 255);
}

.c-slider__dot {
	box-sizing: border-box;
	width: 16px;
	height: 16px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--color-neutral-500);
	cursor: pointer;
}

.c-slider__dot[aria-current="true"] {
	background: var(--color-primary-600);
	box-shadow: inset 0 0 0 2px var(--color-neutral-200);
}

.c-slider--dark .c-slider__dot {
	background: rgb(255 255 255);
}

.c-slider--dark .c-slider__dot[aria-current="true"] {

	/* On a dark ground the .fig's own #12AD99 passes (5.0:1) — the same
	   split designer-questions.md records for the footer hover. */
	background: var(--color-primary-500);
	box-shadow: inset 0 0 0 2px rgb(255 255 255);
}

@media (min-width: 768px) {

	.c-slider__arrow {
		width: 64px;
		height: 64px;
	}
}

@media (min-width: 1920px) {

	.c-slider__arrow {
		width: 84px;
		height: 84px;
	}
}

/* Windows High Contrast / `forced-colors: active`. Chromium drops author
   `box-shadow` entirely, and every edge this component has is exactly that:
   the arrows' 1px inside stroke and the active dot's 2px inner ring are
   `box-shadow: inset`, the project's convention for a Figma inside stroke,
   and the dots themselves are a `background` and nothing else. Without this
   block the arrows disappear over a dark photo (`nav: 'edges'`, the dark
   variant) and every dot looks the same, so «which slide am I on» is gone.

   `outline`, not `border`, for the same reason base.css gives: outline is
   outside the box model, so it cannot grow a 40/64/84px button or a 16px dot
   that spec-diff measures, and a negative `outline-offset` puts it exactly
   where the inside stroke was. Colours are the forced-colors system keywords,
   which Chromium still honours on `outline-color`. The glyph needs nothing:
   it is `currentColor`, so it follows the forced text colour on its own. */
@media (forced-colors: active) {

	.c-slider__arrow,
	.c-slider__dot {
		outline: 1px solid CanvasText;
		outline-offset: -1px;
	}

	/* The .fig's Inactive arrow is dimmer, not edgeless — GrayText is
	   forced-colors' own disabled colour, the same substitution base.css
	   makes for the disabled ticket button. `:not(:focus-visible)` keeps this
	   higher-specificity `outline-color` from outliving the focus ring: see
	   the cascade note in base.css. */
	.c-slider__arrow[aria-disabled="true"]:not(:focus-visible) {
		outline-color: GrayText;
	}

	/* The current slide's dot has to stay the odd one out once its fill and
	   its light ring are both flattened. Filled Highlight against the others'
	   Canvas-with-an-edge is the same read as the design's teal-against-grey:
	   the difference is shape, not hue. */
	.c-slider__dot[aria-current="true"]:not(:focus-visible) {
		background: Highlight;
		outline-color: Highlight;
	}
}
