/**
 * GEEKS Products Carousel.
 *
 * One number decides the geometry: how many are across. A place is one N-th of
 * the stage, the rail moves by whole places, and the gap is padding INSIDE a
 * place — so a place is always exactly one N-th whatever the gap says, and
 * nothing can be pushed out of the frame by a setting that disagrees with
 * another one.
 *
 * Being in the middle or not is a STATE, not a distance: the size, the fading
 * and the filter are one value each, the same for every product that is not in
 * the middle. Only two things vary with distance — where a product sits along
 * the rail, and the arc.
 *
 * @package Geeks
 */

.geeks-prc {
	/* Every resting value in one place. The Style controls overwrite these; the
	 * fallbacks are what the widget looks like untouched. Colours come from the
	 * site's own palette rather than from any particular design. */
	--prc-h: 460px;
	--prc-off-size: .6;
	--prc-off-fade: .35;
	--prc-move: .45s;

	position: relative;
	width: 100%;
	transition: opacity .3s;
}

/* Held until the script has measured and placed everything, and the pictures
 * that will be on screen have arrived.
 *
 * The WHOLE widget, not the frame alone. The categories and the arrows are
 * ordinary markup that needs nothing from the script, so hiding only the frame
 * put a row of buttons and two arrows on the page around an empty space, and
 * the products appeared under them afterwards. It is one thing, so it arrives
 * as one thing.
 *
 * The animation lifts it after three seconds by itself: if the script never
 * arrives — a bad deploy, a blocked file — a visible row of products is a far
 * better failure than an empty space. The script's own cap is shorter, so this
 * is only ever reached when there is no script at all. */
.geeks-prc.is-waiting {
	opacity: 0;
	animation: geeks-prc-rescue .3s ease 3s forwards;
}

@keyframes geeks-prc-rescue {
	to { opacity: 1; }
}

/* The first placement is not a movement, so it must not be animated.
 *
 * The rail starts at nothing and the script moves it to the middle. With a
 * transition on that, the carousel slides into position — and because the fade
 * in is shorter than the slide, you watch it arrive. Nothing here transitions
 * until the script has placed everything and given the browser a frame to paint
 * it. */
.geeks-prc.is-waiting .geeks-prc-rail,
.geeks-prc.is-waiting .geeks-prc-slot,
.geeks-prc.is-waiting .geeks-prc-media,
.geeks-prc.is-waiting .geeks-prc-shot,
.geeks-prc.is-waiting .geeks-prc-logo {
	transition: none !important;
}

/* ------------------------------------------------------------------ filter */

/* The categories are a track with one mark on it.
 *
 * The row itself is the track — a background, a radius and a padding of its
 * own — and the chosen category is shown by a single mark that MOVES along it
 * rather than by each button carrying its own background. One thing sliding
 * reads as a place being chosen; two backgrounds swapping reads as two things
 * blinking. */
.geeks-prc-filter {
	position: relative;
	display: inline-flex;
	flex-wrap: nowrap;
	align-items: center;
	justify-content: center;
	gap: var(--prc-pill-gap, 6px);
	margin-bottom: 24px;
	padding: var(--prc-track-pad, 6px);
	border-radius: var(--prc-track-radius, 999px);
	background: var(--prc-track-bg, transparent);
	max-width: 100%;
	/* Only as wide as the categories in it. The row is one box now, so where it
	   sits is where the BOX sits — a stretched track with the buttons floating
	   in the middle of it is not a row of categories, it is a bar. */
	/* Across the widget, which in a grid is the INLINE axis — align-self would
	   now be asking about the other one. The control's own values are unchanged
	   and mean the same thing here, so nothing saved has to be rewritten. */
	justify-self: var(--prc-track-self, center);
}

/* The mark. Placed by the script, which measures the chosen button — there is
   no way to say "as wide as that one over there" in a stylesheet. */
