.xtool-loop-grid__items {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 20px;
}

/* List view, toggled by a paired Loop Toolbar widget (see
   loop-toolbar.js) — the Columns control above writes a genuine
   per-instance grid-template-columns via Elementor's own generated CSS
   (class-loop-grid.php, add_responsive_control('columns')), so this
   needs !important to reliably win regardless of stylesheet load order.
   Only ever reflows the container's own column count — it never touches
   whatever card markup a Loop Item template itself renders. Column count
   is configurable per Toolbar instance (its own "List View Columns"
   control, default 1) via a CSS custom property set right before this
   class is toggled on; a Loop Grid with no paired Toolbar (or one still
   on an older version without the control) safely falls back to 1. */
.xtool-loop-grid__items.xtool-loop-grid__items--list {
	grid-template-columns: repeat(var(--xtool-loop-list-columns, 1), 1fr) !important;
}

.xtool-loop-grid__item {
	min-width: 0;
}

/* Same root-cause class as the carousel fix below (see its own comment for
   the full explanation) — the plain grid layout above needed its own copy
   of this rule too. It was only ever added for .xtool-loop-grid__swiper
   .swiper-slide, so a Loop Grid used in plain grid mode (not carousel)
   was still exposed to the exact same bug: reported live as a video widget
   nested in a grid-mode Loop Item losing its own height specifically on
   mobile, with the card's own absolutely-positioned caption/button overlay
   (a common "text over video" Loop Item design) then spilling upward past
   its collapsed parent into whatever content sits above the grid. */
.xtool-loop-grid__items .xtool-loop-grid__item > * {
	width: 100%;
}

/* Carousel layout — .xtool-loop-grid__swiper is the actual Swiper root;
   each item renders as a plain .swiper-slide instead of
   .xtool-loop-grid__item (see Loop_Grid::render_items()'s $item_class
   param), so none of the grid rules above apply to it. */
.xtool-loop-grid__swiper .swiper-wrapper {
	align-items: stretch;
}

/* Forces each slide's own rendered Loop Item document (the direct child
   Elementor prints inside .swiper-slide) to fill the slide's full width —
   same root-cause class as the Container Carousel fix elsewhere in this
   plugin: without this, whatever the Loop Item's own outermost Container
   has set for Align Items governs whether its content stretches to the
   slide's real width or shrinks to its own content size, and a widget
   inside that depends on a definite width to size itself (e.g. anything
   using CSS aspect-ratio, like a video frame) can end up much narrower —
   or on some viewport widths, effectively collapsed — than the slide
   actually is. Reported live: a video widget nested in a Loop Item card
   losing its height specifically on mobile, cards visibly overlapping. */
.xtool-loop-grid__swiper .swiper-slide > * {
	width: 100%;
}

.xtool-loop-grid__swiper .swiper-slide {
	height: auto;
	min-width: 0;
}

.xtool-loop-grid__swiper .swiper-button-next,
.xtool-loop-grid__swiper .swiper-button-prev {
	width: 40px;
	height: 40px;
	background: #fff;
	border-radius: 50%;
	box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
	color: #1a1814;
	/* Fine-Tune Position nudge - safe as a plain transform here since
	   Swiper's own default "Sides" positioning never uses transform itself
	   (just top/left/right/margin-top), so this can't collide with it.
	   "Bottom Center" mode below needs its OWN transform for horizontal
	   centering, so each of its 3 alignment variants folds these same
	   custom properties into its own transform instead of relying on this
	   base rule. */
	transform: translate(var(--xtool-loop-arrows-nudge-x, 0px), var(--xtool-loop-arrows-nudge-y, 0px));
}

/* A custom (uploaded-SVG) icon has no font-size to inherit the way a
   font-icon <i> tag already does - sized in em units here so the SAME
   "Icon Size" control (font-size on the button itself) governs both icon
   types, matching the identical pairing already proven on Carousel/
   Container Carousel/Logo Carousel. */
.xtool-loop-grid__swiper .swiper-button-next svg,
.xtool-loop-grid__swiper .swiper-button-prev svg {
	width: 1em;
	height: 1em;
	fill: currentColor;
}

/* Vertical Alignment (Sides mode only) - Top/Bottom sit just inside the
   slides' own top/bottom edge (a small fixed 10px inset, further adjustable
   via the always-available Fine-Tune Offset); "Middle" (the default, no
   modifier class) is left completely untouched, i.e. Swiper's own stock
   top:50%/margin-top:-half-height centering. */
.xtool-loop-grid__swiper--arrows-valign-top .swiper-button-next,
.xtool-loop-grid__swiper--arrows-valign-top .swiper-button-prev {
	top: 10px;
	margin-top: 0;
}

