/* Voxel Toolkit Detached Filters */

/* ── Slot containers ─────────────────────────────── */

/*
 * Dropped into the same row as the search form, the slot has to line up with Voxel's own
 * filters. Voxel wraps each filter in a `.ts-form-group` carrying `padding: 3px 0`, so a
 * 44px control lives in a 50px box and its centre sits 3px lower than a bare element at
 * the same origin — which is exactly the drift you see next to a search form.
 *
 * Reproducing that gutter (rather than centring in the widget box) is what makes it line
 * up in *every* container mode: the search form's filter row stays at the top of its own
 * box when the row stretches, so centring against the full row height would push the slot
 * far below it instead.
 */
.vtdf-slot-wrapper {
	position: relative;
	padding: 3px 0;
}

.vtdf-slot {
	display: flex;
	flex-wrap: wrap;
	flex-direction: column;
	align-items: stretch;
	width: 100%;
	/*
	 * Row gap only. Voxel spaces its own filters with vertical padding rather than a flex
	 * gap, so two filters set to Width 50% add up to exactly 100% and share a row. A
	 * column-gap here would push the second one onto its own line and make the width
	 * setting look ignored — set the Gap control if you want horizontal spacing instead.
	 */
	row-gap: 10px;
	column-gap: 0;
}

.vtdf-slot > .ts-form-group {
	margin: 0;
}

/*
 * Search forms usually cap their filters (`{{WRAPPER}} .ts-filter { max-width: … }`) so the
 * horizontal search bar stays tidy. That cap is inherited along with everything else, and in
 * a slot it fights the layout: a filter set to Width 50% renders its control at the capped
 * width inside a half-width box, so it never lines up with the panel's other rows. Inside a
 * slot the width comes from the slot layout and the per-filter Width (%), so the cap is
 * released. !important is required because the widget's own rule is more specific.
 */
.vtdf-slot .ts-filter {
	max-width: none !important;
}

/*
 * Voxel gutters its filters with 3px of horizontal padding on .ts-form-group, which insets
 * the first and last control from the panel edge and leaves them not quite lining up with
 * the dialog footer buttons. Cancel the gutter at the slot edges only — the spacing between
 * adjacent filters is preserved, the outer edges go flush.
 */
.vtdf-slot {
	margin-left: -3px;
	margin-right: -3px;
	width: calc(100% + 6px);
}

/* Empty slots must not collapse into surrounding content in the editor. */
.elementor-editor-active .vtdf-slot:empty {
	min-height: 48px;
	border: 1px dashed rgba(125, 125, 125, .45);
	border-radius: 6px;
}

.vtdf-notice {
	padding: 12px 14px;
	border: 1px dashed rgba(125, 125, 125, .5);
	border-radius: 6px;
	font-size: 13px;
	opacity: .8;
}

/* ── Originals hidden while their detached copy is live ── */

/*
 * Hide the ORIGINAL button while a detached copy is live — but never the copy itself. With
 * an inline slot the copy sits inside the same .ts-search-widget root, so an unqualified
 * rule here hides the very button it just rendered.
 */
.ts-search-widget.vtdf-hide-search .ts-form-submit:not(.vtdf-detached-btn),
.ts-search-widget.vtdf-hide-reset .ts-form-reset:not(.vtdf-detached-btn) {
	display: none !important;
}

/*
 * A detached button IS a .ts-form-group, appended straight into the slot alongside the
 * teleported filters, so it inherits their gutter and margins for free. It has no
 * per-filter Width (%) of its own, so let it fill the row like the search form does.
 */
.vtdf-detached-btn[hidden] {
	display: none !important;
}

.vtdf-slot > .vtdf-detached-btn {
	flex: 1 1 auto;
}

.vtdf-slot > .vtdf-detached-btn .ts-btn,
.vtdf-slot > .vtdf-detached-btn .ts-filter {
	width: 100%;
}

/*
 * Voxel's Reset button is an <a class="ts-filter"> whose label is a `.ts-filter-text` with
 * `flex: 1 1 auto` — fine at the button's natural width, but once it is stretched to fill a
 * slot the label expands with it and the icon+text pair ends up hard against the left edge,
 * out of step with the Search button beside it. Keep the pair centred as a unit.
 */
.vtdf-slot > .vtdf-detached-btn .ts-filter {
	justify-content: center;
}

.vtdf-slot > .vtdf-detached-btn .ts-filter .ts-filter-text {
	flex: 0 1 auto;
}

/* ── Dialog mode ─────────────────────────────────── */

.vtdf-dialog-trigger {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	cursor: pointer;
}

/*
 * `.ts-filter-count` is absolutely positioned at the right edge of the control, which is
 * exactly where the chevron used to be — so the label needs room not to run underneath it.
 */
.vtdf-has-count .ts-filter-text {
	padding-right: 26px;
}

.vtdf-backdrop,
.vtdf-faux-backdrop {
	position: fixed;
	inset: 0;
	z-index: 499990;
	background: rgba(0, 0, 0, .45);
}

.vtdf-backdrop[hidden],
.vtdf-dialog[hidden] {
	display: none !important;
}

