/* ══════════════════════════════════════════════════════════════════════
   BEFORE / AFTER SLIDER
   Ported from Jaeden's nosmokenofire build and generalised. See the plugin
   header for what changed.

   HOW THE REVEAL WORKS
   Both images are stacked at full size. The AFTER image is clipped from the
   left by the divider position:

       clip-path: inset(0 0 0 var(--ba-pos))

   So a drag writes one custom property and nothing is resized, moved or
   re-laid-out. Everything else — divider, handle, label clips — reads the
   same property, which is why they stay locked together for free.

   Buttons carry !important on appearance, border, background and shadow
   because Elementor kits and themes style bare `button` aggressively, and a
   kit's `transition: all` on buttons made the handle visibly lag the
   divider. That was measured, not defensive.
═══════════════════════════════════════════════════════════════════════ */

.ba {
	--ba-pos: 50%;
	--ba-ratio: 16 / 9;

	position: relative;
	aspect-ratio: var(--ba-ratio);
	width: 100%;
	overflow: hidden;
	border-radius: var(--ba-radius, 0px);
	user-select: none;
}

.ba__img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center center;
	pointer-events: none;
}

.ba__img--after { clip-path: inset(0 0 0 var(--ba-pos)); }

/* ── Divider + handle ──────────────────────────────────────────────── */

