.dipl_vertical_image_slider .swiper-slide{
	height: auto;
	transition: opacity 0.3s ease, transform 0.3s ease;
}

/* Vertical direction: Swiper computes each slide's height by dividing the swiper-container's own
   clientHeight by Slides Per View, then subtracting Space Between Slides out of that division.
   Without an explicit height here that division runs against an undefined/auto container height
   and bakes a garbage fixed height into every slide. The actual `height`/`overflow: hidden` on
   `.dipl_swiper_wrapper[data-direction="vertical"] .swiper-container` (and the matching
   `.dipl_vis_item_image img` height below) are computed and printed per-instance in
   ModuleStylesTrait.php/module-styles.jsx — card height * slides-per-view + space-between, plus
   Below Image mode's Content Box padding + a fixed ~80px content estimate — rather than shipped
   here as a calc()/custom-property formula. */

/* Equalize Slides Height: leave `.swiper-slide` at its natural `auto` height (never force an
   explicit value here, in Overlay mode or Below Image) so the flex row's default
   `align-items: stretch` does the equalizing — stretch only activates when the item's cross-size
   property literally computes to `auto`; a percentage (even one that can't fully resolve)
   disables it and each slide falls back to its own content height instead. Once stretch gives
   the slide a resolved height, `.dipl_vis_item_image`'s own `height: 100%` (below) already fills
   it in Overlay mode by default — Below Image needs its own override, see further down. */

.dipl_vis_item_image{
	position: relative;
	overflow: hidden;
	width: 100%;
	height: 100%;
}
.dipl_vis_item_image img{
	width: 100%;
	object-fit: cover;
	display: block;
}
.dipl_vis_item_text{
	width: 100%;
}
.dipl_vis_item_icon{
	display: block;
	margin-bottom: 8px;
}
.dipl_vis_item_title{
	margin: 0 0 4px;
}
.dipl_vis_item_subtitle{
	margin: 0;
}

/* Content Box — `.dipl_vis_item_text_inner` wraps the icon/title/subtitle and carries the
   user-configurable Spacing/Background (see the "Content Box" settings group); `.dipl_vis_item_text`
   stays a plain, unstyled positioning shell around it. In Below Image mode the inner box spans
   the full card width (a normal text block under the image); in Overlay mode it's left to size
   to its own content (a "badge" floating over the image), positioned by the flex alignment on
   the outer shell below. */
.dipl_text_belowImage .dipl_vis_item_text_inner{
	width: 100%;
}

/* Content Position: Below Image (default flow) — `.dipl_vis_item_text` is nested inside
   `.dipl_vis_item_image` (see edit.jsx/RenderCallbackTrait.php) so the same markup works for
   both content positions; here it sits in normal flow after the <img>. The wrapper can't be
   `height: 100%` of the slide here (unlike Overlay mode) — that would leave zero room for the
   text below the image, since the slide's own height is fixed (see ModuleStylesTrait.php).
   So the wrapper is left `auto`; the <img> already carries its own explicit height (also set
   there) regardless of Content Position, so no mode-specific override is needed here any more. */
.dipl_text_belowImage .dipl_vis_item_image{
	height: auto;
}
.dipl_text_belowImage .dipl_vis_item_text{
	position: static;
}

/* Below Image, fixed-height slide (Vertical always; Horizontal when equalized): the slide's own
   height is fixed by the swiper-container's computed height/flex-stretch rather than by its own
   content, so the image+text column has to fill it explicitly instead of staying `auto`-sized —
   otherwise a card whose text is shorter than the estimate leaves a blank gap under it. Image keeps its
   fixed height, text block grows into whatever's left (content centered within it), so the
   Content Box background reaches the bottom of the slide either way. */
[data-direction="vertical"].dipl_text_belowImage .dipl_vis_item_image,
.dipl_text_belowImage .dipl_equal_slide_height .dipl_vis_item_image{
	height: 100%;
	display: flex;
	flex-direction: column;
}
[data-direction="vertical"].dipl_text_belowImage .dipl_vis_item_image img,
.dipl_text_belowImage .dipl_equal_slide_height .dipl_vis_item_image img{
	flex-shrink: 0;
}
[data-direction="vertical"].dipl_text_belowImage .dipl_vis_item_text,
.dipl_text_belowImage .dipl_equal_slide_height .dipl_vis_item_text{
	flex: 1;
	display: flex;
}
[data-direction="vertical"].dipl_text_belowImage .dipl_vis_item_text_inner,
.dipl_text_belowImage .dipl_equal_slide_height .dipl_vis_item_text_inner{
	display: flex;
	flex-direction: column;
	justify-content: center;
}