.geeks-prc-mark {
	position: absolute;
	top: var(--prc-mark-top, 0px);
	left: 0;
	width: 0;
	height: 0;
	border-radius: var(--prc-mark-radius, 999px);
	background: var(--prc-mark-bg, var(--e-global-color-accent, #2f3437));
	transform: translateX(var(--prc-mark-x, 0px));
	transition: transform var(--prc-mark-move, .35s) cubic-bezier(.22, .61, .36, 1),
		width var(--prc-mark-move, .35s) cubic-bezier(.22, .61, .36, 1),
		opacity .2s;
	pointer-events: none;
}

/* Until the script has measured, there is nothing to show. */
.geeks-prc-filter:not(.is-marked) .geeks-prc-mark {
	opacity: 0;
}

.geeks-prc-pill {
	position: relative;
	z-index: 1;
	flex: 0 0 auto;
	padding: .55rem 1.4rem;
	border: 0;
	border-radius: 999px;
	background: var(--prc-pill-bg, transparent);
	color: var(--prc-pill-col, inherit);
	font: inherit;
	line-height: 1.2;
	cursor: pointer;
	transition: background-color .2s, color .2s;
	user-select: none;
	-webkit-user-select: none;
}

/* Hover only where there is something that can hover.
 *
 * A touch screen leaves the last thing tapped in :hover until something else is
 * tapped, so a tapped arrow keeps its hover colours for as long as the reader
 * looks at it. A media query rather than an extra class, so the specificity does
 * not move and nothing that used to win a tie stops winning. Focus is kept
 * outside it: a keyboard needs to see where it is on any device. */
@media (hover: hover) {
	.geeks-prc-pill:hover {
		background: var(--prc-pill-bg-h, var(--prc-pill-bg, transparent));
		color: var(--prc-pill-col-h, var(--prc-pill-col, inherit));
	}

	.geeks-prc-arrow:hover {
		transform: scale(1.08);
	}

	.geeks-prc-var:hover {
		opacity: 1;
	}

	.geeks-prc-link:hover {
		background: var(--prc-social-bg-h, var(--prc-social-bg, transparent));
		/* The resting colour first, the kit's accent only if neither was set.
		 * Straight to the accent meant an author who set white icons and left
		 * hover empty watched their choice thrown away the moment the pointer
		 * arrived — while a widget nobody has styled still lights up. */
		color: var(--prc-social-col-h, var(--prc-social-col, var(--e-global-color-accent, inherit)));
	}
}

.geeks-prc-pill:focus-visible {
	background: var(--prc-pill-bg-h, var(--prc-pill-bg, transparent));
	color: var(--prc-pill-col-h, var(--prc-pill-col, inherit));
}

/* The chosen one takes a colour, not a background: the background is the mark,
 * and the mark belongs to the row.
 *
 * One class deeper than it looks like it needs to be: a Style control that sets
 * the resting colour writes a rule of exactly the weight a plain
 * `.geeks-prc-pill.is-on` would have, and it lands later in the cascade — so the
 * chosen category would quietly lose its colour to the unchosen ones. */
.geeks-prc .geeks-prc-pill.is-on {
	/* And no background of its own, whatever the Normal tab was set to.
	 *
	 * The buttons sit above the mark — they are z-index 1, the mark is not — so
	 * any opaque colour set for the resting state is painted over the mark by
	 * the one button the mark is behind. The mark went on sliding, invisibly.
	 * The Active tab was denied a background for exactly this reason; this is
	 * the Normal one being kept out of the same place. It outweighs the hover
	 * and focus rules above on both count and order, so those need no
	 * exception of their own. */
	background: transparent;
	color: var(--prc-pill-col-on, #fff);
}

/* ------------------------------------------------------------------- stage */

/* The frame. It has a definite height, it clips, and it is a stacking context
 * so the products' own layering stays inside it and can never climb over the
 * arrows the way it did in the last one. */
.geeks-prc-stage {
	position: relative;
	z-index: 0;
	/* Its own width, stated.
	 *
	 * Swiper centres its container with `margin-left: auto; margin-right: auto`,
	 * which is harmless in ordinary flow — and fatal in a flex column, where an
	 * auto cross-axis margin cancels the stretch and leaves the frame to size
	 * itself from content it has none of. It collapses to nothing, Swiper
	 * measures nothing, and every slide is nothing wide: the arrows show and
	 * the carousel does not. Putting the arrows in a row of their own is
	 * exactly what makes this widget a flex column. */
	width: 100%;
	overflow: hidden;
	height: var(--prc-h);
	/* Nothing inside the frame is text to select or a thing to pick up — it is
	 * all surface to pull the carousel by. Set on the frame rather than on the
	 * pictures, so the gaps between them behave the same way. */
	user-select: none;
	-webkit-user-select: none;
}

/* The only thing that moves — and Swiper is what moves it, transition
 * included. Nothing about the rail's transition may be written here; see the
 * frame's fade above for what happens when it is. */
.geeks-prc-rail {
	/* Held against the start of the frame. With no curve the slides fill the
	 * frame and this cannot be seen; with one, the slide is shorter by the
	 * depth of the curve and the margin below decides where that room goes. */
	align-items: center;
	height: 100%;
}

/* --------------------------------------------------------------- the places */

.geeks-prc-slot {
	/* No width, no height, no padding: Swiper sizes the slide and puts the gap
	 * between slides, taking it out of the container before dividing what is
	 * left. That is the formula this widget was reinventing badly — with the gap
	 * as padding, the space came out of the picture and left a half-gap at both
	 * outer edges.
	 *
	 * What is still ours is the arc, which is a transform on the slide because it
	 * is a function of that slide's distance from the middle. */
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	/* Swiper writes the size that varies — the width across, the height down —
	 * as an inline style on each slide, so this only fills the other axis.
	 *
	 * Less the depth of the curve, because the frame clips and a slide pushed
	 * down by the arc would simply have its bottom cut off — which reads as the
	 * products being different heights, when they are the same height and one
	 * of them is behind the edge. The curve is given its room out of the frame
	 * the carousel was told to be. Every slide is the full height of the frame
	 * and they are all the same height as each other, whatever else is on. The
	 * arc does not touch this: a setting about where a product sits has no
	 * business changing how big it is. */
	height: 100%;
}

/* ---------------------------------------------------------------- the media */

.geeks-prc-media {
	position: relative;
	flex: 0 1 auto;
	min-height: 0;
	/* The slide is the picture's box. Swiper has already taken the gaps out of
	 * the carousel and divided what was left, so there is no second box to size
	 * here — filling the slide is the whole of it. */
	width: 100%;
	height: 100%;
	/* How big this slide's picture is, as one formula for both scale modes.
	 * --prc-dn is how far out the slide counts as: 1 for every inactive slide
	 * when they are all the same size, its real distance when they shrink with
	 * it, 0 for the middle one either way.
	 *
	 * A NUMBER here rather than a transform, because the box must not be the
	 * thing that scales. A transform on this box is inherited by everything
	 * inside it, and the three layers in here are not the same kind of thing:
	 * the picture and the turntable have to scale as one or they would drift
	 * apart, while the mark has nothing to line up with and is the stand-in for
	 * the SMALL state — being carried up to full size by a box growing beneath
	 * it is the one thing it must never do. Each layer takes this number and
	 * decides for itself. */
	/* How big this product is drawn, as a share of the box it is in: 1 in the
	 * middle, and in the wings whatever share fits it inside the size asked for
	 * there. One number, so the product keeps its own proportions either way. */
	--prc-fit: calc(1 - (1 - var(--prc-off-size, .6)) * var(--prc-dn, 1));
	/* The fading is flat: being in the middle or not is a state, not a distance. */
	opacity: var(--prc-off-fade);
	transition: opacity var(--prc-move), filter var(--prc-move);
}

.geeks-prc-slot.is-centre .geeks-prc-media {
	opacity: 1;
	filter: none;
}

/* The two rows are placed against THIS box, so it must not clip them — a corner
 * radius is put on the pictures themselves instead of on the box around them.
 *
 * No margin anywhere in here: how far a row sits from the picture is part of
 * where it is placed, and eleven placements each cancelling a margin is a trap
 * rather than a default. */
.geeks-prc-vars {
	position: absolute;
	top: calc(100% + var(--prc-vars-top, 12px));
	left: 0;
	right: 0;
}

.geeks-prc-social {
	position: absolute;
	top: calc(100% + var(--prc-social-top, 64px));
	left: 0;
	right: 0;
}

/* The three picture layers, named rather than "every child of the media".
 *
 * They used to be the only children, so `> *` was harmless — until the two
 * detail rows moved inside this box and quietly inherited `height: 100%` from
 * it. Elementor's anchors override top, bottom, left, right and width, but they
 * never set a height, so nothing took that back and the rows were stretched to
 * the full box with their buttons centred inside it.
 *
 * One class deeper than it looks like it needs to be, and that part is not
 * optional either: Elementor ships `.elementor img { height: auto }`, which
 * carries a class AND an element. Under it a picture ignores its box and draws
 * itself at its natural height — a 333×1000 bottle at 320px wide is 961px tall
 * — and the box clips the rest off. */
.geeks-prc .geeks-prc-logo,
.geeks-prc .geeks-prc-shot,
.geeks-prc .geeks-prc-spin {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: contain;
	/* A picture is something to drag the carousel BY, not something to drag. */
	-webkit-user-drag: none;
	user-select: none;
	-webkit-user-select: none;
}

/* Three layers, one visible at a time: the mark in the wings, the picture once
 * it is the middle one, and the turntable once enough frames have arrived. A
 * slow connection degrades to the picture rather than to a hole.
 *
 * Each carries its own scale, from the one number the box works out. The
 * picture and the turntable take it as it comes, which is what keeps them
 * registered on each other. */
.geeks-prc-shot,
.geeks-prc-spin,
.geeks-prc-logo {
	/* The curve moves the picture, not the slide.
	 *
	 * The slide is the full height of the frame and stays that way, so there is
	 * nothing here that can change how tall an item is or push one past an edge
	 * to be cut. The room the curve travels in is the room the shrinking has
	 * already made: an inactive product is drawn smaller than its slide, and
	 * what is left over is exactly what it moves within. The middle one is not
	 * moved at all, which is why its having no room to spare does not matter. */
	transform: scale(var(--prc-fit, 1));
}

/* The transform eases like everything else, EXCEPT while the script is feeding
 * it a new position every frame — then it must take each one as it comes, or
 * every frame would set off a fresh quarter-second ease and the arc would drag
 * a long way behind the products it belongs to. */
.geeks-prc-shot { opacity: 0; transition: opacity var(--prc-move), transform var(--prc-follow, var(--prc-move)); }
.geeks-prc-spin { opacity: 0; transition: opacity var(--prc-move), transform var(--prc-follow, var(--prc-move)); }
.geeks-prc-logo { opacity: 1; transition: opacity var(--prc-move), transform var(--prc-follow, var(--prc-move)); }

.geeks-prc.is-following {
	--prc-follow: 0s;
}
.geeks-prc-slot.is-centre .geeks-prc-shot { opacity: 1; }

/* The mark on the middle slide: the size it stands for, and gone quickly.
 *
 * The picture grows to full size here and the mark does not follow it — it
 * holds the inactive size while it fades, which is the size it means. Sizing
 * itself rather than being sized is the whole point of the layers owning their
 * own scale: the two want opposite things at exactly this moment.
 *
 * The fade is short, and short only in this direction. A transition belongs to
 * the state being entered, so the one written here is used on the way IN to
 * the middle. Leaving is the rule above at full length: there the slide is
 * shrinking, and the mark should arrive as it reaches the size it is for. */
.geeks-prc-slot.is-centre .geeks-prc-logo,
.geeks-prc-slot.is-mid .geeks-prc-logo {
	transform: scale(var(--prc-off-size, .6));
	transition: opacity calc(var(--prc-move) * .4), transform var(--prc-follow, var(--prc-move));
}

/* Being in the middle is what stops the mark growing; being NAMED the middle
 * one is what makes it go. They are the same instant on an ordinary move and
 * a long way apart during a glide, where nothing is named until the carousel
 * comes to rest — and for all of that time products pass through the middle
 * with the size, but not the meaning, of the active one. */
.geeks-prc-slot.is-centre .geeks-prc-logo {
	opacity: 0;
}
.geeks-prc-slot.is-centre.is-spinning .geeks-prc-shot { opacity: 0; }
.geeks-prc-slot.is-centre.is-spinning .geeks-prc-spin { opacity: 1; }

/* ------------------------------------------------------------------ detail */

/* The two rows belong to the product, so they live in the slide — but only the
 * one in the middle offers them: buttons under a faded logo in the wings would
 * change something the reader cannot see.
 *
 * Each places itself: in the flow below or above the picture, which is where
 * they start and where the picture shrinks to make room for them; or pinned to
 * one of nine anchors on the slide, out of the flow. The slide and not the
 * picture, so they do not move every time the picture is resized. */
.geeks-prc-vars,
.geeks-prc-social {
	z-index: 1;
	opacity: 0;
	pointer-events: none;
	transition: opacity var(--prc-move);
}

.geeks-prc-slot.is-centre .geeks-prc-vars,
.geeks-prc-slot.is-centre .geeks-prc-social {
	opacity: 1;
	pointer-events: auto;
}

/* --------------------------------------------------------------- variations */

.geeks-prc-vars {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--prc-var-gap, 8px);
}

.geeks-prc-var {
	display: block;
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	font: inherit;
	line-height: 1;
	/* One value for all of them; the chosen one is always full strength. */
	opacity: var(--prc-var-fade, .4);
	transition: opacity .2s;
}

.geeks-prc-var.is-on {
	opacity: 1;
}

/* One class deeper than it looks, for the reason every picture rule here is:
   Elementor's `.elementor img { height: auto }` carries a class AND an element
   and would otherwise decide how tall this is. Sized by height, so a tall bottle
   comes out narrow and a square logo square, and the row keeps one height. */
/* The whole picture: its own shape, at a stated height.
 *
 * Width is left free and max-width is refused, because a bottle photographed
 * against nothing is mostly nothing — constrained to a square it would be a
 * thumbnail of air with a sliver of bottle down the middle. The row is then a
 * row of different widths, which is honest about what the pictures are. */
.geeks-prc .geeks-prc-var img {
	display: block;
	height: var(--prc-var-size, 40px);
	width: auto;
	max-width: none;
	object-fit: contain;
	-webkit-user-drag: none;
}

/* A badge: one shape for every variation, whatever the photograph.
 *
 * The picture is given a square and fills it from the middle, losing whatever
 * does not fit — so a row of variations is even even when the pictures were
 * taken at different distances, which is what makes it read as a set of swatches
 * rather than a shelf.
 *
 * Corners is the button's own radius control, and it rounds this: the picture
 * inherits it and the button clips to it, so one control shapes the badge all
 * the way round to a circle rather than a second one appearing to fight it. The
 * clip is what makes padding behave too — a padded badge shows its background as
 * a ring, with the picture rounded inside it rather than square-cornered. */
.geeks-prc.vars-badge .geeks-prc-var {
	overflow: hidden;
}

.geeks-prc.vars-badge .geeks-prc-var img {
	height: var(--prc-var-size, 40px);
	width: var(--prc-var-size, 40px);
	object-fit: cover;
	/* Which part survives the crop. Middle by default, because that is where a
	   product usually is; the label on a bottle is generally above it. */
	object-position: var(--prc-var-focus-x, 50%) var(--prc-var-focus-y, 50%);
	/* And how far in. The panel gives a percentage because that is what it
	   reads as; a scale wants a multiplier, so it is divided here rather than
	   storing a number that means nothing on its own.

	   Over 100 the picture grows past the badge and the badge clips it, which is
	   the crop. Under 100 it shrinks inside and the background shows around it,
	   which is an inset — the same control doing both, because they are the same
	   question asked in two directions. */
	transform: scale(calc(var(--prc-var-zoom, 100) / 100));
	border-radius: inherit;
}

/* A form with no picture at all falls back to its name, and takes the same
   square so the row stays a row. Left as bare text it would be the one thing in
   a line of badges that is not one — which is the opposite of what choosing
   badges asked for. */
.geeks-prc.vars-badge .geeks-prc-var span {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	height: var(--prc-var-size, 40px);
	width: var(--prc-var-size, 40px);
	padding: 0 .35em;
	overflow: hidden;
	text-align: center;
	font-size: .7em;
	line-height: 1.15;
}

/* ------------------------------------------------------------------ social */

.geeks-prc-social {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--prc-social-gap, 12px);
}


.geeks-prc-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border-radius: 0;
	background: var(--prc-social-bg, transparent);
	color: var(--prc-social-col, inherit);
	line-height: 1;
	transition: color .2s, background-color .2s, opacity .2s;
}