.ba__divider {
	position: absolute;
	top: 0;
	bottom: 0;
	left: var(--ba-pos);
	width: var(--ba-linew, 3px);
	transform: translateX(-50%);
	background: var(--ba-line, #ffffff);
	z-index: 3;
	pointer-events: none;
}

.ba__handle {
	appearance: none !important;
	-webkit-appearance: none !important;
	position: absolute;
	top: 50%;
	left: var(--ba-pos);
	transform: translate(-50%, -50%);
	width: var(--ba-handle, 52px);
	height: var(--ba-handle, 52px);
	min-width: 0 !important;
	min-height: 0 !important;
	padding: 0 !important;
	border: var(--ba-handlebw, 2px) solid var(--ba-handleborder, var(--ba-line, #ffffff)) !important;
	border-radius: var(--ba-handleradius, 50%) !important;
	background: var(--ba-handlebg, rgba(0, 0, 0, 0.45)) !important;
	background-image: none !important;
	color: var(--ba-arrow, #ffffff) !important;
	/* A kit's transition:all on buttons made the handle lag behind the
	   divider during a drag — they must move on the same frame. */
	transition: none !important;
	cursor: ew-resize;
	z-index: 4;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 3px;
	/* The handle drags horizontally; page scrolling stays available
	   everywhere else on the stage. */
	touch-action: none;
}

.ba__handle svg { display: block; width: 30%; height: 30%; }

.ba__handle-img {
	display: block;
	width: var(--ba-iconh, 32px);
	height: var(--ba-iconh, 32px);
	background-image: var(--ba-icon);
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
}

.ba__handle:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.ba--handle-none .ba__handle { gap: 0; }

.ba.is-dragging,
.ba.is-dragging .ba__handle { cursor: ew-resize; }

/* ── Handle flash ──────────────────────────────────────────────────────
   One-shot ring on first grab, gated by a class so it costs nothing when
   the widget has not asked for it. The colour is a variable rather than a
   brand value, which is the whole point of generalising this. */
.ba--flash .ba__handle.is-fired::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	pointer-events: none;
	animation: ba-flash 0.45s ease-out 1;
}

@keyframes ba-flash {
	0%   { opacity: 0.9; box-shadow: 0 0 0 0 var(--ba-flash, rgba(255,255,255,0.85)), 0 0 22px 6px var(--ba-flash, rgba(255,255,255,0.55)); }
	100% { opacity: 0; box-shadow: 0 0 0 26px transparent, 0 0 34px 14px transparent; }
}

/* In fullscreen the whole stage is the drag surface and page scroll is
   already locked, so hand every touch straight to the slider instead of
   letting the browser arbitrate against a scroll gesture first. */
.ba-fs .ba { touch-action: none; }

/* ── Labels ────────────────────────────────────────────────────────────
   Each label sits inside a stage-sized clip layer using the SAME geometry
   as the image clip, so a label is never left floating over the picture
   that has lost the frame. Drag toward one edge and that side's label tucks
   away with its image, which keeps "which am I looking at" unambiguous at
   the extremes.

   The clip has to be on a full-stage box: inset() percentages resolve
   against the element's own border box, so clipping the label span itself
   would measure against the label rather than the stage. */

.ba__labelclip {
	position: absolute;
	inset: 0;
	z-index: 3;
	pointer-events: none;
}

.ba__labelclip--before { clip-path: inset(0 calc(100% - var(--ba-pos)) 0 0); }
.ba__labelclip--after  { clip-path: inset(0 0 0 var(--ba-pos)); }

.ba__label {
	position: absolute;
	top: var(--ba-labeltop, 16px);
	bottom: var(--ba-labelbottom, auto);
	z-index: 3;
	color: var(--ba-labelcolor, #ffffff);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	pointer-events: none;
}

.ba__label--before { left: var(--ba-labelinset, 16px); }
.ba__label--after  { right: var(--ba-labelinset, 16px); }

/* Pills get the background; plain text does not. Padding and radius come
   from the widget's own controls so a pill can be shaped, not just
   recoloured. */
.ba--label-pills .ba__label {
	padding: 10px 20px;
	border-radius: 99px;
	background: var(--ba-labelbg, rgba(0, 0, 0, 0.65));
}

.ba--label-plain .ba__label { background: none; }

/* Redacted bars are drawn by the script as SVG; only the height is CSS. */
.ba--label-redacted .ba__label { padding: 0; background: none; line-height: 0; }
.ba--label-redacted .ba__label svg {
	display: block;
	height: var(--ba-labelh, 57px);
	width: auto;
	overflow: visible;
}

/* Fullscreen puts a close button top-right; keep a top-aligned After label
   clear of it. */
.ba-fs .ba__label--after { right: var(--ba-labelfsright, 64px); }

/* ── Pair tabs ─────────────────────────────────────────────────────── */

.ba-set__tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	justify-content: center;
	margin-bottom: 16px;
}

.ba-set__tab {
	appearance: none !important;
	-webkit-appearance: none !important;
	padding: 9px 20px;
	min-width: 0 !important;
	min-height: 0 !important;
	border: 0 !important;
	border-radius: 99px !important;
	background: rgba(255, 255, 255, 0.08);
	color: #d7dce0;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	cursor: pointer;
	box-shadow: none !important;
	text-shadow: none !important;
}

.ba-set__tab:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* ── Mobile: tap to fullscreen ─────────────────────────────────────────
   On phones the prompt covers the stage, which also means an accidental
   drag cannot happen while scrolling past. Desktop and tablet are
   untouched. */

.ba__prompt { display: none; }

@media (max-width: 767px) {
	.ba--mobilefs .ba__prompt {
		appearance: none !important;
		-webkit-appearance: none !important;
		position: absolute;
		inset: 0;
		z-index: 6;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		gap: 10px;
		width: 100%;
		border: 0 !important;

		/* THE ONE PROPERTY THE ARMOR ABOVE MISSED. This is a bare <button>, and
		   an Elementor kit with a global button radius paints it: on CMR that
		   setting is 999px, which clamps to half the short side and left the
		   overlay as a lozenge sitting inside the image's own corners.

		   Read from --ba-radius rather than `inherit`, so it follows the stage's
		   Corner Radius control at any nesting depth instead of depending on
		   this button staying a direct child. The overlay covers the stage edge
		   to edge, so its corners have to be the stage's corners. */
		border-radius: var(--ba-radius, 0px) !important;

		background: rgba(8, 10, 12, 0.55) !important;
		color: #ffffff;
		font-size: 14px;
		font-weight: 700;
		letter-spacing: 0.06em;
		text-transform: uppercase;
		cursor: pointer;
		box-shadow: none !important;
		text-shadow: none !important;
	}
	.ba--mobilefs .ba__prompt svg { width: 34px; height: 34px; }
}

/* In the editor the prompt would blanket the stage and swallow the click
   that selects the widget, so it stands down. Nothing is lost — fullscreen
   is a visitor affordance, not an authoring one. */
.ba--editor .ba__prompt { display: none !important; }

/* ── Fullscreen shell ──────────────────────────────────────────────── */

.ba-fs {
	position: fixed;
	inset: 0;
	z-index: 99999;
	display: none;
	background: #0b0d0f;
}

.ba-fs.is-open { display: block; }

.ba-fs__close {
	appearance: none !important;
	-webkit-appearance: none !important;
	position: absolute;
	top: 12px;
	right: 12px;
	z-index: 10;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	min-width: 0 !important;
	padding: 0 !important;
	border: 0 !important;
	border-radius: 50% !important;
	background: rgba(255, 255, 255, 0.12) !important;
	color: #ffffff;
	cursor: pointer;
	box-shadow: none !important;
	font-size: 0;
}

.ba-fs__close svg { display: block; width: 16px; height: 16px; }

/* Rotate prompt in portrait, stage in landscape — a CSS-only swap, so no
   orientation listener can get out of step with what is on screen. */
.ba-fs__rotate {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 22px;
	padding: 32px;
	color: #ffffff;
	font-size: 15px;
	font-weight: 600;
	line-height: 1.5;
	text-align: center;
}

.ba-fs__phone {
	position: relative;
	width: 44px;
	height: 74px;
	border: 3px solid #ffffff;
	border-radius: 10px;
	animation: ba-rotate 1.8s ease-in-out infinite alternate;
}

.ba-fs__phone::after {
	content: "";
	position: absolute;
	bottom: 6px;
	left: 50%;
	transform: translateX(-50%);
	width: 14px;
	height: 3px;
	border-radius: 3px;
	background: #ffffff;
}

@keyframes ba-rotate {
	0%, 30%   { transform: rotate(0deg); }
	70%, 100% { transform: rotate(90deg); }
}

.ba-fs__slot {
	position: absolute;
	inset: 0;
	display: none;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 10px;
}

@media (orientation: landscape) {
	.ba-fs__rotate { display: none; }
	.ba-fs__slot { display: flex; }
}

/* The original hardcoded a 16/9 max-width here. Constraining by height
   instead keeps it correct at whatever aspect ratio the stage is set to. */
.ba-fs__slot .ba-set,
.ba-fs__slot > .ba { width: 100%; max-width: 100%; }
.ba-fs__slot .ba { max-height: calc(100vh - 80px); }
.ba-fs .ba__prompt { display: none !important; }

body.ba-lock { overflow: hidden; }

/* ── Optional glitch seam ──────────────────────────────────────────────
   RGB-split bands plus jittering slices of the AFTER image, clipped to a
   corridor around the divider. The script randomises the custom properties
   per frame. Off unless the widget enables it.

   The fragments paint the after image via --ba-afterimg, which the render
   sets inline — without it they would be empty boxes. */

.ba__seamfx {
	position: absolute;
	inset: 0;
	z-index: 2;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.12s ease;
}

.ba.is-glitching .ba__seamfx { opacity: 1; }

.ba__seamfx .bafx {
	position: absolute;
	inset: 0;
	background-image: var(--ba-afterimg);
	background-size: cover;
	background-position: center;
	/* Every fragment is its own thin band around the seam — vertical band,
	   horizontal reach, offset and opacity are all randomised
	   independently, so nothing ever lines up into readable columns. */
	clip-path: inset(var(--t, 30%) calc(100% - var(--ba-pos) - var(--sp, 24px)) var(--b, 60%) calc(var(--ba-pos) - var(--sp, 24px)));
	transform: translateX(var(--a, 0px));
	opacity: var(--o, 0);
}

.ba__seamfx .bafx--red  { filter: url(#ba-glitch-red);  mix-blend-mode: screen; }
.ba__seamfx .bafx--cyan { filter: url(#ba-glitch-cyan); mix-blend-mode: screen; }

.ba__seamfx .bafx-band {
	position: absolute;
	inset: 0;
	background-image: var(--ba-afterimg);
	background-size: cover;
	background-position: center;
	mix-blend-mode: screen;
	clip-path: inset(0 calc(100% - var(--ba-pos) - var(--bd-sp, 20px)) 0 calc(var(--ba-pos) - var(--bd-sp, 20px)));
	transform: translateX(var(--bd-a, 0px));
	opacity: var(--bd-o, 0);
}

.ba__seamfx .bafx-band--red  { filter: url(#ba-glitch-red); }
.ba__seamfx .bafx-band--cyan { filter: url(#ba-glitch-cyan); }

/* Phone budget. Every fragment is a stage-sized layer carrying an SVG
   colour-matrix filter plus a blend mode, and all of them re-rasterise on
   every tick — that filter graph is what melts mobile GPUs. On small or
   touch screens the script adds .ba--lite and parks the surplus fragments;
   these rules drop the SVG filters for a background-blend tint, which reads
   the same chromatically but costs a fraction to paint.

   Without these the class would be inert and mobile would quietly keep the
   expensive path, which is the opposite of what lite mode is for. */
.ba--lite .ba__seamfx .bafx--red,
.ba--lite .ba__seamfx .bafx-band--red {
	filter: none;
	background-color: #ff2f2f;
	background-blend-mode: multiply;
}

.ba--lite .ba__seamfx .bafx--cyan,
.ba--lite .ba__seamfx .bafx-band--cyan {
	filter: none;
	background-color: #24ffff;
	background-blend-mode: multiply;
}

/* ── Reduced motion ────────────────────────────────────────────────────
   The script already skips the tease, the recoil and the glitch under this
   setting. This covers the decorative animation the CSS owns. */
@media (prefers-reduced-motion: reduce) {
	.ba-fs__phone { animation: none; transform: rotate(90deg); }
	.ba__seamfx { display: none; }
	.ba--flash .ba__handle.is-fired::after { animation: none; }
}