/**
 * Eruda Toolkit - Scroll Rail
 *
 * A row of linked cards that travels sideways while the section is pinned, so
 * scrolling down reads the row left to right.
 *
 * The same rule as everything else here: if the script never runs, the section
 * must still be complete and usable. Without it this is an ordinary
 * horizontally scrollable row with snap points -- which is also exactly what
 * it becomes on a narrow screen and under reduced motion, because a pinned
 * rail is worse than a swipe on a phone.
 */

/*
 * Every theme worth the name sets this, and the widget cannot be built on the
 * assumption that this one did. Without it the gutter that pulls the scroller
 * to the screen edges is added to its width instead of taken out of it, and
 * the page gains a sideways scroll of exactly two gutters.
 */
.erail,
.erail *,
.erail *::before,
.erail *::after {
	box-sizing: border-box;
}

.erail {
	position: relative;
}

/*
 * The stage is what pins. Its height is the panel; the runway that drives it
 * is the extra height the script puts on .erail itself.
 */
/*
 * No height of its own by default. The stage is as tall as the cards make it,
 * plus whatever breathing room is asked for -- a fixed height in vh is a
 * setting, not the starting point, because a section sized in screen-heights
 * has no idea how tall a card is and leaves dead space above and below it.
 */
.erail__stage {
	position: relative;
	height: var(--erail-height, auto);
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/*
 * Only the pinned mode sticks, and only the pinned mode is handed extra page
 * height to stick for. In flow the section is exactly as tall as its row and
 * everything after it sits where it would have anyway.
 *
 * The offset that centres it is set by the script, from the height the stage
 * turns out to be. It cannot be a calc here: the stage's height is usually
 * `auto`, and there is no arithmetic to be done on that.
 */
.erail[data-erail-mode="pinned"] .erail__stage {
	position: sticky;
	top: 0;
}

/*
 * The two elements the script inserts when it holds a whole section: a wrapper
 * around that section, which is what bounds the hold, and the spacer inside it
 * that the hold is spent against. Declared here so a theme's own layout rules
 * cannot give either of them a margin, a border or a background.
 */
.erail__pin {
	display: block;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
}

.erail__spacer {
	display: block;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	pointer-events: none;
}

/*
 * When a whole section is being held instead, that section is the sticky one
 * and the stage must not be: two nested sticky elements each stick against
 * their own containing block, and the inner one would slide inside the outer
 * for the length of the hold.
 */
.erail[data-erail-host] .erail__stage {
	position: relative;
	top: auto;
}

.erail__viewport {
	width: 100%;
	/* Until the script takes over this is a real scroller, so the row is
	   usable with a trackpad, a touch screen or a scrollbar. */
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
}

.erail__viewport::-webkit-scrollbar {
	display: none;
}

/*
 * Faded ends.
 *
 * A row that travels sideways has to stop somewhere, and a hard vertical edge
 * where a card meets the end of the scroller reads as a card that has been cut
 * in half rather than as one on its way out. Fading the two ends lets a card
 * leave the frame the way it arrived.
 *
 * A mask, not two gradient overlays. An overlay has to be painted in the
 * section's own background colour, which stops being true the moment the
 * section sits on a picture, a gradient or anything else; and it would have to
 * sit above the cards, where it would swallow the hover and the link on
 * whichever card was under it.
 *
 * Only the ends fade. The mask runs the full height, so the vertical room that
 * a card's shadow and its hover lift live in is untouched.
 *
 * And only an end that has something past it. Before the row sets off there
 * is nothing to the left of the first card, so a fade there just greys out
 * the card people read first. The script eases each end in as cards travel
 * past it (--erail-fade-l, --erail-fade-r: 0 to 1); without the script the
 * row starts at its left edge, so that is the default.
 */
.erail[data-erail-fade] .erail__viewport {
	-webkit-mask-image: linear-gradient(
		to right,
		transparent 0,
		#000 calc(var(--erail-fade, 96px) * var(--erail-fade-l, 0)),
		#000 calc(100% - var(--erail-fade, 96px) * var(--erail-fade-r, 1)),
		transparent 100%
	);
	mask-image: linear-gradient(
		to right,
		transparent 0,
		#000 calc(var(--erail-fade, 96px) * var(--erail-fade-l, 0)),
		#000 calc(100% - var(--erail-fade, 96px) * var(--erail-fade-r, 1)),
		transparent 100%
	);
}

/* Once the script is driving, the row is moved rather than scrolled. */
.erail[data-erail-ready] .erail__viewport {
	overflow: hidden;
	scroll-snap-type: none;
}

.erail__track {
	display: flex;
	align-items: stretch;
	gap: var(--erail-gap, 28px);
	/* The vertical padding is what a card's shadow and its hover lift need in
	   order not to be clipped by the viewport's overflow. */
	padding: var(--erail-pad-y, 24px) var(--erail-lead, 0px);
	width: max-content;
}

/* Only while the script is moving it. A compositing layer costs memory
   whether anything is moving on it or not, and on a phone the row is scrolled
   rather than transformed. */
.erail[data-erail-ready] .erail__track {
	will-change: transform;
}

/* ------------------------------------------------------------- the card --- */

.erail__card {
	position: relative;
	display: block;
	flex: 0 0 auto;
	width: var(--erail-card, 420px);
	aspect-ratio: var(--erail-ratio, 0.81);
	border-radius: var(--erail-radius, 20px);
	border: var(--erail-border-w, 1px) solid var(--erail-border, rgba(255, 255, 255, 0.1));
	background: var(--erail-card-bg, #0c1116);
	overflow: hidden;
	scroll-snap-align: center;
	text-decoration: none;
	color: inherit;
	isolation: isolate;
	transition:
		transform var(--erail-hover-ms, 500ms) cubic-bezier(0.16, 1, 0.3, 1),
		border-color var(--erail-hover-ms, 500ms) ease,
		box-shadow var(--erail-hover-ms, 500ms) ease;
}

/* A card that is not a link is still a card; it just does not pretend. */
.erail__card:not([href]) {
	cursor: default;
}

.erail__media {
	position: absolute;
	inset: 0;
	overflow: hidden;
	z-index: 0;
}

/*
 * Cover, always, and forced for the same reason as the Scroll Story panel:
 * nearly every theme ships `img { height: auto }` at a specificity a plugin
 * stylesheet cannot beat, and the result is the card's background showing
 * through as a band.
 */
.erail .erail__img {
	display: block;
	position: absolute;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	min-width: 100%;
	min-height: 100%;
	max-width: none;
	max-height: none;
	object-fit: cover !important;
	object-position: var(--erail-obj-pos, 50% 50%) !important;
	filter: grayscale(var(--erail-grey, 0.85)) brightness(var(--erail-bright, 0.9));
	transform: scale(1);
	transition:
		transform var(--erail-hover-ms, 500ms) cubic-bezier(0.16, 1, 0.3, 1),
		filter var(--erail-hover-ms, 500ms) ease;
}

/*
 * The scrim. Two stops rather than one: a long, almost-nothing wash over the
 * top half so the picture sits back, then the real darkening under the words.
 * A single gradient dark enough to read against would flatten the whole
 * picture.
 */
.erail__scrim {
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		to bottom,
		transparent 0%,
		color-mix(in srgb, var(--erail-scrim, #0c1116) 18%, transparent) 42%,
		color-mix(in srgb, var(--erail-scrim, #0c1116) 82%, transparent) 72%,
		var(--erail-scrim, #0c1116) 100%
	);
}

/* color-mix is recent. Without it the card still gets a readable scrim. */
@supports not (background: color-mix(in srgb, #000 50%, transparent)) {
	.erail__scrim {
		background: linear-gradient(to bottom, transparent 30%, var(--erail-scrim, #0c1116) 100%);
	}
}

.erail__text {
	position: absolute;
	inset: auto 0 0 0;
	z-index: 2;
	padding: var(--erail-text-pad, 32px);
}

.erail__title {
	margin: 0 0 0.45em;
	color: var(--erail-title, #ffffff);
	font-size: var(--erail-title-size, 2rem);
	font-weight: 800;
	line-height: 1;
	letter-spacing: 0.005em;
	text-transform: uppercase;
	text-wrap: balance;
}

.erail__copy {
	margin: 0;
	color: var(--erail-copy, #c3ccd6);
	font-size: var(--erail-copy-size, 1rem);
	line-height: 1.45;
}

/* ---------------------------------------------------------- the cue --- */

/*
 * The thing that says "this opens something".
 *
 * It is visible before you touch the card, not only on hover: a hover-only
 * affordance tells you a card is clickable exactly when you have already
 * guessed. So it sits there quietly at a low opacity, and blooms -- fills in,
 * grows, and the arrow travels the way it is pointing -- when the card is
 * hovered or focused.
 */
.erail__cue {
	position: absolute;
	top: var(--erail-cue-inset, 20px);
	right: var(--erail-cue-inset, 20px);
	z-index: 3;
	display: grid;
	place-items: center;
	width: var(--erail-cue-size, 44px);
	height: var(--erail-cue-size, 44px);
	border-radius: 50%;
	border: 1px solid var(--erail-cue-border, rgba(255, 255, 255, 0.45));
	background: var(--erail-cue-bg, rgba(12, 17, 22, 0.35));
	color: var(--erail-cue-fg, #ffffff);
	opacity: var(--erail-cue-idle, 0.55);
	transform: scale(0.92);
	pointer-events: none;
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	transition:
		opacity var(--erail-hover-ms, 500ms) ease,
		transform var(--erail-hover-ms, 500ms) cubic-bezier(0.16, 1, 0.3, 1),
		background-color var(--erail-hover-ms, 500ms) ease,
		border-color var(--erail-hover-ms, 500ms) ease,
		color var(--erail-hover-ms, 500ms) ease;
}

.erail__cue[data-erail-cue="left"] {
	right: auto;
	left: var(--erail-cue-inset, 20px);
}

.erail__cue svg {
	width: 45%;
	height: 45%;
	display: block;
	transition: transform var(--erail-hover-ms, 500ms) cubic-bezier(0.16, 1, 0.3, 1);
}

/* ------------------------------------------------------------- hover --- */

.erail__card[href]:hover,
.erail__card[href]:focus-visible {
	transform: translateY(calc(var(--erail-lift, 8px) * -1));
	border-color: var(--erail-border-hover, rgba(255, 255, 255, 0.28));
	box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.75);
}

.erail__card[href]:hover .erail__img,
.erail__card[href]:focus-visible .erail__img {
	transform: scale(1.05);
	filter: grayscale(var(--erail-grey-hover, 0)) brightness(var(--erail-bright-hover, 1));
}

.erail__card[href]:hover .erail__cue,
.erail__card[href]:focus-visible .erail__cue {
	opacity: 1;
	transform: scale(1);
	background: var(--erail-cue-bg-hover, #ffffff);
	border-color: var(--erail-cue-bg-hover, #ffffff);
	color: var(--erail-cue-fg-hover, #0c1116);
}

.erail__card[href]:hover .erail__cue svg,
.erail__card[href]:focus-visible .erail__cue svg {
	transform: translate(2px, -2px);
}

/* The arrow that points straight right has nowhere to go but right. */
.erail__cue[data-erail-icon="right"] svg {
	transform: translate(0, 0);
}

.erail__card[href]:hover .erail__cue[data-erail-icon="right"] svg,
.erail__card[href]:focus-visible .erail__cue[data-erail-icon="right"] svg {
	transform: translate(3px, 0);
}

.erail__card[href]:focus-visible {
	outline: 2px solid var(--erail-focus, #ffffff);
	outline-offset: 3px;
}

/* --------------------------------------------------------- progress --- */

.erail__foot {
	display: flex;
	align-items: center;
	gap: var(--erail-bar-gap, 28px);
	margin-top: var(--erail-bar-gap, 28px);
}

.erail__progress {
	position: relative;
	flex: 1 1 auto;
	height: var(--erail-bar-h, 2px);
	background: var(--erail-bar-track, rgba(255, 255, 255, 0.12));
	border-radius: 999px;
	overflow: hidden;
}

.erail__progress span {
	position: absolute;
	inset: 0 auto 0 0;
	width: 100%;
	border-radius: inherit;
	background: var(--erail-bar-fill, rgba(255, 255, 255, 0.75));
	transform: scaleX(0);
	transform-origin: 0 50%;
}

/*
 * How far through the row you are, in words. A bar says "some of the way";
 * a count says how much is left, which is what decides whether anyone keeps
 * swiping.
 */
.erail__count {
	flex: 0 0 auto;
	color: var(--erail-count, rgba(255, 255, 255, 0.6));
	font-size: var(--erail-count-size, 0.8125rem);
	line-height: 1;
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1;
	white-space: nowrap;
}

.erail__count b {
	font-weight: inherit;
	color: var(--erail-count-now, #ffffff);
}

/*
 * Previous / next. Restated in full for every state, because themes paint
 * buttons (Hello Elementor makes them pink on hover).
 */
.erail__arrows {
	display: flex;
	flex: 0 0 auto;
	gap: 10px;
}

.erail .erail__arrow,
.erail .erail__arrow:hover,
.erail .erail__arrow:focus {
	display: inline-grid;
	place-items: center;
	width: var(--erail-arrow-size, 46px);
	height: var(--erail-arrow-size, 46px);
	margin: 0;
	padding: 0;
	border: 1px solid var(--erail-arrow-line, rgba(255, 255, 255, 0.35));
	border-radius: 50%;
	background: var(--erail-arrow-bg, transparent);
	box-shadow: none;
	color: var(--erail-arrow, #ffffff);
	cursor: pointer;
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, opacity 0.2s ease;
}

.erail .erail__arrow:hover:not(:disabled) {
	border-color: var(--erail-arrow-hover-bg, #ffffff);
	background: var(--erail-arrow-hover-bg, #ffffff);
	color: var(--erail-arrow-hover, #0F3961);
}

.erail .erail__arrow:focus-visible {
	outline: 2px solid var(--erail-arrow, #ffffff);
	outline-offset: 3px;
}

.erail .erail__arrow:disabled {
	opacity: 0.35;
	cursor: default;
}

.erail__arrow svg {
	width: 20px;
	height: 20px;
}

/* ----------------------------------------------------------- narrow --- */

/*
 * Nothing pins below this width. A pinned rail on a phone takes a gesture
 * people already know -- swipe the row -- and replaces it with one they have
 * to discover, on the axis their thumb is worst at.
 */
@media (max-width: 1024px) {
	.erail,
	.erail[data-erail-ready] {
		height: auto !important;
	}

	.erail__stage {
		position: static;
		height: auto;
	}

	.erail[data-erail-ready] .erail__viewport {
		overflow-x: auto;
		scroll-snap-type: x mandatory;
	}

	/*
	 * Edge to edge, with the first card on the same line as the heading.
	 *
	 * A scroller boxed inside the section's padding clips the next card at
	 * that padding, so the peek that tells a reader there is more looks like a
	 * card that has been cut off. Pulling the scroller out to the full width
	 * and putting the gutter back as its own padding gives both: the row
	 * starts where the words start, and the card after it runs off the screen
	 * rather than off a container.
	 */
	.erail[data-erail-bleed] .erail__viewport {
		/* Not 100%. A declared width is not changed by a margin, so with one
		   the negative margins below only slide the scroller sideways instead
		   of widening it, and it stays boxed while drifting left. */
		width: auto;
		margin-left: calc(50% - 50vw);
		margin-right: calc(50% - 50vw);
		padding-left: var(--erail-gutter, 20px);
		padding-right: var(--erail-gutter, 20px);
		/* Snapping without this puts a card's edge against the screen edge,
		   underneath the gutter it was lined up with. */
		scroll-padding-left: var(--erail-gutter, 20px);
	}

	.erail__track {
		transform: none !important;
		padding-left: 0;
		padding-right: 0;
	}

	.erail__card {
		width: var(--erail-card-mobile, 78vw);
		/* Start, not centre: a centred card sits with half a card showing on
		   both sides, which reads as two things half-finished rather than one
		   thing and a hint of the next. */
		scroll-snap-align: start;
	}

	.erail__foot {
		margin-top: var(--erail-bar-gap-mobile, 20px);
		gap: var(--erail-bar-gap-mobile, 20px);
	}
}

/* ------------------------------------------------------------- grid --- */

/*
 * Grid: the same cards, laid out in rows instead of travelling. Nothing here
 * is driven by the script, which leaves a grid alone, so the row stops being
 * a scroller and the cards take their width from the column instead of from
 * --erail-card. These selectors outrank the narrow-screen rules above, which
 * is what keeps a phone from turning the grid back into a swipe row.
 */
.erail[data-erail-mode="grid"] .erail__viewport {
	overflow: visible;
	scroll-snap-type: none;
	/* The render leaves the fade and the bleed off a grid; these hold even
	   if the attributes are put back by hand. */
	width: 100%;
	margin: 0;
	padding: 0;
	-webkit-mask-image: none;
	mask-image: none;
}

.erail[data-erail-mode="grid"] .erail__track {
	display: grid;
	grid-template-columns: repeat(var(--erail-cols, 3), minmax(0, 1fr));
	width: auto;
	padding: 0;
	transform: none !important;
}

.erail[data-erail-mode="grid"] .erail__card {
	width: auto;
	min-width: 0;
}

@media (prefers-reduced-motion: reduce) {
	.erail,
	.erail[data-erail-ready] {
		height: auto !important;
	}

	.erail__stage {
		position: static;
		height: auto;
	}

	.erail[data-erail-ready] .erail__viewport {
		overflow-x: auto;
		scroll-snap-type: x mandatory;
	}

	.erail__track {
		transform: none !important;
	}

	.erail__card,
	.erail__img,
	.erail__cue,
	.erail__cue svg {
		transition: none;
	}

	/* The cue stops being a flourish and is simply always there. */
	.erail__cue {
		opacity: 1;
		transform: none;
	}

	.erail__progress {
		display: none;
	}
}