.xtool-loop-grid__swiper--arrows-valign-bottom .swiper-button-next,
.xtool-loop-grid__swiper--arrows-valign-bottom .swiper-button-prev {
	top: auto;
	bottom: 10px;
	margin-top: 0;
}

/* "Bottom Center" arrow position (Default layout only - Bottom Bar has its
   own separate row/positioning already) - switches both buttons off
   Swiper's own default vertically-centered/edge-anchored positioning onto a
   row below the slides instead. Same containing-box reasoning as Container
   Carousel's identical fix: .xtool-loop-grid__swiper has overflow:hidden
   (required for horizontal slide-clipping), so a button positioned below
   the slides' own bottom edge would otherwise be clipped to invisible -
   padding-bottom here carves out real, unclipped room since bottom:0 on an
   absolutely positioned child lands at the padding edge, not the slide
   content's own edge.

   Computed from Distance From Bottom + Arrows Size (both written as custom
   properties by their own controls) rather than a fixed value - an earlier
   version hardcoded this at a flat 80px (matching Container Carousel's own
   identical, ALSO-fixed reservation), which reliably avoided clipping but
   left a large, visibly dead blank gap below the pagination/arrows row
   whenever the user's actual chosen offset+size added up to noticeably
   less than 80px (reported live via screenshot). The +10px is a small
   breathing-room buffer past the arrows' own visual edge, not tied to any
   control. Fine-Tune's own Vertical Offset (a transform, not a layout
   property) isn't factored in here - nudging arrows further up via that
   control can leave a little of this reserved space unused below them,
   an accepted, minor tradeoff of a nudge that has no effect on box sizing
   by definition. */
.xtool-loop-grid__swiper--arrows-bottom-center {
	padding-bottom: calc(var(--xtool-loop-arrows-bottom, 20px) + var(--xtool-loop-arrows-size, 40px) + 10px);
}

.xtool-loop-grid__swiper--arrows-bottom-center .swiper-button-next,
.xtool-loop-grid__swiper--arrows-bottom-center .swiper-button-prev {
	top: auto;
	margin-top: 0;
}

/* Horizontal Alignment within Bottom Center - "Center" (default, no
   modifier class) anchors both buttons at the row's own horizontal
   midpoint (left:50%) and centers the pair around it via transform.
   "Left"/"Right" instead anchor the pair flush against that edge of the
   row (left:0 / right:0) - an edge anchor (0%, not a fixed px value) is
   what keeps this correctly positioned across every breakpoint on its own,
   unlike a pure px Fine-Tune offset which would need re-tuning per
   breakpoint as the row's own width changes. All 3 read the SAME
   --xtool-loop-arrows-gap custom property (written by the Gap Between
   Buttons control) and --xtool-loop-arrows-nudge-x/-y (Fine-Tune Offset) -
   the gap/nudge controls only ever write those custom properties, never a
   'transform' directly, since two different Elementor controls both
   targeting 'transform' on the same selector would just have the
   later-registered one silently overwrite the earlier one instead of
   composing. */
.xtool-loop-grid__swiper--arrows-bottom-center:not(.xtool-loop-grid__swiper--arrows-halign-left):not(.xtool-loop-grid__swiper--arrows-halign-right) .swiper-button-next,
.xtool-loop-grid__swiper--arrows-bottom-center:not(.xtool-loop-grid__swiper--arrows-halign-left):not(.xtool-loop-grid__swiper--arrows-halign-right) .swiper-button-prev {
	left: 50%;
	right: auto;
}

