/* =============================================================================
   Advanced Gallery for Elementor – Frontend Styles
   ============================================================================= */

/* ── Variables & base ─────────────────────────────────────────────────────── */
.age-gallery {
	--age-gap: 10px;
	--age-columns: 3;
	--age-columns-tablet: 2;
	--age-columns-mobile: 1;
	--age-transition-duration: 400ms;
	width: 100%;
	box-sizing: border-box;
}

.age-gallery *,
.age-gallery *::before,
.age-gallery *::after {
	box-sizing: border-box;
}

/* ── Grid layout ─────────────────────────────────────────────────────────── */
.age-gallery-grid {
	display: grid;
	grid-template-columns: repeat(var(--age-columns), 1fr);
	gap: var(--age-gap);
}

@media (max-width: 1024px) {
	.age-gallery-grid {
		grid-template-columns: repeat(var(--age-columns-tablet), 1fr);
	}
}

@media (max-width: 767px) {
	.age-gallery-grid {
		grid-template-columns: repeat(var(--age-columns-mobile), 1fr);
	}
}

/* Aspect ratio helpers for grid */
.age-gallery-grid .age-gallery-item.age-ratio-1-1  .age-gallery-item-inner { aspect-ratio: 1 / 1; }
.age-gallery-grid .age-gallery-item.age-ratio-4-3  .age-gallery-item-inner { aspect-ratio: 4 / 3; }
.age-gallery-grid .age-gallery-item.age-ratio-3-2  .age-gallery-item-inner { aspect-ratio: 3 / 2; }
.age-gallery-grid .age-gallery-item.age-ratio-16-9 .age-gallery-item-inner { aspect-ratio: 16 / 9; }
.age-gallery-grid .age-gallery-item.age-ratio-2-1  .age-gallery-item-inner { aspect-ratio: 2 / 1; }
.age-gallery-grid .age-gallery-item.age-ratio-3-4  .age-gallery-item-inner { aspect-ratio: 3 / 4; }
.age-gallery-grid .age-gallery-item.age-ratio-9-16 .age-gallery-item-inner { aspect-ratio: 9 / 16; }

/* ── Masonry layout (CSS columns) ────────────────────────────────────────── */
.age-gallery-masonry {
	column-count: var(--age-columns);
	column-gap: var(--age-gap);
	column-fill: balance;
}

@media (max-width: 1024px) {
	.age-gallery-masonry {
		column-count: var(--age-columns-tablet);
	}
}

@media (max-width: 767px) {
	.age-gallery-masonry {
		column-count: var(--age-columns-mobile);
	}
}

.age-gallery-masonry .age-gallery-item {
	break-inside: avoid;
	margin-bottom: var(--age-gap);
	display: block;
	width: 100%;
}

/* ── Justified layout ────────────────────────────────────────────────────── */
.age-gallery-justified {
	display: flex;
	flex-wrap: wrap;
	gap: var(--age-gap);
	width: 100%;
}

.age-gallery-justified .age-gallery-item {
	flex: 1 1 auto;
	min-width: 120px;
	height: 200px;
	overflow: hidden;
}

/* When JS positions items absolutely (library loaded) */
.age-gallery-justified.age-justified-abs {
	display: block;
	position: relative;
}

.age-gallery-justified.age-justified-abs .age-gallery-item {
	position: absolute;
	flex: none;
	min-width: 0;
}

/* ── Item inner ─────────────────────────────────────────────────────────── */
.age-gallery-item {
	min-width: 0;
}

a.age-gallery-item-inner,
div.age-gallery-item-inner {
	position: relative;
	overflow: hidden;
	display: block;
	width: 100%;
	height: 100%;
	background: #e9e9e9;
	text-decoration: none;
	color: inherit;
}

a.age-gallery-item-inner {
	cursor: pointer;
}

div.age-gallery-item-inner {
	cursor: default;
}

/* ── Images ─────────────────────────────────────────────────────────────── */
.age-gallery-item-inner img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Primary image */
.age-gallery-item-inner img.age-primary-img {
	position: relative;
	z-index: 1;
}

/* Hover image – sits on top, hidden by default */
.age-gallery-item-inner img.age-hover-img {
	position: absolute;
	inset: 0;
	z-index: 2;
	opacity: 0;
}

