/* Northern Sky - Category Showcase
   Structural / layout CSS only. Colors, typography, spacing and the
   animation timing are controlled per-instance from the Elementor Style
   tab (see the widget's "selectors" in class-category-showcase-widget.php).

   Layout: one sticky tab bar (.nsm-cshow-tabs) sits above a plain vertical
   stack of .nsm-cshow-section blocks (one per category row). Each section
   is either:
     - a "Stack Scroll" block (.nsm-cshow-stack): the same pinning mechanic
       as the Projects Stack widget - each .nsm-cshow-stack-item is a
       normal-flow block whose height equals the visible card height, and
       pins to the top of the viewport (position: sticky) so a later item
       visually covers the earlier one as the page scrolls past it. No JS
       needed for the pin/cover itself.
     - an "Auto Slider" block (.nsm-cshow-slider): a plain, non-pinned
       horizontal filmstrip that auto-advances via category-showcase.js.
   category-showcase.js separately drives the sticky tab bar's active
   state (scrollspy) and the click-to-jump behaviour. */

.nsm-cshow,
.nsm-cshow *,
.nsm-cshow *::before,
.nsm-cshow *::after {
	box-sizing: border-box;
}

.nsm-cshow {
	position: relative;
	width: 100%;
}

.nsm-cshow-empty {
	padding: 40px;
	text-align: center;
	opacity: 0.6;
}

/* Editor-only heads-up (see maybe_render_dynamic_tag_warning() in the
   widget class) - never shows on the live front end. */
.nsm-cshow-editor-hint {
	margin-bottom: 12px;
	padding: 10px 14px;
	background: #fff8e5;
	border: 1px solid #f0c36d;
	border-radius: 4px;
	font-size: 13px;
	line-height: 1.5;
	color: #664d03;
	text-align: left;
}

/* ---------------------------------------------------------
 * Tabs bar
 * ------------------------------------------------------- */

.nsm-cshow-tabs {
	position: sticky;
	top: 0;
	z-index: 100;
	display: flex !important;
	flex-wrap: wrap;
	align-items: center;
	width: 100% !important;
}

.nsm-cshow-tabs-static .nsm-cshow-tabs {
	position: static;
}

.nsm-cshow-tab {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Content-width tabs: each tab is only as wide as its own label needs
	   (plus padding) - a short "Ready to Move" stays compact, a longer
	   "Completed Projects" takes more room, and the row is positioned by
	   the "Alignment" style control (tabs_justify - left/center/right/
	   justified) rather than every tab being forced to an equal share of
	   the bar. flex-shrink stays on (with min-width: 0) purely as a safety
	   net so tabs only ever shrink below their natural text width, and the
	   label ellipsizes, on a screen too narrow to fit them all - not as
	   the normal case the way equal-width sizing was.

	   !important on both: Elementor prints its own per-page generated CSS
	   for this widget's Style controls (alignment, padding, background,
	   etc.) as a SEPARATE stylesheet/inline block from this plugin's own
	   category-showcase.css. On some hosts/breakpoints that per-page CSS
	   can end up in the DOM before this file finishes loading (theme
	   optimization plugins reordering/deferring stylesheets, aggressive
	   asset caching serving this file slightly stale, etc.), which lets a
	   same-specificity or later-loaded rule win the cascade against this
	   one. !important pins the intended sizing so it can't lose that race,
	   independent of stylesheet load order. */
	flex: 0 1 auto !important;
	min-width: 0 !important;
	cursor: pointer;
	font-family: inherit;
	transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}

/* Truncates gracefully (one label, an ellipsis) if a tab ever ends up
   narrower than its own text - a long label on a narrow mobile screen
   with several tabs, for instance. This has to live on an inner block
   element rather than directly on .nsm-cshow-tab: text-overflow: ellipsis
   on a flex item's own raw text doesn't reliably clip in every browser
   (tested - Chromium lets it overflow the box uncut), and centering via
   justify-content while clipping would cut both edges of the label
   evenly instead of ellipsizing the end. A plain block with its own
   text-align handles both correctly. */
.nsm-cshow-tab-label {
	display: block;
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	text-align: center;
}

/* ---------------------------------------------------------
 * Stack Scroll sections
 * ------------------------------------------------------- */