.vtdf-dialog {
	position: fixed;
	z-index: 499995;
	top: 50%;
	left: 50%;
	display: flex;
	flex-direction: column;
	width: min(560px, 92vw);
	max-height: 88dvh;
	transform: translate(-50%, -50%);
	border-radius: 10px;
	background: #fff;
	box-shadow: 0 8px 40px rgba(0, 0, 0, .25);
	color: inherit;
}

.vtdf-dialog-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 16px 18px;
	border-bottom: 1px solid rgba(125, 125, 125, .2);
}

.vtdf-dialog-title {
	font-weight: 600;
}

.vtdf-dialog-close {
	flex: 0 0 auto;
	cursor: pointer;
}

.vtdf-dialog-body {
	overflow-y: auto;
	flex: 1 1 auto;
	padding: 18px;
}

.vtdf-dialog-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 14px 18px;
	border-top: 1px solid rgba(125, 125, 125, .2);
}

.vtdf-dialog-foot .ts-btn {
	flex: 1 1 auto;
}

body.vtdf-dialog-open {
	overflow: hidden;
}

/* ── Voxel Dialog (VX) compatibility ─────────────── */

/*
 * A dialog opened with showModal() lives in the browser's top layer, where no z-index
 * can lift a body-teleported filter popup above it. The runtime downgrades such a
 * dialog to a non-modal show() and marks it here; .vx-native-dialog is already
 * position:fixed / inset:0 / z-index:500000, so it keeps its exact look while
 * re-entering normal stacking order.
 */
dialog.vtdf-faux-modal {
	z-index: 499995;
}

dialog.vtdf-faux-modal::backdrop {
	background: transparent;
}

/*
 * Filter popups teleport to <body> and rely on .ts-popup-root { z-index: 500000 } to sit
 * above everything. But Voxel fades them in with a transition on the wrapping .vx-popup,
 * and opacity < 1 creates a stacking context — which traps that 500000 inside an
 * unpositioned, z-auto flow element for the length of the animation. A dialog at any
 * positive z-index therefore covers the popup while it fades in, then loses to it the
 * instant the animation ends: a visible snap-to-front.
 *
 * Dropping the fade only while one of our dialogs is open removes the stacking context,
 * so the popup's own z-index applies from the first frame. Popups opened anywhere else
 * keep their animation.
 */
body.vtdf-dialog-open .vx-popup {
	opacity: 1 !important;
}

/*
 * Voxel's own search button renders its spinner with v-if, so it simply does not exist
 * when idle. Our detached copy is plain DOM toggled via the `hidden` attribute — and
 * `.ts-loader-wrapper { display: flex }` (forms.css) outranks the user-agent
 * `[hidden] { display: none }` rule, leaving the spinner visible and animating forever.
 */
.vtdf-detached-btn .ts-loader-wrapper[hidden] {
	display: none !important;
}

/*
 * The portal's inner element exists ONLY to carry the widget's `elementor-element-<id>`
 * class so descendant style rules keep matching. It must never become a stacking context
 * itself, or the fixed dialog inside it gets confined and loses to ordinary page content.
 *
 * That is easy to trigger by accident: whatever the user styles the Filter slot widget
 * with is inherited here, and `position: sticky` creates a stacking context *even with
 * z-index: auto* — so a sticky slot silently buried the dialog behind the post feed.
 * Transforms, filters, opacity, will-change, contain and animations do the same.
 */
.vtdf-portal,
.vtdf-portal > .elementor-element {
	position: static !important;
	z-index: auto !important;
	transform: none !important;
	filter: none !important;
	backdrop-filter: none !important;
	perspective: none !important;
	opacity: 1 !important;
	will-change: auto !important;
	contain: none !important;
	isolation: auto !important;
	animation: none !important;
	mix-blend-mode: normal !important;
	inset: auto !important;
	margin: 0 !important;
	padding: 0 !important;
	width: auto !important;
	min-width: 0 !important;
	max-width: none !important;
	height: auto !important;
	min-height: 0 !important;
	max-height: none !important;
	overflow: visible !important;
	flex: none !important;
	/*
	 * `display` is deliberately NOT !important here: the inline-slot dialog uses v-show,
	 * which toggles an inline `display: none`, and an !important stylesheet rule would beat
	 * it and leave the dialog permanently open. `display` does not create a stacking
	 * context anyway, so it has no business in this reset.
	 */
	display: block;
}

/* ── The "More Filters" trigger (inserted into the form's filter row) ── */

/*
 * The trigger is a .ts-form-group inserted among the real filters, so Voxel's
 * own row layout, gutters and filter styling apply to it untouched. It only
 * needs interaction affordances here.
 */
.vtdf-more-group {
	flex: 0 0 auto;
}

.vtdf-more-group[hidden] {
	display: none !important;
}

.vtdf-more-group .ts-filter {
	cursor: pointer;
}

/* The dialog ships hidden and the runtime toggles the attribute. */
.vtdf-portal[hidden] {
	display: none !important;
}

/* Voxel styles .ts-filter-count with its own display, which outranks the
   hidden attribute's UA rule — enforce it for the dialog trigger badge. */
.vtdf-count[hidden] {
	display: none !important;
}