/* ── Text overlay ────────────────────────────────────────────────────────── */
.age-hover-text {
	position: absolute;
	inset: 0;
	z-index: 3;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 16px;
	background: rgba(0, 0, 0, 0.55);
	color: #fff;
	opacity: 0;
	pointer-events: none;
}

.age-hover-text-inner {
	text-align: center;
	pointer-events: auto;
}

/* ── Hover transitions (only once gallery is ready – prevents load flash) ─── */
/*
 * Without .age-ready, all transition properties are suppressed.
 * .age-ready is added by JS after the first rAF cycle, which guarantees
 * the browser has already painted the initial state (opacity: 0 on hover
 * elements). This prevents the "hover image briefly visible on load" bug
 * caused by CSS transitions firing from the browser's implicit "from" state.
 */
.age-gallery.age-ready .age-gallery-item-inner img.age-primary-img {
	transition: transform var(--age-transition-duration) ease,
	            opacity  var(--age-transition-duration) ease,
	            filter   var(--age-transition-duration) ease;
}

.age-gallery.age-ready .age-gallery-item-inner img.age-hover-img {
	transition: opacity  var(--age-transition-duration) ease,
	            transform var(--age-transition-duration) ease;
}

.age-gallery.age-ready .age-hover-text {
	transition: opacity var(--age-transition-duration) ease;
}

/* Show text overlay on hover */
.age-gallery-item-inner:hover .age-hover-text,
.age-gallery-item-inner.age-hovered .age-hover-text {
	opacity: 1;
}

/* ── Item link ───────────────────────────────────────────────────────────── */
.age-item-link {
	display: block;
	width: 100%;
	height: 100%;
}

/* ============================================================
   Hover image transitions (per data-transition attribute)
   ============================================================ */

/* --- Fade --- */
.age-gallery-item[data-transition="fade"] .age-hover-img {
	opacity: 0;
	transform: none;
}
.age-gallery.age-ready .age-gallery-item[data-transition="fade"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
}

/* --- Slide Up --- */
.age-gallery-item[data-transition="slide-up"] .age-hover-img {
	opacity: 0;
	transform: translateY(100%);
}
.age-gallery.age-ready .age-gallery-item[data-transition="slide-up"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: translateY(0);
}

/* --- Slide Down --- */
.age-gallery-item[data-transition="slide-down"] .age-hover-img {
	opacity: 0;
	transform: translateY(-100%);
}
.age-gallery.age-ready .age-gallery-item[data-transition="slide-down"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: translateY(0);
}

/* --- Slide Left --- */
.age-gallery-item[data-transition="slide-left"] .age-hover-img {
	opacity: 0;
	transform: translateX(100%);
}
.age-gallery.age-ready .age-gallery-item[data-transition="slide-left"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: translateX(0);
}

/* --- Slide Right --- */
.age-gallery-item[data-transition="slide-right"] .age-hover-img {
	opacity: 0;
	transform: translateX(-100%);
}
.age-gallery.age-ready .age-gallery-item[data-transition="slide-right"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: translateX(0);
}

/* --- Zoom In (hover image zooms in from small) --- */
.age-gallery-item[data-transition="zoom-in"] .age-hover-img {
	opacity: 0;
	transform: scale(0.7);
}
.age-gallery.age-ready .age-gallery-item[data-transition="zoom-in"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: scale(1);
}

/* --- Zoom Out (hover image starts large) --- */
.age-gallery-item[data-transition="zoom-out"] .age-hover-img {
	opacity: 0;
	transform: scale(1.3);
}
.age-gallery.age-ready .age-gallery-item[data-transition="zoom-out"] .age-gallery-item-inner:hover .age-hover-img {
	opacity: 1;
	transform: scale(1);
}

/* --- Flip Horizontal --- */
.age-gallery-item[data-transition="flip-h"] .age-gallery-item-inner {
	perspective: 800px;
}
.age-gallery-item[data-transition="flip-h"] img.age-primary-img {
	backface-visibility: hidden;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-h"] img.age-primary-img {
	transition: transform var(--age-transition-duration) ease;
}
.age-gallery-item[data-transition="flip-h"] .age-hover-img {
	opacity: 1;
	transform: rotateY(180deg);
	backface-visibility: hidden;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-h"] .age-hover-img {
	transition: transform var(--age-transition-duration) ease;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-h"] .age-gallery-item-inner:hover img.age-primary-img {
	transform: rotateY(-180deg);
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-h"] .age-gallery-item-inner:hover .age-hover-img {
	transform: rotateY(0deg);
}