.nsm-cshow-stack {
	position: relative;
	width: 100%;
}

.nsm-cshow-stack-item {
	position: sticky;
	top: 0;
	width: 100%;
	height: 90vh;
}

.nsm-cshow-stack-card {
	position: absolute;
	inset: 20px;
	border-radius: 24px;
	overflow: hidden;
}

.nsm-cshow-stack-bg-wrap {
	position: absolute;
	inset: 0;
	overflow: hidden;
}

.nsm-cshow-stack-bg-image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	opacity: 0;
	transform: translateY(var(--nsm-cshow-bg-offset, 40px)) scale(1);
	transition-property: opacity, transform;
	transition-timing-function: cubic-bezier(0.16, 0.84, 0.44, 1);
	transition-duration: var(--nsm-cshow-bg-duration, 0.9s);
	transition-delay: var(--nsm-cshow-bg-delay, 0.1s);
	will-change: transform, opacity;
}

.nsm-cshow-stack-item.nsm-in-view .nsm-cshow-stack-bg-image {
	opacity: 1;
	transform: translateY(0) scale(1);
}

.nsm-cshow-no-bg-reveal .nsm-cshow-stack-bg-image {
	opacity: 1;
	transform: translateY(0) scale(1);
	transition: transform var(--nsm-cshow-hover-duration, 0.9s) ease;
}

/* Hover zoom - independent of the entrance transform above; the settled
   translateY(0) position is preserved, only the scale changes. */
.nsm-cshow-stack-card:hover .nsm-cshow-stack-bg-image {
	transform: translateY(0) scale(var(--nsm-cshow-hover-scale, 1.06));
	transition-duration: var(--nsm-cshow-hover-duration, 0.9s);
	transition-delay: var(--nsm-cshow-hover-delay, 0.4s);
}

.nsm-cshow-stack-overlay {
	position: absolute;
	inset: 0;
	pointer-events: none;
}

.nsm-cshow-stack-content {
	position: relative;
	z-index: 1;
	height: 100%;
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	padding: 48px 56px;
}

.nsm-cshow-stack-divider {
	/* Width comes from the widget's "Content Row Max Width" control (Style
	   tab, or the per-category Content tab override) so it always matches
	   the row below it - this base rule intentionally leaves width unset. */
	border: none;
	border-top-style: solid;
	border-top-width: 1px;
	margin: 0 0 24px;
}

.nsm-cshow-stack-row {
	display: flex;
	align-items: flex-start;
	gap: 32px;
	width: 100%;
}

.nsm-cshow-stack-label-col {
	flex: 0 0 170px;
	max-width: 170px;
}

.nsm-cshow-stack-label {
	display: inline-block;
	text-transform: uppercase;
	white-space: nowrap;
}

.nsm-cshow-stack-description {
	flex: 1 1 auto;
	min-width: 0;
}

.nsm-cshow-stack-description p {
	margin: 0;
}

.nsm-cshow-stack-btn {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	text-decoration: none;
	border-bottom-style: solid;
	border-bottom-width: 1px;
	padding-bottom: 4px;
	width: fit-content;
	transition: color 0.3s ease, border-color 0.3s ease;
}

.nsm-cshow-stack-btn-text {
	display: inline-block;
	transition: color 0.3s ease;
}

.nsm-cshow-stack-btn-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	line-height: 1;
	transition: transform 0.3s ease, color 0.3s ease;
}

.nsm-cshow-stack-heading {
	flex: 0 1 auto;
	/* Position (left/center/right) comes from the widget's Style tab ->
	   Heading -> "Position" control, which sets margin via Elementor's
	   generated CSS - this base rule intentionally leaves margin unset. */
	line-height: 1.15;
}

/* "Minimal Caption" card style - counter + title sit in normal flow above
   a plain background, with the image filling the remaining card height
   below them (no dark overlay, no description/button/label/divider). */
.nsm-cshow-stack-card-minimal {
	display: flex;
	flex-direction: column;
	gap: 16px;
	height: 100%;
}