/* Content Position: Overlay On Hover — `.dipl_vis_item_text` is a child of `.dipl_vis_item_image`
   (which is already `position:relative; overflow:hidden; height:100%`), so `inset:0` pins the
   shell to cover the image exactly. Alignment within it (justify-content/align-items/text-align,
   which position the content box inside the overlay) is set dynamically per-instance from the
   "Overlay Content Position" field — this is just the centered fallback. The shell itself (and
   so its Overlay Background Color tint) is hidden by default and simply cross-fades in on hover
   — independent of which reveal animation is picked for the content box, so the whole-image tint
   always behaves consistently regardless of the "Overlay Animation" style. The content box's own
   reveal animation (`dipl_overlay_anim_*` modifier class below) layers on top of this fade. */
.dipl_text_overlayHover .dipl_vis_item_text{
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	text-align: center;
	opacity: 0;
	transition: opacity 0.35s ease;
	pointer-events: none;
}
.dipl_text_overlayHover .swiper-slide:hover .dipl_vis_item_text{
	opacity: 1;
	pointer-events: auto;
}

/* Overlay Animation: Fade & Scale — the content box fades in while scaling down to its natural
   size. */
.dipl_text_overlayHover.dipl_overlay_anim_fadeScale .dipl_vis_item_text_inner{
	opacity: 0;
	transform: scale(1.06);
	transition: opacity 0.35s ease, transform 0.35s ease;
}
.dipl_text_overlayHover.dipl_overlay_anim_fadeScale .swiper-slide:hover .dipl_vis_item_text_inner{
	opacity: 1;
	transform: scale(1);
}

/* Overlay Animation: Slide Up — the content box fades in while sliding up from the bottom edge. */
.dipl_text_overlayHover.dipl_overlay_anim_slideUp .dipl_vis_item_text_inner{
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.35s ease, transform 0.35s ease;
}
.dipl_text_overlayHover.dipl_overlay_anim_slideUp .swiper-slide:hover .dipl_vis_item_text_inner{
	opacity: 1;
	transform: translateY(0);
}

/* Overlay Animation: Image Zoom + Overlay — the image itself slowly zooms while the content box
   fades in on top of it. `overflow: hidden` on `.dipl_vis_item_image` clips the zoomed image to
   the card's bounds/border-radius. */
.dipl_text_overlayHover.dipl_overlay_anim_zoomOverlay .dipl_vis_item_image img{
	transition: transform 0.6s ease;
}
.dipl_text_overlayHover.dipl_overlay_anim_zoomOverlay .swiper-slide:hover .dipl_vis_item_image img{
	transform: scale(1.08);
}
.dipl_text_overlayHover.dipl_overlay_anim_zoomOverlay .dipl_vis_item_text_inner{
	opacity: 0;
	transition: opacity 0.35s ease;
}
.dipl_text_overlayHover.dipl_overlay_anim_zoomOverlay .swiper-slide:hover .dipl_vis_item_text_inner{
	opacity: 1;
}

/* Arrow position: Vertical Inside / Vertical Outside — same mechanism as the existing
   Inside/Outside options (which only reposition left/right), mirrored onto top/bottom so Prev
   sits above the slider and Next sits below it. */
.dipl_vertical_image_slider .dipl_arrows_vertical_inside .swiper-button-prev,
.dipl_vertical_image_slider .dipl_arrows_vertical_inside .swiper-button-next,
.dipl_vertical_image_slider .dipl_arrows_vertical_outside .swiper-button-prev,
.dipl_vertical_image_slider .dipl_arrows_vertical_outside .swiper-button-next{
	left: 50%;
	right: auto;
}
.dipl_vertical_image_slider .dipl_arrows_vertical_inside .swiper-button-prev{
	top: 0;
	bottom: auto;
	transform: translateX(-50%);
}
.dipl_vertical_image_slider .dipl_arrows_vertical_inside .swiper-button-next{
	bottom: 0;
	top: auto;
	transform: translateX(-50%);
}
.dipl_vertical_image_slider .dipl_arrows_vertical_outside .swiper-button-prev{
	top: 0;
	bottom: auto;
	transform: translateX(-50%) translateY(calc(-100% - 10px));
}
.dipl_vertical_image_slider .dipl_arrows_vertical_outside .swiper-button-next{
	bottom: 0;
	top: auto;
	transform: translateX(-50%) translateY(calc(100% + 10px));
}