/* --- Flip Vertical --- */
.age-gallery-item[data-transition="flip-v"] .age-gallery-item-inner {
	perspective: 800px;
}
.age-gallery-item[data-transition="flip-v"] img.age-primary-img {
	backface-visibility: hidden;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-v"] img.age-primary-img {
	transition: transform var(--age-transition-duration) ease;
}
.age-gallery-item[data-transition="flip-v"] .age-hover-img {
	opacity: 1;
	transform: rotateX(180deg);
	backface-visibility: hidden;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-v"] .age-hover-img {
	transition: transform var(--age-transition-duration) ease;
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-v"] .age-gallery-item-inner:hover img.age-primary-img {
	transform: rotateX(-180deg);
}
.age-gallery.age-ready .age-gallery-item[data-transition="flip-v"] .age-gallery-item-inner:hover .age-hover-img {
	transform: rotateX(0deg);
}

/* ── Elementor lightbox navigation arrows ────────────────────────────────── */
.elementor-lightbox .elementor-swiper-button-prev,
.elementor-lightbox .elementor-swiper-button-next {
	opacity: 1;
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 35px;
	height: 35px;
}

.elementor-lightbox .elementor-swiper-button-prev {
	left: 20px;
}

.elementor-lightbox .elementor-swiper-button-next {
	right: 20px;
}

.elementor-lightbox .elementor-swiper-button-prev i,
.elementor-lightbox .elementor-swiper-button-next i {
	font-size: 25px;
	line-height: 1;
}

.elementor-lightbox .elementor-swiper-button-prev svg,
.elementor-lightbox .elementor-swiper-button-next svg {
	width: 25px;
	height: 25px;
}

/* ── Lazy load placeholder ───────────────────────────────────────────────── */
/*
 * IMPORTANT: rules are scoped to img.age-primary-img only.
 *
 * Applying the ageFadeIn animation to .age-hover-img would override its
 * CSS `opacity: 0` for the animation's duration, making hover images briefly
 * visible while loading — exactly the "hover image appears before main image"
 * flash. Hover images swap their src silently; their opacity is fully
 * controlled by the hover-state rules further down.
 */
img.age-primary-img.age-lazy:not(.age-lazy-loaded) {
	background: #e9e9e9;
	filter: blur(4px);
}

img.age-primary-img.age-lazy.age-lazy-loaded {
	filter: none;
	animation: ageFadeIn 0.3s ease;
}

/* Hover image: just clear the blur placeholder, no opacity animation */
img.age-hover-img.age-lazy-loaded {
	filter: none;
}

@keyframes ageFadeIn {
	from { opacity: 0; }
	to   { opacity: 1; }
}

/* ── Justified: when library positions absolutely, heights come from JS ── */
.age-gallery-justified.age-justified-abs .age-gallery-item {
	height: auto;
}

/* ── Custom Columns layout ───────────────────────────────────────────────── */
/*
 * Desktop: flex-row — PHP defines exactly which images go into which column,
 * giving the editor full positional control.
 *
 * Tablet / Mobile: the PHP-rendered column divs "dissolve" via display:contents
 * so their children flow as a flat list into CSS column-count columns.
 * This avoids the orphan-column problem caused by flex-wrap when the number of
 * PHP columns (e.g. 3) doesn't divide evenly into the responsive column count
 * (e.g. 2). column-count redistributes items cleanly regardless of how many
 * desktop columns were defined.
 */
.age-gallery-columns {
	display: flex;
	flex-direction: row;
	align-items: flex-start;
	gap: var(--age-gap);
	width: 100%;
}

.age-gallery-col {
	flex: 1 1 0%;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: var(--age-gap);
}

/* Items inside custom columns: full width, natural image height */
.age-gallery-col .age-gallery-item {
	width: 100%;
}

.age-gallery-col .age-gallery-item-inner {
	height: auto;
}

.age-gallery-col .age-gallery-item-inner img.age-primary-img {
	height: auto;
	object-fit: cover;
}