/* Makes the whole "Minimal Caption" card clickable (counter, heading AND
   image) instead of offering no way to click through at all - this style
   has no "SEE CASE STUDY" button like the Overlay/Stack style does.
   display: contents removes the <a> from the box tree entirely, so it has
   no layout effect of its own - the caption and image-wrap below still
   act as direct flex children of .nsm-cshow-stack-card-minimal exactly as
   before. color/text-decoration are still inherited by their text through
   the normal cascade, so they need resetting here. Only rendered at all
   when this project actually has a link (ACF link field, or the post's
   own permalink as a fallback) - see $has_link in render_stack_section(). */
.nsm-cshow-stack-minimal-link {
	display: contents;
	color: inherit;
	text-decoration: none;
}

.nsm-cshow-stack-minimal-caption {
	flex: 0 0 auto;
	padding: 0 4px 24px;
}

.nsm-cshow-stack-minimal-counter {
	display: block;
	margin-bottom: 8px;
}

.nsm-cshow-stack-minimal-heading {
	margin: 0;
	line-height: 1.15;
	text-align: left;
}

.nsm-cshow-stack-minimal-image-wrap {
	position: relative;
	flex: 1 1 auto;
	min-height: 0;
	overflow: hidden;
	border-radius: 16px;
}

.nsm-cshow-stack-minimal-image {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	opacity: 0;
	transform: translateY(var(--nsm-cshow-bg-offset, 40px)) scale(1);
	transition-property: opacity, transform;
	transition-timing-function: cubic-bezier(0.16, 0.84, 0.44, 1);
	transition-duration: var(--nsm-cshow-bg-duration, 0.9s);
	transition-delay: var(--nsm-cshow-bg-delay, 0.1s);
	will-change: transform, opacity;
}

.nsm-cshow-stack-item.nsm-in-view .nsm-cshow-stack-minimal-image {
	opacity: 1;
	transform: translateY(0) scale(1);
}

.nsm-cshow-no-bg-reveal .nsm-cshow-stack-minimal-image {
	opacity: 1;
	transform: translateY(0) scale(1);
	transition: transform var(--nsm-cshow-hover-duration, 0.9s) ease;
}

.nsm-cshow-stack-card-minimal:hover .nsm-cshow-stack-minimal-image {
	transform: translateY(0) scale(var(--nsm-cshow-hover-scale, 1.06));
	transition-duration: var(--nsm-cshow-hover-duration, 0.9s);
	transition-delay: var(--nsm-cshow-hover-delay, 0.4s);
}

/* ---------------------------------------------------------
 * Auto Slider sections
 * ------------------------------------------------------- */

.nsm-cshow-slider {
	position: relative;
	width: 100%;
	padding: 40px 0;
}

.nsm-cshow-slider-viewport {
	position: relative;
	overflow: hidden;
	/* Full-bleed - spans the whole widget width, no side padding. The
	   continuous marquee track is longer than this (it always contains two
	   full card sets) and scrolls through it, so "Visible Cards" no longer
	   needs to define the viewport's own width the way a paged slider did. */
	width: 100%;
}

.nsm-cshow-slider[data-drag="1"] .nsm-cshow-slider-viewport {
	cursor: grab;
	touch-action: pan-y;
}

.nsm-cshow-slider.is-dragging .nsm-cshow-slider-viewport {
	cursor: grabbing;
}

.nsm-cshow-slider-track {
	display: flex;
	align-items: flex-end;
	gap: var(--nsm-cshow-slider-gap, 20px);
	transition: transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
	will-change: transform;
}

.nsm-cshow-slider.is-dragging .nsm-cshow-slider-track {
	transition: none;
}

.nsm-cshow-slider-card {
	flex: 0 0 auto;
	width: var(--nsm-cshow-slider-card-width, 220px);
	user-select: none;
}

.nsm-cshow-slider-link {
	display: block;
	text-decoration: none;
	color: inherit;
}

.nsm-cshow-slider-image-wrap {
	width: 100%;
	/* Height comes from the widget's Style tab: "Auto Height (Natural
	   Image Ratio)" (default, masonry-style varying heights) leaves this
	   as auto, or "Image Height" sets a fixed px value when that's off. */
	height: auto;
	overflow: hidden;
}

.nsm-cshow-slider-image {
	display: block;
	width: 100%;
	height: auto;
	object-fit: cover;
	transition: transform var(--nsm-cshow-hover-duration, 0.5s) ease;
}