.xtool-loop-grid__swiper--arrows-bottom-center:not(.xtool-loop-grid__swiper--arrows-halign-left):not(.xtool-loop-grid__swiper--arrows-halign-right) .swiper-button-prev {
	transform: translateX(calc(-100% - var(--xtool-loop-arrows-gap, 12px) / 2 + var(--xtool-loop-arrows-nudge-x, 0px))) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

.xtool-loop-grid__swiper--arrows-bottom-center:not(.xtool-loop-grid__swiper--arrows-halign-left):not(.xtool-loop-grid__swiper--arrows-halign-right) .swiper-button-next {
	transform: translateX(calc(var(--xtool-loop-arrows-gap, 12px) / 2 + var(--xtool-loop-arrows-nudge-x, 0px))) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

.xtool-loop-grid__swiper--arrows-halign-left .swiper-button-next,
.xtool-loop-grid__swiper--arrows-halign-left .swiper-button-prev {
	left: 0;
	right: auto;
}

.xtool-loop-grid__swiper--arrows-halign-left .swiper-button-prev {
	transform: translateX(var(--xtool-loop-arrows-nudge-x, 0px)) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

.xtool-loop-grid__swiper--arrows-halign-left .swiper-button-next {
	transform: translateX(calc(100% + var(--xtool-loop-arrows-gap, 12px) + var(--xtool-loop-arrows-nudge-x, 0px))) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

.xtool-loop-grid__swiper--arrows-halign-right .swiper-button-next,
.xtool-loop-grid__swiper--arrows-halign-right .swiper-button-prev {
	left: auto;
	right: 0;
}

.xtool-loop-grid__swiper--arrows-halign-right .swiper-button-next {
	transform: translateX(var(--xtool-loop-arrows-nudge-x, 0px)) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

.xtool-loop-grid__swiper--arrows-halign-right .swiper-button-prev {
	transform: translateX(calc(-100% - var(--xtool-loop-arrows-gap, 12px) + var(--xtool-loop-arrows-nudge-x, 0px))) translateY(var(--xtool-loop-arrows-nudge-y, 0px));
}

/* Kills Swiper's own default pseudo-icon chevron — without this, the
   custom arrow_prev_icon/arrow_next_icon rendered inside the button
   (see render_carousel()) would double up with Swiper's built-in one,
   same fix already needed on Carousel/Container Carousel/Logo Carousel. */
.xtool-loop-grid__swiper .swiper-button-next:after,
.xtool-loop-grid__swiper .swiper-button-prev:after {
	content: none;
	font-size: 14px;
}

.xtool-loop-grid__swiper .swiper-pagination {
	position: relative;
}

/* Navigation Layout: Bottom Bar - requested directly with a reference
   screenshot (a progress-bar style pagination sitting bottom-left, round
   Prev/Next buttons bottom-right, both on one row below the grid). Only
   the LAYOUT changes here - Swiper's own real pagination/navigation
   mechanisms are completely untouched, this just repositions where the
   same elements sit via plain flexbox instead of Swiper's own default
   absolute-positioned-on-the-sides arrow placement. */
.xtool-loop-grid--nav-bottom-bar .xtool-loop-grid__nav-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-top: 16px;
}

.xtool-loop-grid--nav-bottom-bar .swiper-pagination {
	position: relative;
	margin-top: 0;
	flex: 1 1 auto;
	text-align: left;
}

.xtool-loop-grid--nav-bottom-bar .xtool-loop-grid__nav-arrows {
	display: flex;
	align-items: center;
	gap: 8px;
	flex-shrink: 0;
}

/* Swiper's own base CSS makes .swiper-button-next/-prev position:absolute
   (anchored to the slider's own left/right edges) by default - overridden
   back to a plain, normal-flow flex item here so the two buttons sit
   inline inside .xtool-loop-grid__nav-arrows instead. */
.xtool-loop-grid--nav-bottom-bar .swiper-button-prev,
.xtool-loop-grid--nav-bottom-bar .swiper-button-next {
	position: static;
	top: auto;
	left: auto;
	right: auto;
	margin: 0;
}

/* Progress Bar pagination type is ALSO position:absolute by Swiper's own
   default (sized/pinned via its own `.swiper-pagination-progressbar` +
   `.swiper-pagination-horizontal` classes, which Swiper adds directly to
   the .swiper-pagination element regardless of DOM nesting depth) -
   overridden back to a normal, in-flow flex item so it sits correctly
   inside .xtool-loop-grid__nav-bar's own row instead of pinning itself to
   whatever positioned ancestor happens to be further up the page. */
.xtool-loop-grid--nav-bottom-bar .swiper-pagination.swiper-pagination-progressbar {
	position: relative;
	width: auto;
	height: 4px;
	left: auto;
	top: auto;
}

.xtool-loop-grid__swiper .swiper-pagination-bullet {
	background: #d4cec7;
	opacity: 1;
}

.xtool-loop-grid__swiper .swiper-pagination-bullet-active {
	background: #1c1c1e;
}

.xtool-loop-grid__empty,
.xtool-loop-grid__notice {
	padding: 30px;
	text-align: center;
	background: #F2EDE7;
	border: 1px dashed #D4CEC7;
	border-radius: 8px;
	color: #8A8680;
	font-size: 13px;
}

.xtool-loop-grid__more-wrap {
	display: flex;
	justify-content: center;
	margin-top: 28px;
}

.xtool-loop-grid__more-btn {
	background: #1C1C1E;
	color: #fff;
	border: none;
	padding: 11px 28px;
	border-radius: 6px;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	transition: opacity .15s;
}

.xtool-loop-grid__more-btn:hover {
	opacity: .85;
}

.xtool-loop-grid__more-btn[disabled] {
	opacity: .5;
	cursor: default;
}

.xtool-loop-grid__more-btn.is-loading {
	opacity: .6;
	cursor: wait;
}