/* ── Tablet: dissolve column divs → CSS column-count reflow ─────────────── */
@media (max-width: 1024px) {
	.age-gallery-columns {
		display: block;
		column-count: var(--age-columns-tablet);
		column-gap: var(--age-gap);
	}

	/* display:contents removes the col div from layout — its children
	   flow directly into the column-count columns above */
	.age-gallery-col {
		display: contents;
	}

	.age-gallery-col .age-gallery-item {
		break-inside: avoid;
		margin-bottom: var(--age-gap);
		display: block;
		width: 100%;
	}

	.age-gallery-col .age-gallery-item-inner {
		height: auto;
	}
}

/* ── Mobile: same dissolve but with mobile column count ─────────────────── */
@media (max-width: 767px) {
	.age-gallery-columns {
		column-count: var(--age-columns-mobile);
	}
}


/* =============================================================================
   Entry Animations
   =============================================================================
   How it works:
   – PHP adds class `age-entry-pending` when an animation is configured.
     This hides items (opacity:0 or clip-path) immediately in CSS,
     preventing a flash before JS initialises.
   – JS adds `age-entry-{type}` to each item (with an inline animation-delay
     for stagger). The animation's fill-mode:both keeps the item in the `from`
     state during its delay, then plays into the `to` state.
   – The --age-entry-duration and --age-entry-easing CSS vars are set inline
     per item from JS so each animation auto-picks the user's settings.
   ============================================================================= */

/* Default per-item animation vars (overridden inline by JS) */
.age-gallery-item {
	--age-entry-duration: 700ms;
	--age-entry-easing:   ease-out;
}

/* ── Pending state: items are invisible until animation fires ──────────────── */
.age-gallery-item.age-entry-pending {
	opacity: 0;
}

/* Reveal variants use clip-path instead of opacity so the reveal sweeps in */
.age-gallery[data-entry-animation="reveal-up"]    .age-gallery-item.age-entry-pending { opacity: 1; clip-path: inset(0 0 100% 0); }
.age-gallery[data-entry-animation="reveal-down"]  .age-gallery-item.age-entry-pending { opacity: 1; clip-path: inset(100% 0 0 0); }
.age-gallery[data-entry-animation="reveal-left"]  .age-gallery-item.age-entry-pending { opacity: 1; clip-path: inset(0 100% 0 0); }
.age-gallery[data-entry-animation="reveal-right"] .age-gallery-item.age-entry-pending { opacity: 1; clip-path: inset(0 0 0 100%); }