.geeks-prc-link:focus-visible {
	background: var(--prc-social-bg-h, var(--prc-social-bg, transparent));
	/* The same chain as the hover rule above: the author's resting colour
	 * before the kit's accent. */
	color: var(--prc-social-col-h, var(--prc-social-col, var(--e-global-color-accent, inherit)));
}

/* ---------------------------------------------------------- description */

/* The icon that opens the product's own words.
 *
 * Sized like a link beside it, because the row has to read as one row — the
 * same box, and the padding here shrinks the icon INSIDE that box rather than
 * changing what the box takes up. It is the one thing in the row that opens
 * instead of leaving, so it is the one thing with a background of its own. */
.geeks-prc-info {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	box-sizing: content-box;
	/* Its own size where one is set, the row's where it is not — so it matches
	   the links beside it until somebody says otherwise. */
	width: var(--prc-info-size, var(--prc-social-size, 20px));
	height: var(--prc-info-size, var(--prc-social-size, 20px));
	padding: 0;
	border: 0;
	border-radius: 0;
	line-height: 1;
	cursor: pointer;
	transition: color .2s, background-color .2s, opacity .2s;
	-webkit-appearance: none;
	appearance: none;
}

/* An icon from the library follows the colour control.
 *
 * Elementor draws its icons as solid shapes with no fill of their own, so they
 * come out the browser's default black and the Icon colour above never reached
 * them. Named by Elementor's own class rather than by `svg`, because OURS is
 * drawn with a stroke and carries `fill="none"` on the tag: filling that would
 * turn a ring into a blob. A webfont icon needs nothing — it is text, and text
 * already takes the colour. */
