/*
 * Default Event Card styling (Increment 10, layout completed in
 * Increment 11). Deliberately unopinionated on brand visuals — see
 * CLAUDE.md §3, "Client-specific visual identity" is out of this
 * plugin's scope. Inherits typography/color from Elementor Global
 * Fonts/Colors when active, with plain fallbacks otherwise (CLAUDE.md
 * §5). Not a grid/columns layout — see the Increment 10 specification,
 * "not yet a formal Event Grid component."
 *
 * Event Description (Decision 020): rendered HTML is sanitized with
 * wp_kses_post() after block expansion, which strips any inline `style`
 * a block's color/spacing "block supports" may have emitted. This is
 * intentional, not a bug — descriptions inherit this stylesheet's
 * typography/color entirely, via .jdx-events-card-description below,
 * rather than preserving arbitrary per-block colors, backgrounds, or
 * spacing that could break card consistency, accessibility,
 * responsiveness, or Elementor integration.
 */

:root {
	--jdx-events-font-primary: var(--e-global-typography-primary-font-family, inherit);
	--jdx-events-font-secondary: var(--e-global-typography-secondary-font-family, inherit);
	--jdx-events-color-primary: var(--e-global-color-primary, currentColor);
	--jdx-events-color-secondary: var(--e-global-color-secondary, currentColor);
	--jdx-events-color-text: var(--e-global-color-text, currentColor);
	--jdx-events-color-accent: var(--e-global-color-accent, currentColor);

	/* Structural UI, not a semantic status (Increment 11) — deliberately
	 * NOT chained through an --e-global-color-* Elementor fallback like
	 * the four variables above: this always resolves to a concrete
	 * value, so it can never collapse into a colliding currentColor
	 * fallback the way the Increment 10 CTA/badge defect did. Provisional
	 * literal values — confirm with a measured WCAG contrast check
	 * during release validation, not visual inspection alone. */
	--jdx-events-room-badge-bg: #c9a227;
	--jdx-events-room-badge-text: #1a1a1a;

	/* CTA system (Increment 3A.1). Primary/secondary fill tokens chain
	 * through the same --e-global-color-* Elementor slots the badge/CTA
	 * fallback below already used, with concrete literal fallbacks —
	 * never the collision-prone --jdx-events-color-* chain (see the badge
	 * comment above for why). Hover and border values are deterministic
	 * literals by design, not derived via color-mix()/opacity/filter.
	 *
	 * Hover Background tokens (--jdx-events-cta-{primary,secondary}-bg-hover)
	 * are DELIBERATELY NOT declared here any more (Increment 3, v0.2.31):
	 * this used to be an unconditional :root literal, which meant the
	 * token always had a value, with nothing left for a var() fallback
	 * argument to ever supply. That broke Featured Event's own hover
	 * chain (assets/css/featured-event.css), which needs this SAME
	 * shared token to behave as a genuinely empty JDX-global-setting tier
	 * — falling through to Featured's own themed normal-state color when
	 * nothing is configured, never to this value. Grid/Index/Single's own
	 * hover rule below now supplies #0d0d0d/#e6e6e6 as its OWN fallback
	 * argument instead, so their unconfigured behavior is unchanged. */
	--jdx-events-cta-primary-bg: var(--e-global-color-accent, #1a1a1a);
	--jdx-events-cta-primary-fg: var(--e-global-color-primary, #ffffff);

	--jdx-events-cta-secondary-bg: var(--e-global-color-primary, #ffffff);
	--jdx-events-cta-secondary-fg: var(--e-global-color-text, #1a1a1a);
	--jdx-events-cta-secondary-border: #1a1a1a;

	--jdx-events-cta-min-height: 44px;

	/* Two-layer focus ring: a light inner ring immediately outside the
	 * element, a dark outer ring just beyond it. One of the two always
	 * contrasts against the surrounding surface, whichever it turns out
	 * to be — neither ring depends on the focused element's own fill. */
	--jdx-events-focus-ring-outline: #1a1a1a;
	--jdx-events-focus-ring-shadow: #ffffff;

	/* Card border (Increment 3A.2). Structural UI, not a semantic status —
	 * same rationale as the room-badge tokens above: a deterministic solid
	 * literal, not chained through an --e-global-color-* Elementor slot or
	 * currentColor, so it renders identically and predictably across
	 * transparent, dark, and configured --jdx-events-card-bg surfaces. */
	--jdx-events-card-border-color: #4a4a4a;

	/* Cancelled/Postponed badge colors (Increment 3B.1, Decision 021).
	 * Deterministic literals, not chained through --e-global-color-*
	 * Elementor slots — same rationale as the room-badge tokens above,
	 * stronger here: a CANCELLED/POSTPONED notice must render reliably
	 * regardless of whatever a theme's Elementor global colors resolve
	 * to, never collapse into an invisible currentColor fallback. Sold
	 * Out deliberately has no equivalent token — it keeps inheriting
	 * .jdx-events-card-badge's existing Elementor-chained accent/primary
	 * colors, unchanged, per Decision 021's "do not redesign Sold Out". */
	--jdx-events-badge-cancelled-bg: #b30000;
	--jdx-events-badge-postponed-bg: #9a6400;
	--jdx-events-badge-status-text: #ffffff;
}

/* Light/Dark Appearance — cross-component text-color modifiers
 * (Increment 2, v0.2.25). --jdx-events-appearance-light-text /
 * --jdx-events-appearance-dark-text are the two global, admin-configured
 * tokens (Support\PluginSettings, output as :root custom properties by
 * Frontend\EventCardRenderer::add_appearance_tokens() — never written
 * here), present only when an admin has actually configured them.
 *
 * Centralized here rather than duplicated into featured-event.css/
 * single-event.css, deliberately: each compound selector below
 * (component class + its own --appearance-light/--appearance-dark
 * modifier, e.g. .jdx-events-card.jdx-events-card--appearance-light) has
 * specificity 0,2,0, which beats each component's own single-class root
 * color rule (0,1,0) — .jdx-events-card/.jdx-events-single's
 * `color: var(--jdx-events-color-text)` in this same file, and
 * .jdx-events-featured's `color: #ffffff` in featured-event.css —
 * regardless of stylesheet load order, since specificity always outranks
 * source order when they differ. Verified via this specificity math, not
 * assumed; confirmed no change to featured-event.css or single-event.css
 * is required.
 *
 * Each component's fallback preserves its OWN existing default exactly:
 * .jdx-events-card/.jdx-events-single fall back to the shared
 * --jdx-events-color-text token they already use; .jdx-events-featured
 * falls back to its own existing literal #ffffff (Phase 4G), never to
 * --jdx-events-color-text, which the hero has deliberately never read.
 * No modifier class is ever added for an empty/unset Appearance value
 * (see each template's own $appearance_class construction) — the base
 * component rule alone governs that case, unchanged. No !important. */
/* --jdx-events-card-extra-text (Extra Event Live-Validation Correction)
 * is checked FIRST in both compound rules below — it is only ever set,
 * via inline style, on a .jdx-events-card article for an Extra Event
 * with a configured Extra Text Color (templates/event-card.php); it is
 * never present on a .jdx-events-single article at all (Single Event is
 * explicitly out of scope for this correction), so sharing this
 * fallback chain across both selectors has zero effect on Single Event —
 * the var() there is simply always unset and falls through to the next
 * tier exactly as before. This guarantees Extra Text Color wins
 * regardless of whether Appearance is also configured on the same
 * event, without a specificity war: both tiers live in the same
 * property value of the same rule, not competing selectors. */
.jdx-events-card.jdx-events-card--appearance-light,
.jdx-events-single.jdx-events-single--appearance-light {
	color: var(--jdx-events-card-extra-text, var(--jdx-events-appearance-light-text, var(--jdx-events-color-text)));
}

.jdx-events-card.jdx-events-card--appearance-dark,
.jdx-events-single.jdx-events-single--appearance-dark {
	color: var(--jdx-events-card-extra-text, var(--jdx-events-appearance-dark-text, var(--jdx-events-color-text)));
}

.jdx-events-featured.jdx-events-featured--appearance-light {
	color: var(--jdx-events-appearance-light-text, #ffffff);
}

.jdx-events-featured.jdx-events-featured--appearance-dark {
	color: var(--jdx-events-appearance-dark-text, #ffffff);
}

.jdx-events-card-list {
	display: flex;
	flex-direction: column;
	gap: 1.5em;
}

/* Grid arrangement (Phase 3C): an additional modifier class alongside
 * .jdx-events-card-list, not a replacement — gap:1.5em above is
 * inherited as-is (grid and flex both support the gap property), so
 * list and grid share identical spacing without repeating the value.
 * display:grid here overrides display:flex/flex-direction above at
 * equal specificity by source order; grid-template-columns is the only
 * property that actually needs to vary by breakpoint. Base/default
 * column count (4+ events, at the widest tier) per the approved
 * reference designs (Sakura/Treibhaus event grids): 4 columns
 * >=1400px, 3 columns 1000-1399px, 2 columns 650-999px, 1 column below
 * 650px — same desktop-first max-width pattern already used elsewhere
 * in this file (see .jdx-events-card-content's 480px breakpoint above).
 * 1-3 events get a narrower column count instead of leaving the extra
 * tracks empty — see the count-modifier rules and their cascade-order
 * comment below. .jdx-events-card's own max-width:640px (Increment 11)
 * is deliberately left untouched here — it was designed to go inert
 * inside a narrower grid cell rather than fight a grid-level
 * constraint; confirm via live validation, not assumed. */
.jdx-events-card-list--grid {
	display: grid;
	grid-template-columns: repeat( 4, 1fr );
}

@media ( max-width: 1399px ) {
	.jdx-events-card-list--grid {
		grid-template-columns: repeat( 3, 1fr );
	}
}

/* Count-aware column modifiers (Phase 3C correction): applied by
 * Frontend\EventCardRenderer::wrapper_class() only when the actual
 * event count is 1-2 (--grid-cols-2) or exactly 3 (--grid-cols-3), so
 * an under-full row sizes its columns to the real count instead of
 * leaving unused 4-column tracks as dead space. 4-or-more events get
 * no extra modifier — the default .jdx-events-card-list--grid rule
 * above already produces the correct "4 per row + remainder" layout
 * for a partial last row, since explicit grid tracks don't stretch to
 * absorb missing siblings.
 *
 * Deliberate position in this file, load-bearing for the cascade —
 * do not move without re-deriving the whole matrix below:
 * - Placed AFTER the >=1400px base rule and the 1399px query, so at
 *   both of those tiers a count modifier (same 0,1,0 specificity,
 *   later source order) wins over them for 1-3 events, giving 2 or 3
 *   columns instead of the tier's own 4-or-3 default.
 * - Placed BEFORE the 999px and 649px queries below, so at THOSE
 *   narrower tiers the media query (same specificity, later still)
 *   always wins over any count modifier — every count collapses to
 *   the tier's own column count (2, then 1) exactly as it would with
 *   no count modifier applied at all. This is what keeps "count
 *   modifiers must not defeat the responsive collapse" true without
 *   needing !important anywhere.
 *
 * Resulting matrix (columns shown for 1 / 2 / 3 / 4-or-more events):
 *   >=1400px    : 2 / 2 / 3 / 4
 *   1000-1399px : 2 / 2 / 3 / 3
 *   650-999px   : 2 / 2 / 2 / 2
 *   <650px      : 1 / 1 / 1 / 1
 */
.jdx-events-card-list--grid-cols-2 {
	grid-template-columns: repeat( 2, 1fr );
}

.jdx-events-card-list--grid-cols-3 {
	grid-template-columns: repeat( 3, 1fr );
}

@media ( max-width: 999px ) {
	.jdx-events-card-list--grid {
		grid-template-columns: repeat( 2, 1fr );
	}
}

@media ( max-width: 649px ) {
	.jdx-events-card-list--grid {
		grid-template-columns: 1fr;
	}
}

.jdx-events-card {
	position: relative;
	/* Layout fix: without a width constraint, a flex column's default
	 * align-items: stretch grows the card to the full width of whatever
	 * container the shortcode is placed in, producing an unreadably long
	 * description line length. width:100%/max-width together shrink to
	 * fit a narrow container (no horizontal overflow, no media query
	 * needed) while never exceeding a readable ~65-75 character measure
	 * on a wide one. Scoped to the card itself, not .jdx-events-card-list
	 * — a future Grid places cards in narrower cells where this simply
	 * never activates, rather than fighting a grid-level constraint. */
	width: 100%;
	max-width: 640px;
	margin-inline: auto;
	box-sizing: border-box;
	font-family: var(--jdx-events-font-secondary);
	/* --jdx-events-card-extra-text (Extra Event Live-Validation
	 * Correction) checked first — see the --appearance-light/-dark
	 * compound rules below for the full rationale. Only ever set inline
	 * for an Extra Event with a configured Extra Text Color; inert
	 * (falls through to the existing --jdx-events-color-text default)
	 * for every Standard Event and every Extra Event with no Extra Text
	 * Color configured. */
	color: var(--jdx-events-card-extra-text, var(--jdx-events-color-text));
	/* Increment 11: set only via style="--jdx-events-card-bg: …" on the
	 * article by the template, never a direct background-color inline
	 * style (Decision 020) — transparent when unset, so an event with no
	 * configured color renders identically to Increment 10. */
	background-color: var(--jdx-events-card-bg, transparent);
	border: 1px solid var(--jdx-events-card-border-color);
	/* Sakura Event Presentation Refinement (events-v3-edit.html source of
	 * truth): flex column + a floor height, not a fixed one — a card with
	 * more content than 430px still grows normally; min-height only
	 * keeps short cards visually aligned with their row siblings. The
	 * flex column is what lets .jdx-events-card-content below stretch to
	 * fill the remaining height and push Pricing/CTAs toward the bottom
	 * via their own margin-top:auto (see those rules). */
	display: flex;
	flex-direction: column;
	min-height: 430px;
	/* Event → Single Event navigation UX (validation.40 Part 2): the
	 * stretched title link's hover response (below) changes this same
	 * border-color, so it needs to transition here too — otherwise the
	 * border would snap instantly while the title fades. */
	transition: border-color 175ms;
}

/* Positioning context for the optional Sakura Event Logo watermark
 * (.jdx-events-card-logo) — see that rule below. */
.jdx-events-card-media {
	position: relative;
}

.jdx-events-card-poster-link {
	display: block;
}

.jdx-events-card-poster {
	display: block;
	/* width:100% so the poster spans the full card width, per the
	 * approved events-v3-edit.html reference. aspect-ratio:16/10 +
	 * object-fit:cover (Sakura Event Presentation Refinement) replaces
	 * the previous natural-height rendering: a fixed, predictable crop
	 * keeps every card's image band the same height across a row
	 * regardless of each poster's own source aspect ratio, matching the
	 * reference exactly. Safe against upscaling: Frontend\
	 * EventCardPresenter::poster() requests WordPress's 'large' size
	 * (1024px core default cap), comfortably covering this card's 640px
	 * max-width. */
	width: 100%;
	aspect-ratio: 16 / 10;
	object-fit: cover;
}

/* Sakura Event Logo watermark (Sakura Event Presentation Refinement):
 * subtle, subordinate to the event artwork itself, never a clickable
 * element (pointer-events:none) — Frontend\EventCardPresenter resolves
 * the per-event-override-then-global-default precedence; this rule only
 * positions whichever image (if any) that resolution returns. Sizing
 * mirrors the approved events-v3-edit.html reference's own watermark
 * scale, capped with max-width/max-height (not fixed width/height) so a
 * source image of any aspect ratio never distorts or overflows. */
.jdx-events-card-logo {
	position: absolute;
	top: 14px;
	left: 14px;
	max-width: 110px;
	max-height: 55px;
	width: auto;
	height: auto;
	z-index: 2;
	pointer-events: none;
	opacity: 0.95;
	filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.55));
}

/* Widget text color scheme (v0.2.33-dev.2, Elementor\Widgets\
 * TextSchemeControls). The shared --jdx-events-color-text token falls back
 * to Elementor's Global Text color — #7A7A7A in an untouched Kit — which
 * made new widgets grey-on-black on dark sites. These widgets now default
 * the token to light text on their OWN Elementor wrapper only; nothing
 * global, no theme or page typography is touched, and every explicit
 * Style-tab color (element-level {{WRAPPER}} rules) still wins. The
 * "Text Color Scheme" control adds jdx-events-scheme-{dark|site}. The
 * shortcode output (no Elementor wrapper) is unchanged. */
.elementor-widget-jdx_event_grid,
.elementor-widget-jdx_featured_deal,
.elementor-widget-jdx_deals_grid {
	--jdx-events-color-text: #ffffff;
}

.elementor-widget.jdx-events-scheme-dark {
	--jdx-events-color-text: #1a1a1a;
}

.elementor-widget.jdx-events-scheme-site {
	--jdx-events-color-text: var(--e-global-color-text, currentColor);
}

/* Logo containment (v0.2.33-dev.2). Root cause of the oversized SVG
 * logos: Elementor's `.elementor img { max-width: 100%; height: auto }`
 * (0,1,1) outranks the single-class cap above (0,1,0), so inside an
 * Elementor page the logo's only width limit was the card itself. A PNG
 * stayed small at its intrinsic size; an SVG (no or large intrinsic size)
 * grew to the full card width. This card-scoped rule (0,2,0) wins without
 * !important. Max width/height default to 120×48 and are set per Event
 * Grid instance through --jdx-events-card-logo-max-width/-height. */
.jdx-events-card .jdx-events-card-logo {
	max-width: var(--jdx-events-card-logo-max-width, 120px);
	max-height: var(--jdx-events-card-logo-max-height, 48px);
	width: auto;
	height: auto;
	object-fit: contain;
	object-position: left top;
}

/* An SVG may have no intrinsic pixel size: give it the containment box
 * itself; object-fit keeps its aspect ratio, left/top aligned. */
.jdx-events-card .jdx-events-card-logo--svg {
	width: var(--jdx-events-card-logo-max-width, 120px);
	height: var(--jdx-events-card-logo-max-height, 48px);
}

/* Extra Event Live-Validation Correction: applied alongside (not instead
 * of) the base rule above, only when this card has no poster —
 * .jdx-events-card-media then has no image establishing its height, so
 * the base rule's position:absolute would collapse to zero visible
 * space. position:static returns the logo to normal in-flow layout,
 * rendering it as a plain block at the top of the (otherwise empty)
 * media area; top/left/z-index from the base rule become inert once
 * position is no longer absolute, so they don't need to be reset
 * individually. Same max-width/max-height cap as the overlay variant —
 * still a subordinate watermark, not a hero image. */
.jdx-events-card-logo--standalone {
	position: static;
	display: block;
	margin: 1.25rem 1.25rem 0;
}

.jdx-events-card-content {
	/* Single spacing source for every text element below the poster —
	 * individual headings/paragraphs/lists must not carry their own
	 * horizontal padding. Poster stays edge-to-edge (no padding applied
	 * to it); only this wrapper is inset.
	 *
	 * flex column + flex:1 (Sakura Event Presentation Refinement): fills
	 * the remaining height inside .jdx-events-card's own flex column
	 * (above), which is what gives Pricing/CTAs' own margin-top:auto
	 * something to push against — see those rules below. */
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	padding: 2rem;
}

@media ( max-width: 480px ) {
	.jdx-events-card-content {
		/* 2rem (32px) on each side leaves little room on a ~320-375px
		 * phone viewport — reduced proportionally, not a different
		 * design, just keeping the desktop spec usable at small widths. */
		padding: 1.25rem;
	}
}

/* Shared badge slot (Increment 3B.1): holds 0–2 badges in the same
 * position/order Sold Out alone previously occupied — status
 * (Cancelled/Postponed) first, Sold Out second, per approved order.
 * gap/margin-bottom reproduce the spacing a single Sold Out badge
 * already had before the date line (no dedicated rule previously
 * existed; that spacing came from the badge's own inline-block line box
 * plus the date paragraph's zero top margin). */
.jdx-events-card-badges {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4em;
	margin-bottom: 0.5em;
}

/* Status overlay area (Final Sakura Event Presentation Alignment,
 * event-grid-card.html reference): "status renders ABSOLUTELY OVER the
 * image, bottom-right — never touches body layout." Reuses the exact
 * same .jdx-events-card-badges container/grouping (unchanged business
 * logic — Cancelled/Postponed and Sold Out can both render together,
 * same as before) only repositioned; .jdx-events-card-media already
 * carries position:relative, so this needs no new positioning context.
 * margin-bottom:0 overrides the base rule's in-flow spacing, which has
 * no meaning for an absolutely positioned element anyway. */
.jdx-events-card-badges--overlay {
	position: absolute;
	right: 14px;
	bottom: 14px;
	z-index: 2;
	margin-bottom: 0;
	max-width: calc( 100% - 28px );
	justify-content: flex-end;
}

.jdx-events-card-badge {
	display: inline-block;
	font-family: var(--jdx-events-font-secondary);
	font-size: 0.75em;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	padding: 0.25em 0.6em;
	/* Concrete, distinct fallback pair — not --jdx-events-color-accent/
	 * -primary, which both collapse to the same inherited currentColor
	 * when Elementor is inactive or those two Global Color slots are
	 * unconfigured, producing invisible label text (Increment 10 bug
	 * fix). Elementor's real global colors still win whenever set. */
	background: var(--e-global-color-accent, #1a1a1a);
	color: var(--e-global-color-primary, #ffffff);
}

/* Cancelled/Postponed variants (Increment 3B.1, Decision 021; color
 * configurability added Increment 2, v0.2.31): same shared
 * .jdx-events-card-badge geometry/typography, only background/color
 * differ. Doubled-class selector (.jdx-events-card-badge.jdx-events-card-badge--*,
 * specificity 0,2,0) rather than the modifier class alone (0,1,0): live
 * validation found the single-class form losing to an external site
 * rule of equal or higher specificity/later print order (exact source
 * outside this plugin's codebase, not identifiable from here) — this is
 * a targeted specificity increase, not a rework of the component.
 *
 * var() fallback arguments added here (v0.2.31): previously these two
 * rules read the bare custom property with no fallback argument,
 * relying entirely on this file's own :root literal default above —
 * the one token pair in this component that didn't yet follow this
 * codebase's otherwise-universal "unconfigured-emits-nothing + var()
 * fallback at the consumption site" convention (see e.g.
 * --jdx-events-appearance-light-text above, or any Single Event
 * typography token). Adding the fallback argument here is additive and
 * backward-compatible — both the :root literal and the fallback
 * argument carry the identical existing value, so nothing changes for
 * any site; Frontend\EventCardRenderer::add_appearance_tokens() now
 * also has a single, consistent mechanism to target for every status
 * color, not two different mechanisms for different tokens.
 *
 * Text color is now per-status, not shared: --jdx-events-badge-cancelled-text/
 * --jdx-events-badge-postponed-text replace the single shared
 * --jdx-events-badge-status-text this pair previously both read directly
 * (required so Cancelled and Postponed can have independently configured
 * text colors, per the approved Increment 2 spec) — but each still
 * falls back THROUGH the original shared token first, not straight to
 * the literal, so any existing child-theme customization of
 * --jdx-events-badge-status-text itself (still declared in :root above,
 * intentionally left in place) continues to be honored for either
 * status unless/until the new, more specific per-status setting is
 * configured. Sold Out intentionally had no equivalent modifier rule
 * here before this change — see its own new rule below. */
.jdx-events-card-badge.jdx-events-card-badge--cancelled {
	background: var(--jdx-events-badge-cancelled-bg, #b30000);
	color: var(--jdx-events-badge-cancelled-text, var(--jdx-events-badge-status-text, #ffffff));
}

.jdx-events-card-badge.jdx-events-card-badge--postponed {
	background: var(--jdx-events-badge-postponed-bg, #9a6400);
	color: var(--jdx-events-badge-postponed-text, var(--jdx-events-badge-status-text, #ffffff));
}

/* Sold Out (Increment 2, v0.2.31) — new dedicated rule; previously Sold
 * Out had none and simply inherited the base .jdx-events-card-badge
 * rule's own Elementor-accent-chained colors above. The fallback chain
 * here reproduces that exact prior behavior term-for-term
 * (var(--e-global-color-accent,#1a1a1a) / var(--e-global-color-primary,#ffffff)),
 * so an unconfigured site's Sold Out badge is pixel-identical to before
 * this change — this rule only ever changes anything once the new
 * Settings → JDX Events → Status Colors fields are actually filled in. */
.jdx-events-card-badge.jdx-events-card-badge--sold-out {
	background: var(--jdx-events-badge-sold-out-bg, var(--e-global-color-accent, #1a1a1a));
	color: var(--jdx-events-badge-sold-out-text, var(--e-global-color-primary, #ffffff));
}

.jdx-events-card-title {
	font-family: var(--jdx-events-font-primary);
	font-size: 1.5em;
	text-transform: uppercase;
	/* margin-bottom only, no margin-top (Sakura Event Presentation
	 * Refinement): .jdx-events-card-content is now a flex column (see
	 * that rule above), which never collapses adjacent margins the way
	 * normal block flow did — a margin-top here would now sum with the
	 * previous element's own margin-bottom instead of collapsing with
	 * it, widening this gap beyond the original design. Every sibling in
	 * this component follows the same margin-bottom-only convention
	 * (see .jdx-events-card-rooms below), matching the approved
	 * events-v3-edit.html reference's own flex-column spacing model. */
	margin: 0 0 0.6em;
	/* 2-line clamp + overflow hardening (Final Sakura Event Presentation
	 * Alignment, event-grid-card.html reference) — a safety net, not a
	 * reserved zone like Description/Pricing below: a long title clips
	 * at 2 lines instead of growing the card indefinitely, and
	 * min-width:0/overflow-wrap guard against a single unbroken word
	 * widening the card (this element sits inside .jdx-events-card-content,
	 * itself a flex column, so min-width:0 is needed here for the same
	 * reason every flex/grid text descendant in this plugin needs it). */
	min-width: 0;
	overflow-wrap: anywhere;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.jdx-events-card-headline {
	font-family: var(--jdx-events-font-secondary);
	font-size: 1.1em;
	font-weight: 600;
	margin: 0 0 0.5em;
}

.jdx-events-card-title a {
	color: inherit;
	text-decoration: none;
	transition: color 175ms;
}

/* Event → Single Event navigation UX (validation.40 Part 2): the title
 * link is the only real permalink anchor in this card (the poster's own
 * link, .jdx-events-card-poster-link above, is tabindex="-1"/
 * aria-hidden and exists only so the image itself is visually clickable
 * — it is not a second accessible link). Rather than wrap the whole
 * card in a second <a> (which would nest an interactive element around
 * the CTAs below and break them), this ::after stretches the EXISTING
 * title anchor's hit area over the whole card via inset:0 — .jdx-events-card
 * above is the nearest position:relative ancestor, so inset:0 resolves
 * against the full card, not just the title line. z-index:1 sits above
 * the card's own background/poster/badges but stays below the CTA row,
 * which claims z-index:2 (see .jdx-events-card-ctas below) so Buy
 * Tickets/Book a Table remain independently clickable on top of it. */
.jdx-events-card-title a::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 1;
	cursor: pointer;
}

/* Date + Time on one compact row (Visual Correction Increment, gap
 * fixed in the Extra Events / Compact Metadata increment): Date
 * immediately followed by Time with a modest fixed gap, on the same
 * line whenever both exist — replaces the previous two stacked <p>
 * elements. Presentation-only: templates/event-card.php still outputs
 * the exact same $date_line/$time_line values, only wrapped in one
 * shared row. justify-content:space-between was removed — with the new
 * compact numeric date format (Support\DateTime::display_summary()) the
 * date is short enough that space-between pushed Time uncomfortably far
 * to the right instead of sitting beside it; a plain fixed gap keeps
 * Time immediately adjacent regardless of row width. A single child
 * (Time absent/all-day) still simply left-aligns, no extra CSS needed.
 * flex-wrap:wrap is the narrow-width safety net: Date and Time drop to
 * two lines only if a card genuinely has no room for both side by side
 * (e.g. a very narrow single-column mobile card), never overlapping or
 * overflowing. */
.jdx-events-card-meta {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0.25em 0.75em;
	margin: 0 0 0.5em;
}

/* Typography alignment (Sakura Event Presentation Refinement): Date/Time
 * are quiet metadata, not body copy — a modest size reduction plus
 * opacity (never a separate color token, so it still follows whatever
 * text color — including Light/Dark Appearance — is already in effect)
 * reads as secondary information beneath the Title without needing a
 * dedicated muted-text color system. Scale matches .jdx-events-card-pricing
 * below, per the approved "Date and Pricing are both quiet metadata at
 * the same scale" hierarchy rule. margin:0 (Visual Correction Increment):
 * the row above now supplies the shared bottom margin; the previous
 * per-element margin would have doubled it once both sit in one row. */
.jdx-events-card-date,
.jdx-events-card-time {
	font-family: var(--jdx-events-font-secondary);
	font-size: 0.9em;
	opacity: 0.7;
	margin: 0;
}

.jdx-events-card-excerpt {
	margin: 0 0 0.75em;
}

.jdx-events-card-rooms {
	list-style: none;
	/* margin-bottom only — see .jdx-events-card-title's own comment above
	 * for why a margin-top here would now double up under the flex
	 * column instead of collapsing. */
	margin: 0 0 1em;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.4em;
}

.jdx-events-card-room {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.5em;
}

/* Per-event > Elementor widget setting > JDX global setting > existing
 * fallback (Increment 4, v0.2.31) — the same four-tier precedence model
 * Increment 3 established for CTA colors; see DECISIONS.md's Increment
 * 4 entry. The widget tier (--jdx-events-room-badge-{bg,fg}-widget) is
 * written by Elementor\Widgets\FeaturedEventWidget's own Room Badge
 * color controls on {{WRAPPER}} — Event Grid/Event Index/Single Event
 * never populate it (no widget registers a Style control for this
 * selector in that context), so it is always empty here and this is a
 * no-op fallthrough for them, exactly as before. The global tier reuses
 * the EXISTING token names (Frontend\EventCardRenderer::
 * add_appearance_tokens()), so an unconfigured site resolves
 * identically to pre-Increment-4. No "always-present token" trap here,
 * unlike the CTA case: the shared tokens' own :root default below
 * already equals the literal every consumer (including Featured Event)
 * has always used, so no companion override token is needed. */
.jdx-events-card-badge--room {
	background: var(--jdx-events-card-room-badge-bg, var(--jdx-events-room-badge-bg-widget, var(--jdx-events-room-badge-bg)));
	color: var(--jdx-events-card-room-badge-fg, var(--jdx-events-room-badge-fg-widget, var(--jdx-events-room-badge-text)));
}

.jdx-events-card-room-artist {
	font-family: var(--jdx-events-font-secondary);
}

/* FIXED 2-line reserved zone (Final Sakura Event Presentation Alignment,
 * event-grid-card.html reference) — supersedes the previous room-count-
 * based 1/2/4-line rule (Sakura Event Presentation Refinement) entirely;
 * that rule is retired, not merely superseded-when-in-grid-layout: this
 * now applies unconditionally, list layout and grid layout alike, since
 * the reference treats this as a constant property of the card itself,
 * not a row-alignment feature scoped to the grid wrapper. height (not
 * just line-clamp) is what makes this a true RESERVE, not just a
 * maximum: -webkit-line-clamp alone only clips content that overflows,
 * it does not force a shorter paragraph to occupy the full 2-line
 * height — templates/event-card.php now always renders this div
 * (never omitted for an empty description), so an event with no/short
 * description still reserves the identical footprint as one that fills
 * both lines. Visual-only: $description_html itself is never truncated
 * server-side. min-width:0/overflow-wrap: same long-unbroken-word
 * protection as .jdx-events-card-title above. */
/* --desc-lines (validation.30 adaptive budget correction): now driven by
 * Pricing's own populated-line count (2 lines when 3 prices exist, up to
 * 5 when none do — see templates/event-card.php's own comment), not a
 * hardcoded 2 — the ", 2" fallback here only matters if some future
 * caller ever renders this template without setting the property at
 * all. */
.jdx-events-card-description {
	font-family: var(--jdx-events-font-secondary);
	line-height: 1.5;
	margin: 0 0 0.75em;
	min-width: 0;
	overflow-wrap: anywhere;
	height: calc( 1em * 1.5 * var( --desc-lines, 2 ) );
	display: -webkit-box;
	-webkit-line-clamp: var(--desc-lines, 2);
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.jdx-events-card-description p {
	margin: 0 0 0.75em;
}

.jdx-events-card-description p:last-child {
	margin-bottom: 0;
}

/* Plain-text preview (v0.2.32, Decision 052) — same rationale as
 * .jdx-events-index__description--preview (assets/css/event-index.css).
 * Only templates/event-card.php emits this modifier; Single Event and
 * Featured Event never do, so neither is affected. */
.jdx-events-card-description--preview {
	white-space: pre-line;
	height: calc( 1em * 1.5 * var( --desc-lines, 2 ) );
	height: calc( 1lh * var( --desc-lines, 2 ) );
}

/* FIXED 3-line reserved zone (Final Sakura Event Presentation Alignment,
 * event-grid-card.html reference) — always exactly 3 slots' worth of
 * height, 0-3 actually populated: templates/event-card.php now always
 * renders this list (never omitted when $pricing_lines is empty), and
 * this fixed height reserves the same footprint regardless of how many
 * <li> it actually contains. No literal placeholder markup needed for
 * unused slots — the reserved height alone keeps the footer/CTA
 * position stable. Pricing/CTAs pushed toward the bottom (Sakura Event
 * Presentation Refinement, unchanged): margin-top:auto on Pricing
 * consumes all remaining free space inside .jdx-events-card-content's
 * own flex column above it, carrying the CTA row down with it since
 * nothing else sits between them. */
/* --price-lines (validation.30 adaptive budget correction): reserves
 * exactly this event's own populated Pricing-line count (0-3) instead
 * of always reserving the full 3 — the space this frees up is what
 * .jdx-events-card-description's own larger --desc-lines claims. The
 * ", 3" fallback preserves the original fixed-3 behavior for any caller
 * that never sets the property. */
.jdx-events-card-pricing {
	list-style: none;
	font-family: var(--jdx-events-font-secondary);
	font-size: 0.9em;
	line-height: 1.5;
	margin: 0 0 0.75em;
	margin-top: auto;
	padding: 0;
	min-width: 0;
	height: calc( 1em * 1.5 * var( --price-lines, 3 ) );
	overflow: hidden;
}

.jdx-events-card-pricing li {
	margin: 0 0 0.1em;
	min-width: 0;
	overflow-wrap: anywhere;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.jdx-events-card-pricing li:last-child {
	margin-bottom: 0;
}

/* Two equal-width columns (Sakura Event Presentation Refinement,
 * events-v3-edit.html source of truth) — CSS grid rather than the
 * flex+:only-child fallback pattern used elsewhere in this plugin
 * (assets/css/event-calendar.css): with exactly two fixed 1fr tracks, a
 * lone CTA already occupies only the first track at that track's own
 * width, and (grid's default justify-items:stretch) fills it edge to
 * edge — the desired "half-width, not stretched full-width" outcome with
 * no extra selector needed. When both CTAs are present, each simply
 * fills its own 1fr track — genuinely equal width, full available card
 * width, unlike the previous flex row's content-sized buttons.
 * margin-top:auto is the same "stable position at the bottom of this
 * item's own column" mechanism .jdx-events-card-pricing above already
 * uses — resolves to 0 whenever Pricing (immediately before this in the
 * DOM) already consumed the available free space, so the two never
 * double up. */
.jdx-events-card-ctas {
	display: grid;
	grid-template-columns: repeat( 2, 1fr );
	gap: 0.75em;
	margin: 0;
	margin-top: auto;
	/* Event → Single Event navigation UX (validation.40 Part 2): stacks
	 * above the stretched title link's ::after (z-index:1, see
	 * .jdx-events-card-title a::after above) so Buy Tickets/Book a Table
	 * stay independently clickable instead of being intercepted by the
	 * card-wide overlay. position:relative is required for z-index to
	 * apply. */
	position: relative;
	z-index: 2;
}

.jdx-events-card-cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	min-height: var(--jdx-events-cta-min-height);
	padding: 0.5em 1em;
	/* Transparent, same width as the secondary variant's visible border,
	 * so both variants share identical box dimensions — only secondary
	 * overrides border-color below, never border-width. */
	border: 2px solid transparent;
	text-decoration: none;
	transition: background-color 175ms, color 175ms, border-color 175ms;
}

/* Per-event CTA color overrides (validation.30 correction) — checked
 * FIRST, falling back to the existing global tokens unchanged. Only
 * ever set, via inline style, on a .jdx-events-card article (Event
 * Grid) or .jdx-events-index__event article (Event Index) that has a
 * configured Primary/Secondary CTA color (Admin\EventMetaBox's "CTA
 * Colors" fieldset, general to any event) — never present on
 * .jdx-events-single, so this is a no-op there, unchanged. No
 * Elementor Style controls exist for Event Grid/Event Index CTAs
 * (confirmed: neither widget registers a Style section for these
 * classes), so no specificity conflict is possible here the way
 * Calendar's own equivalent fix needed to guard against.
 *
 * Border Color (validation.31 Task 10) — a new, independent override
 * for each tier. Primary's own base rule above already gives every CTA
 * a transparent 2px border by default (box-sizing parity with
 * Secondary's visible one); an explicit Primary Border Color override
 * now paints that same border, falling back to transparent — never to
 * Primary's own Background Color — when unset. Secondary's border no
 * longer follows its Background Color override either (that was the
 * confirmed live-validation defect: a filled custom Background Color
 * silently changed the border too) — it now falls back straight to the
 * existing --jdx-events-cta-secondary-border default token. */
/* Per-event override > built-in fallback (v0.2.31 stabilization,
 * Decision 045 — supersedes Decision 043's four-tier model for this
 * surface specifically). Event Grid, Event Index List, and Single
 * Event never had, and still don't have, any Elementor Style control
 * for these classes — the widget tier Decision 043 introduced here was
 * always a permanently-empty no-op fallthrough for this shared rule,
 * so it is removed for clarity, not behavior change. The JDX global
 * setting tier (also Decision 043) is removed entirely per Decision
 * 045 — Settings → JDX Events → CTA Appearance no longer exists. The
 * built-in fallback token (--jdx-events-cta-primary-bg, etc.) is
 * exactly the same :root-declared, Elementor-global-color-chained
 * literal this plugin has used since before any CTA color work this
 * session — completely unaffected by any of the above. */
/* Unset built-in default standardized to #D4AF37/#000000 (v0.2.31
 * stabilization, Decision 045 follow-up) — matches Featured Event's
 * own built-in default exactly, so Grid/Index/Single/Featured no
 * longer show visually inconsistent unset colors. Deliberately NOT
 * read from --jdx-events-cta-primary-bg/-fg/etc. any more (those
 * shared tokens are still declared at :root above, unchanged, since
 * assets/css/event-index.css's active-filter-button styling and
 * assets/css/event-calendar.css's Prev/Next hover still read
 * --jdx-events-cta-primary-fg directly with no fallback of their own —
 * changing that shared token's value would have silently recolored
 * both of those unrelated elements too). The literal lives directly in
 * each property below instead, exactly like Featured's own rule. */
.jdx-events-card-cta--tickets {
	background: var(--jdx-events-card-cta-primary-bg, #D4AF37);
	color: var(--jdx-events-card-cta-primary-fg, #000000);
	border-color: var(--jdx-events-card-cta-primary-border, #D4AF37);
}

.jdx-events-card-cta--table {
	background: var(--jdx-events-card-cta-secondary-bg, #D4AF37);
	color: var(--jdx-events-card-cta-secondary-fg, #000000);
	border-color: var(--jdx-events-card-cta-secondary-border, #D4AF37);
}

@media ( hover: hover ) {
	/* Background-only hover by default (never opacity, which would also
	 * dim the label) — scoped out of touch devices to avoid sticky hover.
	 * Increment 3 (v0.2.31) adds an optional, independently configurable
	 * hover TEXT color too (same four-tier precedence), defaulting to the
	 * already-resolved NORMAL text value — i.e. no visible change unless
	 * a hover text color is actually configured somewhere, preserving
	 * today's "hover never changes text" behavior exactly. */
	.jdx-events-card-cta--tickets:hover {
		background: var(--jdx-events-card-cta-primary-bg-hover, #0d0d0d);
		color: var(--jdx-events-card-cta-primary-fg-hover, var(--jdx-events-card-cta-primary-fg, #000000));
	}

	.jdx-events-card-cta--table:hover {
		background: var(--jdx-events-card-cta-secondary-bg-hover, #e6e6e6);
		color: var(--jdx-events-card-cta-secondary-fg-hover, var(--jdx-events-card-cta-secondary-fg, #000000));
	}

	/* Event → Single Event navigation UX (validation.40 Part 2): hovering
	 * anywhere on the card — including the stretched title-link overlay,
	 * a descendant of .jdx-events-card — also matches :hover here, since
	 * :hover applies to every ancestor of the pointed-at element. Subtle,
	 * restrained response only: existing border/title tokens, no
	 * transform/scale/glow. Scoped to hover-capable input only, matching
	 * every other hover rule in this file, so touch devices are unaffected
	 * (mobile relies on tap, not hover, per the same requirement). */
	.jdx-events-card:hover {
		border-color: var(--jdx-events-color-accent);
	}

	.jdx-events-card:hover .jdx-events-card-title a {
		color: var(--jdx-events-color-accent);
	}
}

.jdx-events-card-cta:focus-visible,
.jdx-events-card-title a:focus-visible {
	/* Two concentric layers (light then dark) replace the single dark
	 * ring this used to be — a ring colored only for a light page
	 * background was invisible against a dark one. Spread/offset are
	 * sized to sit flush against each other with no gap and no overlap. */
	box-shadow: 0 0 0 3px var(--jdx-events-focus-ring-shadow);
	outline: 2px solid var(--jdx-events-focus-ring-outline);
	outline-offset: 3px;
}

.jdx-events-empty {
	font-family: var(--jdx-events-font-secondary);
	color: var(--jdx-events-color-text);
}
