/**
 * Systm ThreeJS
 *
 * The scene renders against black — that is what keeps the water and the
 * doorway crisp — and every edge is feathered to real transparency with a mask
 * so it dissolves into the section behind it instead of sitting there as a
 * rectangle.
 */

.systm-scene {
	position: relative;
	width: 100%;
	height: var(--systm-height, 70vh);
	min-height: var(--systm-min-height, 360px);
	overflow: hidden;
	pointer-events: none;
	background: transparent;
	isolation: isolate;
}

/* The feather is applied to the rendered layers, NOT to the container.
 *
 * A CSS mask applies to every descendant, and there is no way for a child to
 * opt out. With the mask on .systm-scene, anything a scene appended — a hover
 * hint, a caption, a control — was faded out along with the artwork, and the
 * bottom fade is 32% by default, so a hint sitting 20px above the bottom edge
 * of a 70vh hero ended up at roughly 6% opacity. It was being drawn correctly
 * and was simply invisible.
 *
 * Masking the canvas, vignette and poster individually produces an identical
 * result for the artwork and leaves the container free to hold interface. */
.systm-scene__canvas,
.systm-scene__vignette,
.systm-scene__poster {
	-webkit-mask-image:
		linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 var(--systm-feather-top, 9%), #000 calc(100% - var(--systm-feather-bottom, 32%)), rgba(0, 0, 0, 0) 100%),
		linear-gradient(to right, rgba(0, 0, 0, 0) 0%, #000 var(--systm-feather-side, 7%), #000 calc(100% - var(--systm-feather-side, 7%)), rgba(0, 0, 0, 0) 100%);
	mask-image:
		linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 var(--systm-feather-top, 9%), #000 calc(100% - var(--systm-feather-bottom, 32%)), rgba(0, 0, 0, 0) 100%),
		linear-gradient(to right, rgba(0, 0, 0, 0) 0%, #000 var(--systm-feather-side, 7%), #000 calc(100% - var(--systm-feather-side, 7%)), rgba(0, 0, 0, 0) 100%);
	-webkit-mask-composite: source-in;
	mask-composite: intersect;
}

/* Anything a scene adds to the container for the visitor to read or use.
   Outside the mask, above the artwork, and click-through unless it opts in. */
.systm-scene__ui,
.systm-scene > :not(.systm-scene__canvas):not(.systm-scene__vignette):not(.systm-scene__poster) {
	position: absolute;
	z-index: 2;
}

/* Fills the parent Elementor section instead of taking up its own space. */
.systm-scene--overlay {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	min-height: 0;
	z-index: 0;
}

/* Page builders wrap every widget in a div or two. Those wrappers are the
   problem for overlay mode:
     - our overlay is absolutely positioned, so it leaves the wrapper with no
       in-flow content at all;
     - inside a flex container — which Elementor's e-flexbox always is — a flex
       item with no content resolves to zero width, while align-items:stretch
       still gives it full height;
     - Elementor also makes widget wrappers position:relative, so that
       zero-width box becomes the containing block the overlay measures against.
   The result is a 0×Npx canvas: WebGL draws into it without complaint and the
   page looks broken with nothing in the console. Giving the wrapper a real
   width puts the overlay back on the section the author actually meant. */
.elementor-widget:has(.systm-scene--overlay),
.elementor-widget-container:has(> .systm-scene--overlay),
.elementor-shortcode:has(> .systm-scene--overlay) {
	width: 100%;
}

/* Draggable scenes.
 *
 * `touch-action: pan-y` is the important part. Handing pointer events to the
 * canvas is enough to let a visitor drag on a desktop, but on a phone it also
 * hands over every touch — including the swipe they were using to scroll the
 * page. A full-height hero then becomes a trap you cannot scroll past.
 * `pan-y` reserves vertical swipes for the page and gives horizontal drags to
 * the scene, which is exactly the split an orbit control wants. */
.systm-scene.is-interactive {
	pointer-events: auto;
	cursor: grab;
}

.systm-scene.is-interactive:active {
	cursor: grabbing;
}

/* `touch-action` is what actually arbitrates the gesture. It tells the browser
   which movements to keep for itself; anything it keeps never reaches
   JavaScript at all, so the scene cannot steal a scroll even by accident. */

/* Default. Vertical stays with the page, sideways goes to the scene. */
.systm-scene.is-touch-horizontal,
.systm-scene.is-touch-two-finger {
	touch-action: pan-y;
}

/* The scene takes every touch. Only sane when it does not fill the viewport. */
.systm-scene.is-touch-full {
	touch-action: none;
}

/* Mouse only: touch behaves exactly as it would over an image. */
.systm-scene.is-touch-off {
	touch-action: auto;
}

/* Pinch-zoom needs multi-touch delivered to the canvas, which means the browser
   can keep nothing — so this overrides the touch mode above. It is the reason
   zoom is opt-in: turning it on costs page scrolling over the scene. */
.systm-scene.is-interactive.is-zoomable {
	touch-action: none;
}

/* No background here.
 *
 * This used to be `background: #000`, which put an opaque black plate behind
 * every scene. On a page that is not exactly #000 it showed as a visible
 * rectangle, and it silently defeated any scene offering a transparent
 * background — the canvas was clear, the plate behind it was not.
 *
 * The plugin hosts arbitrary animations and should impose no look of its own.
 * A scene that wants a background sets `scene.background`, which it controls
 * and can expose as a parameter. */
.systm-scene__canvas {
	display: block;
	width: 100%;
	height: 100%;
}

.systm-scene__vignette {
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: radial-gradient(ellipse 72% 62% at 50% 48%, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.6) 100%);
}

/* Shown until the first frame lands, and left in place if WebGL is unavailable. */
.systm-scene__poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity 600ms ease;
}

.systm-scene.is-running .systm-scene__poster {
	opacity: 0;
}

.systm-scene.is-unsupported .systm-scene__canvas {
	display: none;
}

/* Last resort: the containing block gave overlay mode nothing to fill.
   Rather than render an invisible canvas, fall back to inline behaviour so the
   scene is at least on the page. The runtime adds this class only after
   measuring, and says in the console what to fix. It changes layout — an
   overlay is meant to sit behind content, not take up space — but a visible
   scene in the wrong flow beats a correct scene nobody can see. */
.systm-scene--overlay.is-overlay-fallback {
	position: relative;
	inset: auto;
	height: var(--systm-height, 70vh);
	min-height: var(--systm-min-height, 360px);
}

/* NOTE: there is deliberately no blanket `.elementor-editor-active` override
   forcing overlay to position:relative. There used to be, to make the widget
   easier to select, and it was actively harmful: it gave every overlay scene a
   guaranteed size *in the editor only*, so a scene whose section had no height
   looked perfect while editing and rendered nothing on the published page. The
   editor has to show the same result as the front end. */

/* A container with no room to draw in. WebGL fails silently at 0×0, so make it
   visible in the editor rather than leaving a blank gap; the runtime also logs
   what is wrong and how to fix it. Front end stays clean. */
.elementor-editor-active .systm-scene.is-collapsed,
.wp-admin .systm-scene.is-collapsed {
	min-height: 120px;
	outline: 1px dashed rgba(255, 90, 90, .8);
	outline-offset: -1px;
}