.geeks-prc-info .e-font-icon-svg,
.geeks-prc-pop-x .e-font-icon-svg {
	fill: currentColor;
}

/* Sized, and nothing else.
 *
 * NOT given a fill or a stroke here. Ours is drawn with a stroke and carries
 * `fill="none"` on the tag itself, which is enough — and an icon the author
 * picks is Elementor's, rendered as a SOLID shape whose whole substance is its
 * fill. A rule here saying `fill: none` erased it: the button was still there,
 * still the right size, still opened the description, and drew nothing at all.
 *
 * Width and height are safe: an SVG keeps its own proportions inside the box it
 * is given, so a tall glyph stays a tall glyph rather than being squared off. */
.geeks-prc-info svg,
.geeks-prc-info i {
	width: 100%;
	height: 100%;
	font-size: var(--prc-info-size, var(--prc-social-size, 20px));
	display: block;
}

/* Both of these are BUTTONS, and a theme's button reset paints its own colours
 * on :focus and :hover — `[type=button]:focus` outweighs a single class of ours,
 * so the panel's colours were thrown away the moment either was focused. That is
 * not an edge case here: the popup deliberately focuses its close button as it
 * opens, so the close button was ALWAYS wrong. Stated one class deeper, and for
 * the focused state by name, so the reset cannot reach them.
 *
 * The outline that says where the keyboard is stays exactly as it was — this
 * settles colour, not focus. */