/* ── Shared properties for all active entry animation classes ─────────────── */
.age-gallery-item[class*=" age-entry-"]:not(.age-entry-pending),
.age-gallery-item[class^="age-entry-"]:not(.age-entry-pending) {
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* =============================================================================
   Keyframes – Fade
   ============================================================================= */

@keyframes ageEntryFadeIn {
	from { opacity: 0; }
	to   { opacity: 1; }
}
.age-gallery-item.age-entry-fade-in {
	animation-name: ageEntryFadeIn;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Fade In Up ── */
@keyframes ageEntryFadeInUp {
	from { opacity: 0; transform: translateY(32px); }
	to   { opacity: 1; transform: translateY(0); }
}
.age-gallery-item.age-entry-fade-in-up {
	animation-name: ageEntryFadeInUp;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Fade In Down ── */
@keyframes ageEntryFadeInDown {
	from { opacity: 0; transform: translateY(-32px); }
	to   { opacity: 1; transform: translateY(0); }
}
.age-gallery-item.age-entry-fade-in-down {
	animation-name: ageEntryFadeInDown;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Fade In Left (enters from the right) ── */
@keyframes ageEntryFadeInLeft {
	from { opacity: 0; transform: translateX(32px); }
	to   { opacity: 1; transform: translateX(0); }
}
.age-gallery-item.age-entry-fade-in-left {
	animation-name: ageEntryFadeInLeft;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Fade In Right (enters from the left) ── */
@keyframes ageEntryFadeInRight {
	from { opacity: 0; transform: translateX(-32px); }
	to   { opacity: 1; transform: translateX(0); }
}
.age-gallery-item.age-entry-fade-in-right {
	animation-name: ageEntryFadeInRight;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* =============================================================================
   Keyframes – Slide  (larger travel distance than Fade variants)
   ============================================================================= */

/* ── Slide In Up (enters from below) ── */
@keyframes ageEntrySlideInUp {
	from { opacity: 0; transform: translateY(80px); }
	to   { opacity: 1; transform: translateY(0); }
}
.age-gallery-item.age-entry-slide-in-up {
	animation-name: ageEntrySlideInUp;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Slide In Down (enters from above) ── */
@keyframes ageEntrySlideInDown {
	from { opacity: 0; transform: translateY(-80px); }
	to   { opacity: 1; transform: translateY(0); }
}
.age-gallery-item.age-entry-slide-in-down {
	animation-name: ageEntrySlideInDown;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Slide In Left (enters from the right) ── */
@keyframes ageEntrySlideInLeft {
	from { opacity: 0; transform: translateX(80px); }
	to   { opacity: 1; transform: translateX(0); }
}
.age-gallery-item.age-entry-slide-in-left {
	animation-name: ageEntrySlideInLeft;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Slide In Right (enters from the left) ── */
@keyframes ageEntrySlideInRight {
	from { opacity: 0; transform: translateX(-80px); }
	to   { opacity: 1; transform: translateX(0); }
}
.age-gallery-item.age-entry-slide-in-right {
	animation-name: ageEntrySlideInRight;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* =============================================================================
   Keyframes – Reveal (clip-path curtain wipe; no opacity change)
   ============================================================================= */

/* ── Reveal Up (curtain lifts from bottom) ── */
@keyframes ageEntryRevealUp {
	from { clip-path: inset(0 0 100% 0); }
	to   { clip-path: inset(0 0 0% 0); }
}
.age-gallery-item.age-entry-reveal-up {
	animation-name: ageEntryRevealUp;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Reveal Down (curtain drops from top) ── */
@keyframes ageEntryRevealDown {
	from { clip-path: inset(100% 0 0 0); }
	to   { clip-path: inset(0% 0 0 0); }
}
.age-gallery-item.age-entry-reveal-down {
	animation-name: ageEntryRevealDown;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Reveal Left (curtain slides from right) ── */
@keyframes ageEntryRevealLeft {
	from { clip-path: inset(0 100% 0 0); }
	to   { clip-path: inset(0 0% 0 0); }
}
.age-gallery-item.age-entry-reveal-left {
	animation-name: ageEntryRevealLeft;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Reveal Right (curtain slides from left) ── */
@keyframes ageEntryRevealRight {
	from { clip-path: inset(0 0 0 100%); }
	to   { clip-path: inset(0 0 0 0%); }
}
.age-gallery-item.age-entry-reveal-right {
	animation-name: ageEntryRevealRight;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* =============================================================================
   Keyframes – Flip 3D
   Each variant rotates from 90° on the relevant axis so the tile "flips in"
   from that direction. perspective() is applied per-item to avoid overflow.
   ============================================================================= */

/* ── Flip Left (front face enters from the right, rotating left) ── */
@keyframes ageEntryFlipLeft {
	from { opacity: 0; transform: perspective(600px) rotateY(90deg); }
	to   { opacity: 1; transform: perspective(600px) rotateY(0deg); }
}
.age-gallery-item.age-entry-flip-left {
	animation-name: ageEntryFlipLeft;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Flip Right (front face enters from the left, rotating right) ── */
@keyframes ageEntryFlipRight {
	from { opacity: 0; transform: perspective(600px) rotateY(-90deg); }
	to   { opacity: 1; transform: perspective(600px) rotateY(0deg); }
}
.age-gallery-item.age-entry-flip-right {
	animation-name: ageEntryFlipRight;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Flip Up (enters from below, rotating upward) ── */
@keyframes ageEntryFlipUp {
	from { opacity: 0; transform: perspective(600px) rotateX(-90deg); }
	to   { opacity: 1; transform: perspective(600px) rotateX(0deg); }
}
.age-gallery-item.age-entry-flip-up {
	animation-name: ageEntryFlipUp;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}

/* ── Flip Down (enters from above, rotating downward) ── */
@keyframes ageEntryFlipDown {
	from { opacity: 0; transform: perspective(600px) rotateX(90deg); }
	to   { opacity: 1; transform: perspective(600px) rotateX(0deg); }
}
.age-gallery-item.age-entry-flip-down {
	animation-name: ageEntryFlipDown;
	animation-fill-mode: both;
	animation-duration: var(--age-entry-duration);
	animation-timing-function: var(--age-entry-easing);
}