/* Fixed per-position filmstrip heights (desktop/tablet), cycling every 5
   cards - 332 / 190 / 293 / 243 / 214px - instead of each card sizing to
   its own image's aspect ratio ("Auto Height" in the Style tab) or one
   flat height ("Image Height"). nth-child counts by DOM position, so the
   pattern cycles correctly through the JS-cloned duplicate card sets used
   for the continuous marquee loop (see cloneOriginalSet() in
   category-showcase.js) - each clone set starts back at position 1, so
   card 6/11/16/... lines up with card 1's height again, same as the
   original list just continuing. !important because these are meant to
   win regardless of the "Auto Height" / "Image Height" Style tab controls
   above, which only ever produce ONE height rule (auto, or one flat
   value) and can't express a repeating pattern of different heights. */
.nsm-cshow-slider-card:nth-child(5n+1) .nsm-cshow-slider-image-wrap { height: 332px !important; }
.nsm-cshow-slider-card:nth-child(5n+2) .nsm-cshow-slider-image-wrap { height: 190px !important; }
.nsm-cshow-slider-card:nth-child(5n+3) .nsm-cshow-slider-image-wrap { height: 293px !important; }
.nsm-cshow-slider-card:nth-child(5n+4) .nsm-cshow-slider-image-wrap { height: 243px !important; }
.nsm-cshow-slider-card:nth-child(5n) .nsm-cshow-slider-image-wrap { height: 214px !important; }

.nsm-cshow-slider-card .nsm-cshow-slider-image {
	height: 100% !important;
	object-fit: cover !important;
}

.nsm-cshow-slider-card:hover .nsm-cshow-slider-image {
	transform: scale(var(--nsm-cshow-slider-hover-scale, 1.05));
}

.nsm-cshow-slider-caption {
	margin: 12px 0 0;
}

.nsm-cshow-slider-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: none;
	border-radius: 50%;
	cursor: pointer;
	padding: 0;
	font-family: inherit;
	z-index: 4;
	transition: background-color 0.25s ease, color 0.25s ease;
}

.nsm-cshow-slider-arrow.is-disabled {
	opacity: 0.35;
	pointer-events: none;
}

.nsm-cshow-slider-arrow-prev {
	left: 0;
}

.nsm-cshow-slider-arrow-next {
	right: 0;
}

.nsm-cshow-slider-arrow svg,
.nsm-cshow-slider-arrow i {
	width: 1em;
	font-size: 16px;
}

@media (prefers-reduced-motion: reduce) {
	.nsm-cshow-stack-bg-image,
	.nsm-cshow-slider-track,
	.nsm-cshow-slider-image {
		transition: none !important;
	}

	.nsm-cshow-stack-bg-image {
		opacity: 1 !important;
		transform: translateY(0) scale(1) !important;
	}

	.nsm-cshow-stack-card:hover .nsm-cshow-stack-bg-image {
		transform: translateY(0) scale(1) !important;
	}
}

/* Mobile Image Field (acf_image_mobile_field) - optional per-card override
   used across all three layouts (Stack, Stack Minimal, Auto Slider). Only
   present in the markup at all when that field resolved to something (see
   the three render_*_section() methods), so these are hidden-by-default
   here and swapped in at the 767px breakpoint below. */
.nsm-cshow-stack-bg-image-mobile,
.nsm-cshow-stack-minimal-image-mobile,
.nsm-cshow-slider-image-mobile {
	display: none;
}

/* Tablet */
@media (max-width: 1024px) {
	.nsm-cshow-stack-content {
		padding: 32px;
	}

	.nsm-cshow-stack-row {
		gap: 20px;
	}

	.nsm-cshow-stack-label-col {
		flex-basis: 120px;
		max-width: 120px;
	}
}

