/**
 * RDCFE Pro Listings — Front-end Stylesheet
 *
 * Styles the rendered output of the Listings module (Step 28).
 *
 * Design goals:
 *   - Inherit the same CSS-variable surface used by the rest of the
 *     plugin (`--rdcfe-primary`, `--rdcfe-border`, `--rdcfe-text-muted`,
 *     etc.) so themes that already override those vars get listings
 *     colored automatically.
 *   - Zero hard-coded layouts — grid columns and gap are driven by CSS
 *     custom properties set inline by the renderer (`--rdcfe-listing-cols`
 *     / `--rdcfe-listing-gap`).
 *   - Mobile-first responsive defaults: collapse to one column at narrow
 *     viewports without the author having to write a single media query.
 *   - Pure CSS, no JS dependency for the V1 layout.
 *
 * @package RoxDynamicCPTFieldsEnginePro
 */

/* =========================================================================
   Default variable surface
   ========================================================================= */

:root {
	--rdcfe-listing-cols: 3;
	--rdcfe-listing-gap: 20px;
	--rdcfe-listing-radius: 8px;
	--rdcfe-listing-card-bg: var(--rdcfe-bg, #fff);
	--rdcfe-listing-card-border: var(--rdcfe-border, #e2e4e7);
	--rdcfe-listing-card-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
	--rdcfe-listing-card-shadow-hover: 0 6px 24px rgba(15, 23, 42, 0.08);
	--rdcfe-listing-text: var(--rdcfe-text, #1e1e1e);
	--rdcfe-listing-text-muted: var(--rdcfe-text-muted, #646970);
	--rdcfe-listing-link: var(--rdcfe-primary, #675dd8);
	--rdcfe-listing-link-hover: var(--rdcfe-primary-hover, #4f46c1);
	--rdcfe-listing-badge-bg: var(--rdcfe-primary-bg, #f3f1fc);
	--rdcfe-listing-badge-text: var(--rdcfe-primary, #675dd8);
}

/* =========================================================================
   Grid wrapper
   ========================================================================= */

.rdcfe-listing {
	box-sizing: border-box;
	color: var(--rdcfe-listing-text);
	font-size: 15px;
	line-height: 1.55;
}

.rdcfe-listing *,
.rdcfe-listing *::before,
.rdcfe-listing *::after {
	box-sizing: inherit;
}

.rdcfe-listing--grid {
	display: grid;
	grid-template-columns: repeat(var(--rdcfe-listing-cols, 3), minmax(0, 1fr));
	gap: var(--rdcfe-listing-gap, 20px);
	margin: 0 0 24px;
}

/* Gutenberg / Site Editor ServerSideRender — canvas iframe width is often
   <640px even on a large monitor, so viewport-based rules below would
   always collapse to one column. Keep the saved `--rdcfe-listing-cols`. */
.rdcfe-listing--grid.rdcfe-listing--editor-preview {
	grid-template-columns: repeat(var(--rdcfe-listing-cols, 3), minmax(0, 1fr));
}

/* Default responsive collapse — most card layouts read better as a
   single column below ~640px and as two columns between 640-960px.
   Authors can override by adding their own media queries against
   `--rdcfe-listing-cols`. */
@media (max-width: 960px) {

	.rdcfe-listing--grid.rdcfe-listing--cols-3:not(.rdcfe-listing--editor-preview),
	.rdcfe-listing--grid.rdcfe-listing--cols-4:not(.rdcfe-listing--editor-preview),
	.rdcfe-listing--grid.rdcfe-listing--cols-5:not(.rdcfe-listing--editor-preview),
	.rdcfe-listing--grid.rdcfe-listing--cols-6:not(.rdcfe-listing--editor-preview) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 640px) {

	.rdcfe-listing--grid:not(.rdcfe-listing--editor-preview) {
		grid-template-columns: 1fr;
	}
}

/* =========================================================================
   Card item
   ========================================================================= */

.rdcfe-listing__item {
	display: flex;
}

.rdcfe-listing__card {
	display: flex;
	flex-direction: column;
	width: 100%;
	background: var(--rdcfe-listing-card-bg);
	border: 1px solid var(--rdcfe-listing-card-border);
	border-radius: var(--rdcfe-listing-radius);
	box-shadow: var(--rdcfe-listing-card-shadow);
	overflow: hidden;
	transition: box-shadow 0.18s ease, transform 0.18s ease;
	padding-bottom: 16px;
}

.rdcfe-listing__card:hover {
	box-shadow: var(--rdcfe-listing-card-shadow-hover);
	transform: translateY(-2px);
}

/* ---- Card style modifiers (driven by template card_style config) ---- */

.rdcfe-listing__card--no-padding {
	padding-bottom: 0;
}

.rdcfe-listing__card--no-padding > .rdcfe-listing__component--dynamic_text,
.rdcfe-listing__card--no-padding > .rdcfe-listing__component--dynamic_link,
.rdcfe-listing__card--no-padding > .rdcfe-listing__component--dynamic_meta,
.rdcfe-listing__card--no-padding > .rdcfe-listing__component--term_badges,
.rdcfe-listing__card--no-padding > .rdcfe-listing__component--repeater_output,
.rdcfe-listing__card--no-padding > .rdcfe-listing__node > .rdcfe-listing__component--dynamic_text,
.rdcfe-listing__card--no-padding > .rdcfe-listing__node > .rdcfe-listing__component--dynamic_link,
.rdcfe-listing__card--no-padding > .rdcfe-listing__node > .rdcfe-listing__component--dynamic_meta,
.rdcfe-listing__card--no-padding > .rdcfe-listing__node > .rdcfe-listing__component--term_badges,
.rdcfe-listing__card--no-padding > .rdcfe-listing__node > .rdcfe-listing__component--repeater_output,
.rdcfe-listing__card--no-padding > .rdcfe-listing__meta-inline-row .rdcfe-listing__component {
	padding-left: 0;
	padding-right: 0;
}

.rdcfe-listing__card--no-border {
	border: none;
}

.rdcfe-listing__card--no-shadow {
	box-shadow: none;
}

.rdcfe-listing__card--no-shadow:hover {
	box-shadow: none;
}

.rdcfe-listing__card--no-hover:hover {
	box-shadow: var(--rdcfe-listing-card-shadow);
	transform: none;
}

.rdcfe-listing__card--no-hover.rdcfe-listing__card--no-shadow:hover {
	box-shadow: none;
}

.rdcfe-listing__card--no-radius {
	border-radius: 0;
}

.rdcfe-listing__card--no-image-zoom:hover .rdcfe-listing__image {
	transform: none;
}

/* =========================================================================
   Component primitives
   ========================================================================= */

.rdcfe-listing__component {
	margin: 0;
	padding: 0;
	transition: color 0.15s ease, background-color 0.15s ease;
}

/* Author-set hover text / background — custom properties from
   `AbstractComponent::build_inline_style()` (`--rdcfe-listing-hover-color`,
   `--rdcfe-listing-hover-bg`).

   The rule is gated on `.has-hover-color` / `.has-hover-bg` flags
   emitted by `AbstractComponent::build_class()`. Without that gate,
   `var(--…)` on an undefined variable becomes IACVT (Invalid At
   Computed Value Time) and silently degrades the property to `unset`
   → `inherit`. On hover that means the element inherits the parent's
   colour, *not* the declared colour — visually a flicker. On
   inline-display components (e.g. Term Badges → "Inline (joined)")
   the cascade can also swap padding/line-height resolution mid-hover
   and produce a perceptible "shake". Gating on a class avoids
   IACVT entirely when no hover style is configured. */
.rdcfe-listing__component.has-hover-color:hover {
	color: var(--rdcfe-listing-hover-color) !important;
}

.rdcfe-listing__component.has-hover-color:hover a {
	color: var(--rdcfe-listing-hover-color) !important;
}

.rdcfe-listing__component.has-hover-bg:hover {
	background-color: var(--rdcfe-listing-hover-bg) !important;
}

/* Term badges (Chips / Badges): the generic rule above would paint the
   entire flex wrapper — behind padding, selection chrome, and outside the
   pill's border-radius. Hover fill is delegated to `.rdcfe-listing__badge`
   only (see block under "Term Badges"). */
.rdcfe-listing__component--term_badges.rdcfe-listing__badges--chip.has-hover-bg:hover {
	background-color: transparent !important;
}

/* Phase 2 — width helper. `display: block` + `width: 100%` so an inline
   wrapper (e.g. `<span>`) can still be set Fullwidth from the inspector
   without the author having to touch CSS. */
.rdcfe-listing__component--w-full {
	display: block;
	width: 100%;
}

/* Padded inner area for text-ish components — image components stay
   edge-to-edge so cards feel like real product cards. */
.rdcfe-listing__component--dynamic_text,
.rdcfe-listing__component--dynamic_link,
.rdcfe-listing__component--dynamic_meta,
.rdcfe-listing__component--term_badges,
.rdcfe-listing__component--repeater_output {
	padding: 0 16px;
}

.rdcfe-listing__component + .rdcfe-listing__component {
	margin-top: 8px;
}

/* =========================================================================
   Dynamic Text — default tag styles
   -------------------------------------------------------------------------
   The Dynamic Text component lets authors pick a wrapper tag from a fixed
   whitelist (`p / span / div / h1-h6 / strong / em`). These rules give
   each tag a sensible baseline so swapping the tag in the inspector
   produces a meaningful visual change *before* the author opens the
   Style tab — exactly the JetEngine "predefined" feel.

   The PHP output places `class="… rdcfe-listing__component--dynamic_text"`
   on the **same element** as the author's tag (`<h2 class="…">`), not on
   a wrapper. Use compound selectors (`h2.rdcfe-listing__…`), not
   `.… > h2`, or tag changes have no effect.

   Inline `style="..."` from the Style tab still wins over these rules.
   ========================================================================= */

:is(h1, h2, h3, h4, h5, h6).rdcfe-listing__component--dynamic_text {
	margin: 0;
	color: var(--rdcfe-listing-text);
	font-weight: 700;
	line-height: 1.25;
	letter-spacing: -0.01em;
}

h1.rdcfe-listing__component--dynamic_text {
	font-size: 26px;
	line-height: 1.2;
}

h2.rdcfe-listing__component--dynamic_text {
	font-size: 22px;
}

h3.rdcfe-listing__component--dynamic_text {
	font-size: 18px;
}

h4.rdcfe-listing__component--dynamic_text {
	font-size: 16px;
}

h5.rdcfe-listing__component--dynamic_text {
	font-size: 14px;
	font-weight: 600;
}

h6.rdcfe-listing__component--dynamic_text {
	font-size: 13px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--rdcfe-listing-text-muted);
}

p.rdcfe-listing__component--dynamic_text {
	margin: 0;
	padding: 0 16px;
	color: var(--rdcfe-listing-text-muted);
	font-size: 14px;
	line-height: 1.55;
}

div.rdcfe-listing__component--dynamic_text {
	margin: 0;
	padding: 0;
	color: var(--rdcfe-listing-text);
	font-size: 14px;
	line-height: 1.55;
}

span.rdcfe-listing__component--dynamic_text {
	color: var(--rdcfe-listing-text);
	font-size: inherit;
	line-height: inherit;
}

strong.rdcfe-listing__component--dynamic_text {
	color: var(--rdcfe-listing-text);
	font-weight: 700;
}

em.rdcfe-listing__component--dynamic_text {
	color: var(--rdcfe-listing-text);
	font-style: italic;
}

/* Prevent embedded `<a>` (when format=html) from overriding the
   author-set color — keeps the wrapper's `color:` declaration as the
   single source of truth for text inside Dynamic Text. */
.rdcfe-listing__component--dynamic_text a {
	color: inherit;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.rdcfe-listing__component--dynamic_text a:hover {
	color: var(--rdcfe-listing-link-hover);
}

/* =========================================================================
   Dynamic Image
   ========================================================================= */

.rdcfe-listing__component--dynamic_image {
	display: block;
	overflow: hidden;
	background: var(--rdcfe-bg-light, #f6f7f7);
	aspect-ratio: 16 / 9;
}

.rdcfe-listing__image,
.rdcfe-listing__image-link {
	display: block;
	width: 100%;
	height: 100%;
}

.rdcfe-listing__image {
	object-fit: cover;
	transition: transform 0.4s ease;
}

.rdcfe-listing__card:hover .rdcfe-listing__image {
	transform: scale(1.04);
}

/* Dynamic Text — optional link wrapper (`link_to: post | custom`).
   Inherit text colour / font so the link feels part of the heading /
   paragraph — hover adds underline for discoverability. */
.rdcfe-listing__text-link {
	color: inherit;
	text-decoration: none;
	transition: color 0.15s ease;
}

.rdcfe-listing__text-link:hover,
.rdcfe-listing__text-link:focus-visible {
	color: var(--rdcfe-listing-link);
	text-decoration: underline;
}

/* =========================================================================
   Dynamic Link
   -------------------------------------------------------------------------
   The component root **is** the `<a>` (no inner anchor). Do not use
   `margin-top: auto` here: in a column flex card that pattern steals
   free space above the CTA; adding Style-tab padding grows the item and
   shrinks that auto margin, which pulls the link’s top edge up and can
   visually overlap the row above.
   ========================================================================= */

.rdcfe-listing__component--dynamic_link {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	color: var(--rdcfe-listing-link);
	font-weight: 500;
	text-decoration: none;
	transition: color 0.15s ease;
}

.rdcfe-listing__component--dynamic_link:hover,
.rdcfe-listing__component--dynamic_link:focus-visible {
	color: var(--rdcfe-listing-hover-color, var(--rdcfe-listing-link-hover)) !important;
	text-decoration: underline;
}

.rdcfe-listing__component--dynamic_link::after {
	content: "→";
	display: inline-block;
	transition: transform 0.15s ease;
}

.rdcfe-listing__component--dynamic_link:hover::after {
	transform: translateX(3px);
}

/* =========================================================================
   Dynamic Meta
   ========================================================================= */

.rdcfe-listing__component--dynamic_meta {
	color: var(--rdcfe-listing-text-muted);
	font-size: 13px;
}

.rdcfe-listing__component--dynamic_meta + .rdcfe-listing__component--dynamic_meta {
	margin-top: 0;
	padding-top: 0;
}

/* Icon + text — inner row uses flex cross-axis centering. Dashicons from
   WP core use 20×20px + `vertical-align: top`, so glyphs sit high next to
   meta copy; normalize to an em-scaled box with a centered ::before. */
.rdcfe-listing__meta-inner {
	display: inline-flex;
	align-items: center;
	flex-wrap: wrap;
	column-gap: 0.35em;
	row-gap: 0.15em;
	line-height: 1.45;
}


.rdcfe-listing__meta-icon {
	font-size: 1.15em;
	width: 1em;
	height: 1em;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.rdcfe-listing__meta-icon::before {
	display: block;
	width: 1em;
	height: 1em;
	line-height: 1;
	font-size: 1em;
	text-align: center;
	vertical-align: middle;
}

.rdcfe-listing__meta-author {
	color: inherit;
	text-decoration: none;
	font-weight: 500;
}

.rdcfe-listing__meta-author:hover {
	color: var(--rdcfe-listing-link);
}

/* Consecutive Dynamic Meta layers with Style → "Inline row" group into one
   flex row (see `ListingRenderer`). The card uses flex-column, so without
   this wrapper each meta would stack on its own line. */
.rdcfe-listing__meta-inline-row {
	display: flex;
	flex-direction: row;
	align-items: center;
	flex-wrap: wrap;
	row-gap: 0.25rem;
}


.rdcfe-listing__meta-inline-row .rdcfe-listing__component + .rdcfe-listing__component {
	margin-top: 0;
}

.rdcfe-listing__meta-inline-row > .rdcfe-listing__node {
	flex: 0 0 auto;
}
.rdcfe-listing__meta-inline-row .rdcfe-listing__component--dynamic_meta{
	padding-right: 0;
}

/* Match `.rdcfe-listing__component + .rdcfe-listing__component` spacing when the
   inline row sits next to other card children (row is a `div`, not a component). */
.rdcfe-listing__card > .rdcfe-listing__component + .rdcfe-listing__meta-inline-row,
.rdcfe-listing__card > .rdcfe-listing__node + .rdcfe-listing__meta-inline-row {
	margin-top: 8px;
}

.rdcfe-listing__card > .rdcfe-listing__meta-inline-row + .rdcfe-listing__component,
.rdcfe-listing__card > .rdcfe-listing__meta-inline-row + .rdcfe-listing__node,
.rdcfe-listing__card > .rdcfe-listing__meta-inline-row + .rdcfe-listing__meta-inline-row {
	margin-top: 8px;
}

/* =========================================================================
   Term Badges
   ========================================================================= */

.rdcfe-listing__component--term_badges {
	font-size: 13px;
}

.rdcfe-listing__badges--chip {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	width: fit-content;
	max-width: 100%;
}

.rdcfe-listing__badge {
	display: inline-flex;
	align-items: center;
	padding: 3px 10px;
	border-radius: 999px;
	background: var(--rdcfe-listing-badge-bg);
	color: var(--rdcfe-listing-badge-text);
	font-size: 12px;
	font-weight: 500;
	line-height: 1.4;
}

.rdcfe-listing__badge a {
	color: inherit;
	text-decoration: none;
}

.rdcfe-listing__badge a:hover {
	text-decoration: underline;
}

/* Chip mode — hover custom properties live on the component wrapper
   (`build_inline_style`), but the visible fill is on each `.rdcfe-listing__badge`.
   Without these rules, `has-hover-bg` would restyle an outer wrapper that no
   longer carries the chip background in chip mode. */
.rdcfe-listing__component--term_badges.rdcfe-listing__badges--chip.has-hover-bg:hover .rdcfe-listing__badge {
	background-color: var(--rdcfe-listing-hover-bg) !important;
}

.rdcfe-listing__component--term_badges.rdcfe-listing__badges--chip.has-hover-color:hover .rdcfe-listing__badge,
.rdcfe-listing__component--term_badges.rdcfe-listing__badges--chip.has-hover-color:hover .rdcfe-listing__badge a {
	color: var(--rdcfe-listing-hover-color) !important;
}

.rdcfe-listing__badges--inline {
	color: var(--rdcfe-listing-text-muted);
	/* Outer tag is `<span>` — inline box. If the author adds background /
	 * padding in the Style tab, the anonymous inline box still follows the
	 * line box and can look like a full-width strip next to block siblings.
	 * `inline-block` + `fit-content` keeps pill/chrome tied to the text. */
	display: inline-block;
	width: fit-content;
	max-width: 100%;
	vertical-align: top;
}

.rdcfe-listing__badges--inline a {
	color: var(--rdcfe-listing-link);
	text-decoration: none;
}

.rdcfe-listing__badges--inline a:hover {
	text-decoration: underline;
}

/* =========================================================================
   Repeater Output
   ========================================================================= */

.rdcfe-listing__repeater {
	margin: 0;
	padding-left: 18px;
	color: var(--rdcfe-listing-text-muted);
	font-size: 14px;
}

.rdcfe-listing__repeater[class*="ol"],
ol.rdcfe-listing__repeater {
	list-style: decimal;
}

ul.rdcfe-listing__repeater {
	list-style: disc;
}

div.rdcfe-listing__repeater {
	padding-left: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 6px 12px;
	list-style: none;
}

.rdcfe-listing__repeater-item {
	margin: 0;
}

/* =========================================================================
   Pagination
   ========================================================================= */

.rdcfe-listing__pagination {
	margin-top: var(--rdcfe-listing-gap, 20px);
}

/* Numeric pagination — styled `paginate_links()` output */
.rdcfe-listing__pagination--numeric ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 4px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.rdcfe-listing__pagination--numeric li {
	margin: 0;
}

.rdcfe-listing__pagination--numeric a,
.rdcfe-listing__pagination--numeric span {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	padding: 0 10px;
	border-radius: 8px;
	font-size: 14px;
	font-weight: 500;
	text-decoration: none;
	transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.rdcfe-listing__pagination--numeric a {
	color: var(--rdcfe-listing-text);
	background: var(--rdcfe-listing-card-bg);
	border: 1px solid var(--rdcfe-listing-card-border);
}

.rdcfe-listing__pagination--numeric a:hover {
	color: var(--rdcfe-listing-link);
	border-color: var(--rdcfe-listing-link);
	background: var(--rdcfe-listing-badge-bg);
}

.rdcfe-listing__pagination--numeric .current {
	color: #fff;
	background: #000;
	border: 1px solid #000;
	box-shadow: 0 2px 8px rgba(103, 93, 216, 0.25);
}

.rdcfe-listing__pagination--numeric .dots {
	color: var(--rdcfe-listing-text-muted);
	border: none;
	background: transparent;
}

/* Load More button */
.rdcfe-listing__pagination--load-more {
	display: flex;
	justify-content: center;
}

.rdcfe-listing__load-more-btn {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 12px 28px;
	border: 1px solid var(--rdcfe-listing-card-border);
	border-radius: 8px;
	background: var(--rdcfe-listing-card-bg);
	color: var(--rdcfe-listing-text);
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	transition: border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.rdcfe-listing__load-more-btn:hover {
	color: var(--rdcfe-listing-link);
	border-color: var(--rdcfe-listing-link);
	box-shadow: 0 2px 12px rgba(103, 93, 216, 0.12);
	transform: translateY(-1px);
}

.rdcfe-listing__load-more-btn:active {
	transform: translateY(0);
}

.rdcfe-listing__load-more-btn.is-loading {
	pointer-events: none;
	opacity: 0.7;
}

.rdcfe-listing__load-more-btn.is-loading .rdcfe-listing__load-more-label {
	opacity: 0.5;
}

.rdcfe-listing__load-more-spinner {
	display: none;
	width: 16px;
	height: 16px;
	border: 2px solid var(--rdcfe-listing-card-border);
	border-top-color: var(--rdcfe-listing-link);
	border-radius: 50%;
	animation: rdcfe-spin 0.6s linear infinite;
}

.rdcfe-listing__load-more-btn.is-loading .rdcfe-listing__load-more-spinner {
	display: inline-block;
}

@keyframes rdcfe-spin {
	to { transform: rotate(360deg); }
}

/* =========================================================================
   Empty / placeholder states
   ========================================================================= */

.rdcfe-listing--empty {
	padding: 32px 16px;
	border: 1px dashed var(--rdcfe-listing-card-border);
	border-radius: var(--rdcfe-listing-radius);
	background: var(--rdcfe-bg-light, #f6f7f7);
	text-align: center;
}

.rdcfe-listing__empty-message {
	margin: 0;
	color: var(--rdcfe-listing-text-muted);
}

.rdcfe-listing--placeholder {
	padding: 24px;
	border: 2px dashed var(--rdcfe-listing-card-border);
	border-radius: var(--rdcfe-listing-radius);
	background: var(--rdcfe-bg-light, #f6f7f7);
	color: var(--rdcfe-listing-text-muted);
	text-align: center;
}

/* =========================================================================
   Gutenberg block editor preview
   =========================================================================
   Scoped to `.rdcfe-block-preview-wrap` (the wrapper our edit.js renders
   around `wp.serverSideRender`). Keeps the editor preview from
   inheriting awkward editor-only stretches (e.g. `align: stretch` on
   flex items) and gives the loading spinner a consistent home.
*/

.rdcfe-block-preview-wrap {
	border: 1px solid var(--rdcfe-listing-card-border);
	border-radius: var(--rdcfe-listing-radius);
	padding: 16px;
	background: var(--rdcfe-bg, #fff);
	overflow: hidden;
}

.rdcfe-block-preview-wrap > .rdcfe-listing {
	margin: 0;
}

.rdcfe-block-loading {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 32px 16px;
	color: var(--rdcfe-listing-text-muted);
	font-size: 13px;
}

.rdcfe-block-fallback {
	padding: 16px;
	border: 1px dashed var(--rdcfe-listing-card-border);
	border-radius: var(--rdcfe-listing-radius);
	color: var(--rdcfe-listing-text-muted);
	text-align: center;
	font-size: 13px;
}

/* When the SSR preview lands inside the WP block editor, drop the
   outer card chrome — the block editor adds its own selection
   outline, and stacking two borders looks heavy. */

.block-editor-block-list__block .rdcfe-block-preview-wrap {
	border: 0;
	padding: 0;
	background: transparent;
}

/* =========================================================================
   React canvas — interactive builder surface
   =========================================================================
   Scoped to `.rdcfe-listing-canvas-preview` so these editor-only
   styles never bleed into the front-end. The PHP renderer wraps each
   component in `.rdcfe-listing__node[data-rdcfe-node-id]` only when
   preview mode is on, so the rules below activate purely in the React
   admin canvas.
*/

.rdcfe-listing-canvas-preview {
	cursor: default;
	/* Room for floating type badges (top: -22px) and drop rails without
	   clipping — the outer preview chrome may still use border-radius. */
	padding-top: 28px;
	margin-top: 4px;
}

/* Card chrome must not clip node outlines/badges/drop lines. */

.rdcfe-listing-canvas-preview .rdcfe-listing__card {
	overflow: visible;

}

/* Stop the card hover lift inside the editor — it competes with our
   selection / hover outlines and looks busy. */

.rdcfe-listing-canvas-preview .rdcfe-listing__card:hover {
	box-shadow: var(--rdcfe-listing-card-shadow);
	transform: none;
}

/* Respect --no-shadow inside the canvas preview as well. */
.rdcfe-listing-canvas-preview .rdcfe-listing__card--no-shadow,
.rdcfe-listing-canvas-preview .rdcfe-listing__card--no-shadow:hover {
	box-shadow: none;
}

/* Image scale-on-hover (`transform: scale(1.04)`) is reader-side flair
   only — inside the builder it can interact with cursor hit-testing on
   tightly packed cards and *re-trigger* hover transitions on every
   paint. Pin to the un-scaled state so the canvas is visually static
   between explicit edits. */
.rdcfe-listing-canvas-preview .rdcfe-listing__card:hover .rdcfe-listing__image,
.rdcfe-listing-canvas-preview .rdcfe-listing__image {
	transform: none !important;
}

/* `__node` MUST stay block-level. The wrapper is emitted as a `<div>`
   but its child can be inline (`<span>` for Term Badges → "Inline
   (joined)", Dynamic Meta with the inline flow, etc.). Some browser
   states + author CSS combos can otherwise inline-fy the wrapper and
   destabilise hover hit-testing; this rule pins the geometry. */
.rdcfe-listing-canvas-preview .rdcfe-listing__node {
	display: block;
}

/* Belt-and-braces: kill the colour / background-color transition on
   the inner component while inside the canvas. The wrapper's
   `outline-color` already telegraphs hover; transitioning the
   component's own colour on top of an unstable wrapper-class toggle
   is the classic recipe for a "shake" perception when the cursor
   is right at the edge of an inline-display component. */
.rdcfe-listing-canvas-preview .rdcfe-listing__component {
	transition: none;
}

.rdcfe-listing__node {
	position: relative;
	cursor: pointer;
	transition: outline-color 0.12s ease, background 0.12s ease;
	outline: 1px solid transparent;
	outline-offset: 0;
	border-radius: 4px;
}

.rdcfe-listing__node.is-hovered {
	outline-color: hsl(var(--rdcfe-primary) / 0.45);
	background: transparent;
	box-shadow: none;
}

.rdcfe-listing__node.is-selected {
	outline: 1px solid hsl(var(--rdcfe-primary));
	outline-offset: 0;
	background: transparent;
	box-shadow: none;
	z-index: 2;
}

/* Builder canvas: hide the CSS `::before` type slug (e.g. `DYNAMIC_META`)
   on hover/selection — authors use the React grip + toolbar instead; the
   raw slug confused end users and isn’t needed for drag affordance. */
.rdcfe-listing-canvas-preview .rdcfe-listing__node::before {
	display: none;
}

.rdcfe-listing__node[data-rdcfe-empty="1"] {
	min-height: 32px;
	padding: 8px 12px;
	background: hsl(var(--rdcfe-muted, 220 14% 96%) / 0.6);
	color: hsl(var(--rdcfe-muted-foreground, 215 16% 47%));
	border: 1px dashed var(--rdcfe-listing-card-border);
	font-size: 12px;
	font-style: italic;
}

.rdcfe-listing__node-empty {
	display: inline-block;
}

/* Floating type label — centered above the node; translucent pill so it
   stays readable without a heavy fill behind the component. */

.rdcfe-listing__node.is-hovered::before,
.rdcfe-listing__node.is-selected::before {
	content: attr(data-rdcfe-node-type);
	position: absolute;
	top: -24px;
	left: 50%;
	transform: translateX(-50%);
	padding: 3px 9px;
	border-radius: 6px 6px 0 0;
	background: hsl(var(--rdcfe-primary) / 0.62);
	color: #fff;
	font-size: 10px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	white-space: nowrap;
	pointer-events: none;
	z-index: 20;
	box-shadow: 0 1px 3px hsl(var(--rdcfe-primary) / 0.22);
}

.rdcfe-listing__node.is-hovered:not(.is-selected)::before {
	background: hsl(var(--rdcfe-primary) / 0.5);
}

/* Drag-and-drop indicators — a 5px line above or below the drop
   target with a halo glow + end caps so authors can never miss where
   the drop will land. While a drag is active we also dim every
   non-target node so the eye is drawn straight to the indicator. */

.rdcfe-listing__node.is-drag-source {
	opacity: 0.35;
	filter: grayscale(50%);
}

/* Quiet the hover/selection outlines + the floating label badge
   during an active drag so the drop indicator is the only loud
   element on the canvas. Authors care about ONE thing during a
   drag — where it's about to land. */

.rdcfe-listing-canvas-preview.is-dragging .rdcfe-listing__node.is-hovered:not(.is-drop-before):not(.is-drop-after) {
	outline-color: transparent;
	background: transparent;
}

.rdcfe-listing-canvas-preview.is-dragging .rdcfe-listing__node.is-selected:not(.is-drop-before):not(.is-drop-after) {
	outline-color: hsl(var(--rdcfe-primary) / 0.25);
	background: transparent;
}

.rdcfe-listing-canvas-preview.is-dragging .rdcfe-listing__node.is-hovered:not(.is-drop-before):not(.is-drop-after)::before,
.rdcfe-listing-canvas-preview.is-dragging .rdcfe-listing__node.is-selected:not(.is-drop-before):not(.is-drop-after)::before {
	display: none;
}

/* Soften every non-target node so the drop target is the obvious
   visual focus during the drag. */

.rdcfe-listing-canvas-preview.is-dragging .rdcfe-listing__node:not(.is-drop-before):not(.is-drop-after):not(.is-drag-source) {
	opacity: 0.5;
}

/* The actual drop indicator — a thick coloured pill that spans the
   full width of the parent card, plus a soft glow + matching label
   so the line is impossible to miss. */

.rdcfe-listing__node.is-drop-before::after,
.rdcfe-listing__node.is-drop-after::after {
	content: "";
	position: absolute;
	left: -6px;
	right: -6px;
	height: 4px;
	background: hsl(var(--rdcfe-primary, 245 70% 60%));
	border-radius: 999px;
	box-shadow:
		0 0 0 2px #fff,
		0 0 0 4px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.18),
		0 4px 14px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.4);
	pointer-events: none;
	z-index: 6;
	animation: rdcfe-drop-pulse 1.1s ease-in-out infinite;
}

.rdcfe-listing__node.is-drop-before::after {
	top: -6px;
}

.rdcfe-listing__node.is-drop-after::after {
	bottom: -6px;
}

/* End-cap dot on the leading edge of the drop line — gives the line
   a clear "starts here" anchor and makes the direction obvious. */

.rdcfe-listing__node.is-drop-before,
.rdcfe-listing__node.is-drop-after {
	outline-color: hsl(var(--rdcfe-primary, 245 70% 60%) / 0.45);
}

@keyframes rdcfe-drop-pulse {

	0%,
	100% {
		box-shadow:
			0 0 0 2px #fff,
			0 0 0 4px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.18),
			0 4px 14px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.4);
	}

	50% {
		box-shadow:
			0 0 0 2px #fff,
			0 0 0 6px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.28),
			0 6px 20px hsl(var(--rdcfe-primary, 245 70% 60%) / 0.5);
	}
}

/* "Drop here" floating label tied to the drop indicator — anchored
   at the right edge of the line so it never collides with the node's
   own type badge on the left. */

.rdcfe-listing__node.is-drop-before::before,
.rdcfe-listing__node.is-drop-after::before {
	position: absolute;
	right: -2px;
	padding: 1px 8px;
	background: hsl(var(--rdcfe-primary, 245 70% 60%));
	color: #fff;
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	border-radius: 999px;
	pointer-events: none;
	z-index: 7;
	white-space: nowrap;
	content: "Drop here";
}

.rdcfe-listing__node.is-drop-before::before {
	top: -16px;
}

.rdcfe-listing__node.is-drop-after::before {
	bottom: -16px;
}

/* Links inside the canvas preview are completely inert:
   `pointer-events: none` makes the browser treat them as
   non-interactive, so the click event is dispatched on the parent
   `.rdcfe-listing__node` wrapper instead of the anchor — that's the
   element our React click handler reads `data-rdcfe-node-id` from for
   inspector selection. This is the third (CSS) layer of nav-blocking
   on top of (1) `useLayoutEffect` href-stripping and (2) capture-phase
   `preventDefault` in `CanvasPreview.tsx`; even if both JS guards
   fail, the link physically cannot fire a click. We deliberately keep
   the cursor on the parent `.rdcfe-listing__node`, which already shows
   `cursor: pointer` (line ~594), so the affordance survives. */

.rdcfe-listing-canvas-preview a {
	pointer-events: none;
}

/* Re-enable pointer events on action buttons inside our floating
   toolbar so the buttons themselves still work. */

.rdcfe-listing-canvas-preview [data-rdcfe-action] {
	pointer-events: auto;
}

/* =========================================================================
   Reduced motion
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {

	.rdcfe-listing__card,
	.rdcfe-listing__image,
	.rdcfe-listing__component--dynamic_link::after,
	.rdcfe-listing__node {
		transition: none;
	}

	.rdcfe-listing__card:hover {
		transform: none;
	}

	.rdcfe-listing__card:hover .rdcfe-listing__image {
		transform: none;
	}

	.rdcfe-listing__node.is-drop-before::after,
	.rdcfe-listing__node.is-drop-after::after {
		animation: none;
	}
}