.geeks-prc .geeks-prc-info,
.geeks-prc .geeks-prc-info:focus,
.geeks-prc .geeks-prc-info:hover {
	background: var(--prc-info-bg, transparent);
	color: var(--prc-info-col, var(--prc-social-col, inherit));
}

.geeks-prc-pop .geeks-prc-pop-x,
.geeks-prc-pop .geeks-prc-pop-x:focus,
.geeks-prc-pop .geeks-prc-pop-x:hover {
	background: var(--prc-pop-x-bg, transparent);
	color: var(--prc-pop-x-col, inherit);
}

/* While its words are open the icon is not there to press again. Hidden by
   opacity rather than display, so the row keeps its shape and nothing shifts
   under the reader's finger. */
.geeks-prc-info.is-open {
	opacity: 0;
	pointer-events: none;
}

/* --------------------------------------------------- and the box it opens */

/* Built on the BODY, not in the widget.
 *
 * The frame clips what is inside it, so a box built there could only ever be
 * as big as the carousel and would be cut off at its edges. Out here it can be
 * any size the panel asks for, it is measured against the WINDOW — which is
 * what makes a percentage mean what an author expects — and the stacking order
 * is its own, because the neighbours out here are the page's furniture rather
 * than the widget's. */
.geeks-prc-pop {
	position: fixed;
	inset: 0;
	z-index: var(--prc-pop-z, 9999);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
	background: var(--prc-pop-veil, rgba(0, 0, 0, .5));
	/* Nothing here reacts until it is opened; the script raises this with the
	   rest of the opening, so a click cannot land on a box that is still on its
	   way in. */
	opacity: 0;
	visibility: hidden;
}

.geeks-prc-pop.is-open {
	visibility: visible;
}