/* Mobile */
@media (max-width: 767px) {
	/* Swap to the Mobile Image Field's image, when one was set for this
	   card (.nsm-has-mobile-bg only gets added to the wrap element when
	   acf_image_mobile_field resolved to something) - otherwise the
	   desktop image just keeps showing here too, same as always. */
	.nsm-cshow-stack-bg-wrap.nsm-has-mobile-bg .nsm-cshow-stack-bg-image-desktop,
	.nsm-cshow-stack-minimal-image-wrap.nsm-has-mobile-bg .nsm-cshow-stack-minimal-image-desktop,
	.nsm-cshow-slider-image-wrap.nsm-has-mobile-bg .nsm-cshow-slider-image-desktop {
		display: none;
	}

	.nsm-cshow-stack-bg-wrap.nsm-has-mobile-bg .nsm-cshow-stack-bg-image-mobile,
	.nsm-cshow-stack-minimal-image-wrap.nsm-has-mobile-bg .nsm-cshow-stack-minimal-image-mobile,
	.nsm-cshow-slider-image-wrap.nsm-has-mobile-bg .nsm-cshow-slider-image-mobile {
		display: block;
	}

	.nsm-cshow-tabs {
		justify-content: center !important;
	}

	.nsm-cshow-stack-item {
		height: auto;
		min-height: 70vh;
	}

	.nsm-cshow-stack-card {
		inset: 12px;
		border-radius: 16px;
	}

	.nsm-cshow-stack-content {
		padding: 24px 20px;
		/* Matches the base/desktop rule's flex-start (content pinned to the
		   top, image filling the rest below via object-fit: cover) - this
		   used to flip to flex-end here, bottom-packing the
		   label/description/heading instead, which pushed them down
		   against the bottom of a short mobile card. Same bug, same fix,
		   as Projects Stack's mobile content anchor. */
	}

	.nsm-cshow-stack-row {
		flex-direction: column;
		gap: 16px;
	}

	/* Mobile-only visual reorder: heading right after the label, above the
	   description/CTA - matches the reference design (label, then heading,
	   then description). Desktop/tablet keep the row layout (label |
	   description | heading side by side) untouched; this "order" only
	   applies once the row above switches to flex-direction: column. Screen
	   readers/tab order still follow the underlying DOM (label,
	   description, heading), only the visual stacking changes. */
	.nsm-cshow-stack-label-col {
		order: 1;
	}

	.nsm-cshow-stack-heading {
		order: 2;
	}

	.nsm-cshow-stack-description {
		order: 3;
	}

	/* !important because the "Label Column Width" Style control's own
	   selector sets flex-basis from a plain px number tuned for a
	   desktop/tablet ROW layout (flex: 0 0 170px) - that same value
	   doesn't have a sensible mobile equivalent, since flex-basis governs
	   HEIGHT, not width, once the row becomes a column here. Without the
	   override, that 170px was being read as the label box's mobile
	   HEIGHT instead of its old width, leaving a ~150px empty gap below
	   the actual label text before the description started. Same bug,
	   same fix, as Projects Stack's label column. */
	.nsm-cshow-stack-label-col {
		flex: 0 0 auto !important;
		max-width: 100% !important;
	}

	.nsm-cshow-stack-description {
		max-width: 100% !important;
	}

	.nsm-cshow-stack-heading {
		margin-left: 0;
		max-width: 100% !important;
		text-align: left !important;
	}

	/* Mobile gets its own fixed per-position height pattern, cycling every
	   4 cards - 100 / 150 / 120 / 180px - same idea as the desktop 5-value
	   pattern above but with mobile-appropriate (shorter) numbers and its
	   own cycle length. !important for the same reason as the desktop
	   block: needs to win over the "Auto Height" / "Image Height" Style
	   tab controls (see slider_masonry_height / slider_card_height /
	   slider_mobile_image_height in class-category-showcase-widget.php),
	   none of which can express a repeating pattern on their own. */
	.nsm-cshow-slider-card:nth-child(4n+1) .nsm-cshow-slider-image-wrap { height: 100px !important; }
	.nsm-cshow-slider-card:nth-child(4n+2) .nsm-cshow-slider-image-wrap { height: 150px !important; }
	.nsm-cshow-slider-card:nth-child(4n+3) .nsm-cshow-slider-image-wrap { height: 120px !important; }
	.nsm-cshow-slider-card:nth-child(4n) .nsm-cshow-slider-image-wrap { height: 180px !important; }

	.nsm-cshow-slider-card .nsm-cshow-slider-image {
		height: 100% !important;
		object-fit: cover !important;
	}

	.nsm-cshow-slider-arrow-prev {
		left: 4px;
	}

	.nsm-cshow-slider-arrow-next {
		right: 4px;
	}
}