.geeks-prc-pop-box {
	position: relative;
	box-sizing: border-box;
	width: var(--prc-pop-w, 520px);
	max-width: 100%;
	max-height: var(--prc-pop-h, 80%);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border-radius: var(--prc-pop-radius, 10px);
	border: var(--prc-pop-line-w, 0px) solid var(--prc-pop-line, transparent);
	background: var(--prc-pop-bg, #fff);
	color: var(--prc-pop-text-col, inherit);
	/* It is measured before it is shown, so it must not be measured with a
	   growth already on it. */
	transform-origin: 50% 50%;
}

/* A header that stays and a body that moves.
 *
 * The title used to scroll away with the words, which is the one thing a title
 * must not do. Split, the box is a column of two: the header takes the height it
 * needs, the body takes the rest and gives way when there is too much — which is
 * what min-height:0 is for, since a flex child will otherwise refuse to be
 * smaller than its contents and push the whole box past its greatest height. */
.geeks-prc-pop-head {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	flex: 0 0 auto;
	padding: var(--prc-pop-head-pad, 20px 24px 12px);
	/* The line between the two halves, carried by the header so it stays with it
	   rather than travelling with the words. None of it exists until a thickness
	   is asked for. */
	border-bottom: var(--prc-pop-rule-w, 0px) solid var(--prc-pop-rule-col, transparent);
}

.geeks-prc-pop-title {
	margin: 0;
	flex: 1 1 auto;
	min-width: 0;
	color: var(--prc-pop-title-col, inherit);
	font-size: 1.25em;
	line-height: 1.25;
}

/* Which end the close button takes; the title takes the other. */
.geeks-prc-pop.x-start .geeks-prc-pop-head { flex-direction: row-reverse; }

.geeks-prc-pop-body {
	position: relative;
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
	padding: var(--prc-pop-body-pad, 4px 24px 24px);
}

/* The words, the only part that may be longer than the box.
 *
 * No scrollbar: there is a hint at the foot of the body saying there is more,
 * which says it better than a bar does and leaves the words the full width. It
 * still scrolls by every other means — wheel, drag, keyboard, a finger. */
.geeks-prc-pop-text {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overflow-x: hidden;
	-webkit-overflow-scrolling: touch;
	color: var(--prc-pop-text-col, inherit);
	scrollbar-width: none;
	-ms-overflow-style: none;
}

/* The words are for pulling, not for picking up.
 *
 * Selection is off inside the popup: this is a panel you drag, and an I-beam
 * over something you are meant to grab is a promise of the wrong gesture — a
 * pull would otherwise leave a trail of highlighted text behind it. */
.geeks-prc-pop-text {
	user-select: none;
	-webkit-user-select: none;
}

/* Only where there is something to pull. Offering a hand over a popup that
   fits on one screen promises a movement that cannot happen. */
.geeks-prc-pop.can-scroll .geeks-prc-pop-text {
	cursor: grab;
}

.geeks-prc-pop .geeks-prc-pop-text.is-pulling {
	cursor: grabbing;
}

/* A link is still a link, whatever the hand around it says. */
.geeks-prc-pop-text a {
	cursor: pointer;
}

.geeks-prc-pop-text::-webkit-scrollbar {
	width: 0;
	height: 0;
}

/* The hint that there is more below.
 *
 * A bar across the foot of the BODY and a sibling of the words, not a child of
 * them — inside, it would scroll away with the first line it was meant to point
 * past. Full width so a gradient background can fade the last line out under it.
 *
 * It is not there at all until the words are actually too long, and it goes when
 * the end is reached — an arrow that points at nothing is worse than no arrow. */
.geeks-prc-pop-more {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	display: none;
	align-items: center;
	justify-content: var(--prc-pop-more-align, center);
	padding: var(--prc-pop-more-pad, 18px 0 6px);
	color: var(--prc-pop-more-col, inherit);
	pointer-events: none;
	opacity: 1;
	transition: opacity .25s;
}

.geeks-prc-pop.can-scroll .geeks-prc-pop-more { display: flex; }
.geeks-prc-pop.at-end .geeks-prc-pop-more { opacity: 0; }

/* The icon alone is the target, and it is given a little room around it so a
   20px chevron is not a 20px thing to hit. The strip stays untouchable: it lies
   across the last line of the words, and text that scrolls when clicked is a
   trap. At the end there is nothing left to show, so it stops answering. */
.geeks-prc-pop-more svg,
.geeks-prc-pop-more i {
	display: block;
	box-sizing: content-box;
	width: var(--prc-pop-more-size, 20px);
	height: var(--prc-pop-more-size, 20px);
	font-size: var(--prc-pop-more-size, 20px);
	padding: 6px 10px;
	cursor: pointer;
	pointer-events: auto;
}

.geeks-prc-pop.at-end .geeks-prc-pop-more svg,
.geeks-prc-pop.at-end .geeks-prc-pop-more i {
	pointer-events: none;
}

.geeks-prc-pop-more .e-font-icon-svg { fill: currentColor; }

/* The product's own picture, behind the words.
 *
 * A real picture rather than a background, because that is what gives it a fit
 * and a transparency of its own — a background would have to fade the words with
 * it. Under everything, and clipped by the box's corners. */
.geeks-prc-pop-bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	object-fit: var(--prc-pop-bg-fit, cover);
	object-position: var(--prc-pop-bg-x, 50%) var(--prc-pop-bg-y, 50%);
	/* The control sends a percentage, so 100 means life size — same as the
	   variation badge's zoom above. */
	transform: scale(calc(var(--prc-pop-bg-size, 100) / 100));
	opacity: var(--prc-pop-bg-fade, 1);
	pointer-events: none;
}

.geeks-prc-pop-head,
.geeks-prc-pop-body {
	position: relative;
	z-index: 1;
}

.geeks-prc-pop-text > *:first-child { margin-top: 0; }
.geeks-prc-pop-text > *:last-child { margin-bottom: 0; }

/* The facts, under the words and inside the same scroll — they are content, and
   a list pinned below a scrolling description would be a list the description
   slides behind.

   Only the ones the product answered are here at all; an unanswered attribute is
   left out in PHP rather than printed as an empty row. */
/* The facts, all of them, in one grid.
 *
 * One container rather than a run of loose lists, and the lists inside it are
 * structure only — `display: contents` hands their rows to this grid, so the
 * labels of every form share ONE column and every value in the popup starts at
 * the same place. Measured from the longest label, so renaming an attribute
 * cannot leave a column set to the wrong width. */
.geeks-prc-pop-facts {
	display: grid;
	grid-template-columns: var(--prc-pop-attr-cols, max-content 1fr);
	column-gap: var(--prc-pop-attr-colgap, 16px);
	row-gap: var(--prc-pop-attr-gap, 8px);
	margin: var(--prc-pop-attr-top, 20px) 0 0;
	padding: 0;
}

.geeks-prc-pop-attrs,
.geeks-prc-pop-attr {
	display: contents;
}

/* Which form the lines under it belong to: its own row, all the way across. */
.geeks-prc-pop-form {
	grid-column: 1 / -1;
	margin: 0;
	color: var(--prc-pop-form-col, inherit);
}

/* Between one form and the next, never after the last — and nothing at all
   until the line is switched on, since the thickness it reads defaults to none. */
.geeks-prc-pop-facts .geeks-prc-pop-form:not(:first-child) {
	margin-top: var(--prc-pop-form-rule-gap, 0px);
	padding-top: var(--prc-pop-form-rule-gap, 0px);
	border-top: var(--prc-pop-form-rule-w, 0px) solid var(--prc-pop-form-rule-col, transparent);
}

.geeks-prc-pop-attr-k {
	color: var(--prc-pop-attr-k-col, inherit);
	margin: 0;
	min-width: 0;
}

/* The colon belongs to the label, not to the words: written here so it cannot
   be typed twice, and so it never ends up inside a value. */
.geeks-prc-pop-attr-k::after {
	content: ":";
}

.geeks-prc-pop-attr-v {
	color: var(--prc-pop-attr-v-col, inherit);
	margin: 0;
	min-width: 0;
}

.geeks-prc-pop-x {
	position: relative;
	flex: 0 0 auto;
	/* Nudged from wherever the header put it. */
	transform: translate(var(--prc-pop-x-dx, 0px), var(--prc-pop-x-dy, 0px));
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--prc-pop-x-size, 18px);
	height: var(--prc-pop-x-size, 18px);
	padding: 0;
	border: 0;
	line-height: 1;
	cursor: pointer;
	z-index: 1;
	transition: color .2s, background-color .2s;
	-webkit-appearance: none;
	appearance: none;
}

.geeks-prc-pop-x svg,
.geeks-prc-pop-x i {
	width: 100%;
	height: 100%;
	font-size: var(--prc-pop-x-size, 18px);
	display: block;
}



@media (hover: hover) {
	.geeks-prc .geeks-prc-info:hover {
		background: var(--prc-info-bg-h, var(--prc-info-bg, transparent));
		color: var(--prc-info-col-h, var(--prc-info-col, var(--prc-social-col, inherit)));
	}

	.geeks-prc-pop .geeks-prc-pop-x:hover {
		background: var(--prc-pop-x-bg-h, var(--prc-pop-x-bg, transparent));
		color: var(--prc-pop-x-col-h, var(--prc-pop-x-col, inherit));
	}
}

.geeks-prc-info:focus-visible,
.geeks-prc-pop-x:focus-visible {
	outline: 2px solid var(--e-global-color-accent, #2f3437);
	outline-offset: 2px;
}

.geeks-prc-link svg,
.geeks-prc-link i {
	width: var(--prc-social-size, 18px);
	height: var(--prc-social-size, 18px);
	font-size: var(--prc-social-size, 18px);
	fill: currentColor;
}

/* ------------------------------------------------------------------ arrows */

/* A child of the widget, not of the stage, so it can sit over the carousel or
 * take a row of its own without the frame cutting it off.
 *
 * Over the carousel it is a layer laid across the stage and only the buttons
 * take clicks; above or below it is an ordinary block that pushes the carousel
 * out of the way, which is the case the last one could not do at all. */
.geeks-prc-nav {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--prc-nav-gap, 10px);
	pointer-events: none;
}

.geeks-prc.nav-over .geeks-prc-nav {
	position: absolute;
	inset: var(--prc-nav-y, 0px) var(--prc-nav-x, 0px);
	z-index: 2;
}

/* Their own row. The distance from the carousel is its own number: with the two
   arrows together there is a gap between them and a gap from the carousel, and
   one control cannot honestly be both. */
.geeks-prc.nav-before .geeks-prc-nav,
.geeks-prc.nav-after .geeks-prc-nav {
	position: relative;
	pointer-events: auto;
	margin: var(--prc-nav-from, 16px) 0 0;
}

/* Above means above, so a row is placed before the carousel rather than being a
   second copy of the markup. The arrows and the filter buttons each choose a
   side of the carousel to sit on, and this is how either of them gets there.

   A grid of named rows rather than a column of ordered ones, for one reason:
   "over the carousel" has to mean over the CAROUSEL. Both over-layers are
   absolutely positioned against this element, so with a column they measured
   from the top of the WIDGET — and the moment the other one took a row of its
   own, the widget was taller than the carousel by that row and every offset was
   out by its height. Put the arrows above and lay the categories over, and the
   categories landed a row's height too high, with nothing in the panel to say
   why.

   In a grid an absolutely positioned child is placed against its own grid AREA,
   so putting the over-layers in the carousel's area makes their offsets measure
   from the carousel whatever else the widget is carrying. The rows nothing is
   in collapse to nothing, so a widget with neither extra row is laid out
   exactly as the column laid it out. */
.geeks-prc {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"prc-pill-before"
		"prc-nav-before"
		"prc-stage"
		"prc-nav-after"
		"prc-pill-after";
	/* No long-press menu anywhere in the carousel.
	 *
	 * A finger held on a picture is how the ring is turned, and a phone answers
	 * a held finger by offering to save the image — the menu appears, the drag
	 * is abandoned, and the reader is looking at a list instead of a product.
	 * The pictures already refuse to be dragged away; this refuses the menu. */
	-webkit-touch-callout: none;
}

.geeks-prc-stage {
	grid-area: prc-stage;
}

.geeks-prc.nav-before .geeks-prc-nav {
	grid-area: prc-nav-before;
	margin: 0 0 var(--prc-nav-from, 16px);
}

.geeks-prc.nav-after .geeks-prc-nav {
	grid-area: prc-nav-after;
}

/* Over the carousel means over the carousel: the layer is given the carousel's
   own area, and its offsets are measured from there. */
.geeks-prc.nav-over .geeks-prc-nav,
.geeks-prc.pill-over .geeks-prc-filter {
	grid-area: prc-stage;
}

/* --------------------------------------------------- where the filter sits */

/* The same three places the arrows have, and for the same reasons: a row of its
   own above or below, which pushes the carousel out of the way, or laid across
   the carousel, where only the buttons take clicks. */
.geeks-prc.pill-before .geeks-prc-filter {
	grid-area: prc-pill-before;
}

.geeks-prc.pill-after .geeks-prc-filter {
	grid-area: prc-pill-after;
	margin: var(--prc-pill-from, 24px) 0 0;
}

/* Over the carousel, the row is PLACED, not stretched.
 *
 * The arrows can be stretched across the frame because their bar is invisible
 * and only the two buttons take clicks. This row has a background of its own,
 * so a bar from edge to edge is a bar from edge to edge — it has to be the size
 * of its buttons and put where it was asked for. */
.geeks-prc.pill-over .geeks-prc-filter {
	position: absolute;
	top: var(--prc-pill-top, var(--prc-pill-y, 0px));
	bottom: var(--prc-pill-bottom, auto);
	left: var(--prc-pill-left, 50%);
	right: var(--prc-pill-right, auto);
	transform: translate(var(--prc-pill-shift, -50%), var(--prc-pill-rise, 0px));
	z-index: 3;
	margin: 0;
	pointer-events: none;
}

.geeks-prc.pill-over .geeks-prc-pill {
	pointer-events: auto;
}

.geeks-prc-arrow {
	pointer-events: auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	/* The site's own palette, not a colour borrowed from somebody's demo. */
	background: var(--e-global-color-primary, #2f3437);
	color: #fff;
	cursor: pointer;
	transition: opacity .2s, transform .2s;
}

.geeks-prc-arrow[disabled] {
	opacity: .35;
	cursor: default;
	transform: none;
}

.geeks-prc-arrow svg,
.geeks-prc-arrow i {
	width: var(--prc-arrow-icon, 22px);
	height: var(--prc-arrow-icon, 22px);
	font-size: var(--prc-arrow-icon, 22px);
	line-height: 1;
	/* Elementor's icon SVGs declare no fill at all — its only rule for them is a
	 * height — and an SVG path with no fill paints black. So a chosen icon
	 * ignored the colour control entirely while the built-in chevrons worked,
	 * because those carry stroke="currentColor" of their own.
	 *
	 * Set on the SVG and not on its paths, deliberately: our own chevrons keep
	 * their fill="none" attribute, which beats an inherited value, while an
	 * Elementor icon's paths have no attribute and inherit this. */
	fill: currentColor;
}

/* The icon points the way the carousel runs. Two paths rather than a rotation,
   so the stroke stays true and the join at the point does not smear. */
/* The arrows are the same pair whichever way the products run: previous on the
   left, next on the right, with the sideways chevrons. They are Back and Next,
   not up and down, and changing them with the carousel only made them a second
   thing to learn. */
.geeks-prc-arrow .prc-v { display: none; }

.geeks-prc-empty {
	padding: 2rem;
	border: 1px dashed currentColor;
	border-radius: 8px;
	opacity: .6;
	text-align: center;
}

/* ---------------------------------------------------------------- downwards */

/* Running down is Swiper's `direction: vertical`. It lays the wrapper out as a
/* Somebody who asked for less movement still gets the carousel — it arrives
   rather than slides. */
@media (prefers-reduced-motion: reduce) {
	/* Said outright, because the engine's own rules below carry more classes
	   than these do and a media query adds no weight of its own — without it
	   the shorthand down there quietly puts the duration back. */
	.geeks-prc-rail,
	.geeks-prc-slot,
	.geeks-prc-media,
	.geeks-prc-shot,
	.geeks-prc-spin,
	.geeks-prc-logo {
		transition-duration: .01ms !important;
	}
}

/* ================================================================ the engine ==
 *
 * The layout the carousel makes for itself. The rail does not move — every
 * product places itself, which is what lets the ring be arithmetic instead of a
 * band of copies.
 *
 * The rail does not move — every product places itself, which is what lets the
 * ring be arithmetic instead of a band of copies. */
.geeks-prc .geeks-prc-rail {
	display: block;
	position: relative;
	width: 100%;
	/* Depth, for the setting that turns each product away from the reader. A
	   flat carousel never uses it and pays nothing for it being here. */
	perspective: var(--prc-persp, 1400px);
}

.geeks-prc .geeks-prc-slot {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	/* The size that varies is written on the slide by the engine: the width
	   across, the height down. This fills the other axis. */
}

/* The three layers compose their own transform out of the two numbers the
 * engine writes, and it writes them every frame — so the transform is already
 * the answer and must not also be eased towards it. A quarter-second ease
 * started afresh on every frame is how the arc comes to drag behind the
 * products it belongs to. The fades keep theirs. */
.geeks-prc .geeks-prc-shot,
.geeks-prc .geeks-prc-spin,
.geeks-prc .geeks-prc-logo {
	transition: opacity var(--prc-move);
}

.geeks-prc .geeks-prc-slot.is-centre .geeks-prc-logo {
	transition: opacity calc(var(--prc-move) * .4);
}

/* Which way the page may still be scrolled over the carousel. The old mover
 * supplied this only on devices with no touch at all, and used its own angle
 * test everywhere else; ours is the drag's cross-axis yield, and this. */
.geeks-prc .geeks-prc-stage {
	touch-action: pan-y;
}

.geeks-prc.is-vertical .geeks-prc-stage,
.geeks-prc.is-vertical .geeks-prc-slot.is-centre .geeks-prc-media {
	touch-action: pan-x;
}

.geeks-prc .geeks-prc-stage:focus-visible {
	outline: 2px solid var(--e-global-color-accent, #2f3437);
	outline-offset: 2px;
}

/* What the carousel says about itself, for a reader who cannot see it change.
   Present, but taking no room and drawing nothing. */
.geeks-prc-said {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}
