/**
 * [travel_collage_slider] — collage mosaic plus the marquee it lives in.
 *
 * The movement is a CSS animation on a transform, not a JavaScript per-frame
 * write. That is deliberate: a keyframed transform is handled by the compositor,
 * so it keeps running smoothly while the main thread is busy with Elementor, and
 * pausing is a single `animation-play-state` change rather than cancelling and
 * restarting a rAF loop. Nothing here animates left, margin or width.
 *
 * assets/js/travel-collage.js supplies the numbers this cannot know:
 *   --tcs-distance   the exact pixel width of one original set of groups
 *   --tcs-duration   distance / speed, so speed stays honest in px per second
 *   --tcs-bleed-w    viewport width excluding the scrollbar, for full-width mode
 *   --tcs-bleed-x    how far left to shift to reach the viewport edge
 *
 * The loop is seamless because the JS clones whole groups until the row is at
 * least twice the visible width, and the animation travels exactly
 * --tcs-distance. At 100% the row therefore shows a pixel-identical frame to 0%,
 * so the restart has nothing to hide.
 *
 * There is deliberately no edge fade. A gradient overlay has to be painted in the
 * background's own colour to disappear, so it only ever looked right on white —
 * on the Home page's #F5F7FA section it read as two pale smears, and full width
 * made them screen-wide. The strip now simply runs to the edge, which is what the
 * reference design does.
 *
 * Selector names are unprefixed inside .tcs (.scroll-outer, .track-right,
 * .travel-collage, .collage-item) because that is the agreed structure; the .tcs
 * root scopes them so they cannot leak into the theme or Elementor.
 *
 * @package CustomTours
 */

.tcs {
	/*
	 * These two arrive as an inline style attribute from the shortcode, carrying
	 * its height= and gap= attributes.
	 *
	 * That has one consequence which drives the whole responsive section below: an
	 * inline custom property beats every stylesheet rule, media query or not. So a
	 * breakpoint CANNOT say `--tcs-height: 175px` — the declaration is valid, it
	 * simply loses, silently, at every screen width. The mosaic has to be scaled by
	 * a second variable that is not set inline instead.
	 */
	--tcs-height: 400px;
	--tcs-gap: 20px;

	/*
	 * The responsive multipliers. Breakpoints set these; nothing sets them inline,
	 * so they actually take effect. 1 means "as the shortcode asked for", which is
	 * what desktop gets.
	 *
	 * Scaling rather than replacing also keeps height="600" meaningful: a taller
	 * strip stays proportionally taller on a phone instead of being flattened to
	 * the same fixed number as every other instance.
	 */
	--tcs-scale: 1;
	--tcs-gap-scale: 1;

	/* Not set inline, so these can be plain values per breakpoint. */
	--tcs-cell-gap: 10px;
	--tcs-radius: 14px;

	/* Space between the label rule and the top of the photos. */
	--tcs-label-gap: 30px;

	/* Placeholders until the JS measures. A zero distance means no movement, which
	   is the correct thing to show if the script never runs. */
	--tcs-distance: 0px;
	--tcs-duration: 0s;

	position: relative;
	width: 100%;
}

/* ==========================================================================
   Full width
   ========================================================================== */
/*
 * Edge to edge, without the usual 100vw bug.
 *
 * The common trick is `width: 100vw; margin-left: calc(50% - 50vw)`. It is wrong
 * on desktop: 100vw *includes* the scrollbar, so the element ends up ~15px wider
 * than the visible page and the whole document gains a horizontal scrollbar —
 * exactly the failure this component must never cause.
 *
 * So the width comes from JS instead, out of document.documentElement.clientWidth,
 * which excludes the scrollbar. The offset is the element's own measured distance
 * from the viewport's left edge, so it works at any nesting depth and needs no
 * assumption about the parent being centred.
 *
 * The breakout only reaches the screen edge if no ancestor clips it. Elementor's
 * containers default to `overflow: visible`, so this works out of the box —
 * setting Overflow: Hidden on the section in Elementor would clip it back.
 *
 * The fallbacks matter: with no JS this stays a normal in-flow block rather than
 * collapsing to nothing.
 */
.tcs.is-full {
	width: var(--tcs-bleed-w, 100%);
	max-width: none;
	margin-left: var(--tcs-bleed-x, 0px);
	margin-right: 0;
}

/*
 * The clipping boundary. This is what guarantees the marquee can never make the
 * page itself scroll sideways, however wide the track grows.
 */
.tcs .scroll-outer {
	position: relative;
	overflow: hidden;
	width: 100%;
	-webkit-overflow-scrolling: auto;
}

/*
 * The moving row.
 *
 * flex + a fixed gap keeps the spacing between groups identical, including across
 * the seam — the gap after the last original group is the same as every other, so
 * the clone that follows it sits exactly one --tcs-distance along.
 *
 * width:max-content stops the flex line from ever wrapping or shrinking, which
 * would change the measured distance and break the seam.
 */
.tcs .track-right {
	display: flex;
	flex-direction: row;
	flex-wrap: nowrap;
	align-items: stretch;
	gap: calc(var(--tcs-gap) * var(--tcs-gap-scale));
	width: max-content;
	will-change: transform;
	/* translate3d rather than translateX: it promotes the row to its own layer on
	   the older mobile WebKits this site's audience still uses. */
	transform: translate3d(0, 0, 0);
}

/* Added by the JS only once it has measured and cloned, so nothing animates
   against a wrong distance on the first frame. */
.tcs.is-ready .track-right {
	animation-name: tcs-marquee;
	animation-duration: var(--tcs-duration);
	animation-timing-function: linear;
	animation-iteration-count: infinite;
	animation-play-state: running;
}

/* Direction is a reversed playback of the same keyframes, so both directions
   share one animation and one measured distance. */
.tcs.is-ready[data-direction="right"] .track-right {
	animation-direction: reverse;
}

/*
 * Pause. Applied by the JS on hover, on touch, and while the strip is scrolled
 * out of view. animation-play-state freezes the current computed transform and
 * resumes from exactly there, so there is no jump either way.
 */
.tcs.is-paused .track-right {
	animation-play-state: paused;
}

/* ---------------------------------------------------------------------------
 * Touch: the visitor scrolls it
 *
 * On a coarse pointer the row becomes a real horizontal scroller and the
 * marquee drives scrollLeft instead of a transform, so the automatic motion and
 * the visitor's own are the same value and cannot fight each other.
 *
 * The transform has to go for that to work: it would move the content without
 * moving the scroll position, and the two would drift apart until the end of the
 * row came into view as blank space. `is-native` is set by the script rather
 * than being a media query so that the stylesheet and the script can never
 * disagree about which mode is running.
 * ------------------------------------------------------------------------- */

.tcs.is-native .scroll-outer {
	overflow-x: auto;
	overflow-y: hidden;

	/* Keeps a swipe that reaches the end from turning into a page-back gesture
	   or scrolling the document sideways. */
	overscroll-behavior-x: contain;

	-webkit-overflow-scrolling: touch;

	/* A scrollbar under a photo strip reads as a broken layout; the row moving
	   on its own already says it can be moved. */
	scrollbar-width: none;
}

.tcs.is-native .scroll-outer::-webkit-scrollbar {
	display: none;
}

/*
 * Three classes so this beats `.tcs.is-ready .track-right` on specificity
 * rather than on source order.
 */
.tcs.is-native.is-ready .track-right,
.tcs.is-native .track-right {
	animation: none !important;
	transform: none !important;
	will-change: auto;
}

/* ---------------------------------------------------------------------------
 * Drag to scroll
 *
 * The wrapper exists only to carry a second transform. max-content is what keeps
 * the flex row at its natural width — see the note in class-ct-collage.php.
 *
 * grab/grabbing is the whole affordance: there is no scrollbar to hint with, so
 * the cursor is the only thing that says this row can be pushed.
 * ------------------------------------------------------------------------- */

.tcs .tcs-drag {
	width: max-content;
	will-change: transform;
}

.tcs .scroll-outer {
	cursor: grab;
}

.tcs.is-dragging .scroll-outer {
	cursor: grabbing;
}

/* The browser's own image drag would fight the pointer, and a text selection
   started mid-drag leaves the row highlighted blue. */
.tcs.is-dragging,
.tcs.is-dragging * {
	user-select: none;
	-webkit-user-select: none;
}

.tcs .collage-item img {
	-webkit-user-drag: none;
	user-drag: none;
}

/* A photo that opens is a control, and has to look like one. */
.tcs .collage-item {
	cursor: zoom-in;
}

/* ---------------------------------------------------------------------------
 * The lightbox
 *
 * One element, appended to <body> rather than inside .tcs: a fixed overlay
 * nested inside a transformed ancestor is positioned against THAT ancestor, not
 * the viewport, so it would ride along with the marquee.
 * ------------------------------------------------------------------------- */

.tcs-box {
	position: fixed;
	inset: 0;
	z-index: 999999;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background: rgba(0, 0, 0, .88);
	opacity: 0;
	visibility: hidden;
	transition: opacity .18s ease, visibility .18s ease;
}

.tcs-box.is-open {
	opacity: 1;
	visibility: visible;
}

.tcs-box__img {
	max-width: 100%;
	max-height: 100%;
	display: block;
	border-radius: 6px;
	box-shadow: 0 20px 60px rgba(0, 0, 0, .5);
	/* The image is the one thing a click must NOT close the box on. */
	cursor: default;
}

.tcs-box__btn {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 46px;
	height: 46px;
	border: 0;
	border-radius: 50%;
	background: rgba(255, 255, 255, .16);
	color: #fff;
	font-size: 24px;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background .15s ease;
}

.tcs-box__btn:hover,
.tcs-box__btn:focus-visible {
	background: rgba(255, 255, 255, .32);
	outline: none;
}

.tcs-box__prev { left: 18px; }
.tcs-box__next { right: 18px; }

.tcs-box__close {
	position: absolute;
	top: 18px;
	right: 18px;
	transform: none;
}

.tcs-box__count {
	position: absolute;
	bottom: 18px;
	left: 0;
	right: 0;
	text-align: center;
	color: rgba(255, 255, 255, .75);
	font-size: 13px;
	letter-spacing: .04em;
}

@media (max-width: 600px) {
	.tcs-box { padding: 12px; }
	.tcs-box__btn { width: 38px; height: 38px; font-size: 20px; }
	.tcs-box__prev { left: 8px; }
	.tcs-box__next { right: 8px; }
}

@keyframes tcs-marquee {
	from { transform: translate3d(0, 0, 0); }
	to   { transform: translate3d(calc(var(--tcs-distance) * -1), 0, 0); }
}

/* ==========================================================================
   The collage group — one visual unit, six images
   ========================================================================== */

/*
 * A fixed height with the width derived from it, so the group's size is known
 * before a single image has loaded. That is what keeps the measured distance
 * correct on the first pass and the page free of layout shift; measuring after
 * load would mean either a wrong seam or a visible re-layout.
 *
 * The proportions come off the reference screenshot: a 735x382 repeat, columns
 * of 350/178/173, and — the part that matters — each column splitting at its own
 * height rather than on one shared line. Column 1 is a big image over a short
 * one, columns 2 and 3 are a short image over a big one.
 *
 * Three rows of 34/34/32 give exactly the two split points needed: 68% for
 * column 1 and 34% for columns 2 and 3. Every column therefore shows exactly one
 * gap, at its own split, because the spanning item absorbs the other row line.
 * A uniform two-row grid cannot express this, which is what made the first
 * attempt look wrong.
 */
.tcs .travel-collage {
	flex: 0 0 auto;
	display: grid;
	grid-template-columns: 2fr 1fr 1fr;
	grid-template-rows: 34fr 34fr 32fr;
	gap: var(--tcs-cell-gap);
	height: calc(var(--tcs-height) * var(--tcs-scale));
	/* 735 / 382 from the reference. */
	width: calc(var(--tcs-height) * var(--tcs-scale) * 1.92);
}

.tcs .collage-item {
	position: relative;
	overflow: hidden;
	margin: 0;
	border-radius: var(--tcs-radius);
	background: #EEF1F5;
}

/* Column 1 — tall over short, 68% / 32%. */
.tcs .collage-item--1 { grid-column: 1; grid-row: 1 / 3; }
.tcs .collage-item--2 { grid-column: 1; grid-row: 3 / 4; }

/* Columns 2 and 3 — short over tall, 34% / 66%. */
.tcs .collage-item--3 { grid-column: 2; grid-row: 1 / 2; }
.tcs .collage-item--4 { grid-column: 2; grid-row: 2 / 4; }
.tcs .collage-item--5 { grid-column: 3; grid-row: 1 / 2; }
.tcs .collage-item--6 { grid-column: 3; grid-row: 2 / 4; }

/* ==========================================================================
   Section label — the centred "• EXPLORE WITH US" rule above a strip
   ========================================================================== */
/*
 * The gap below is a variable, not a literal, because it is set again at three
 * breakpoints. It is deliberately larger than the group's own cell gap: the label
 * is a separate band from the mosaic, and spacing them the same makes the rule
 * read as part of the first collage rather than as a heading over it.
 */
.tcs-label {
	display: flex;
	align-items: center;
	gap: 16px;
	margin: 0 0 var(--tcs-label-gap);
}

/* Hairlines fill whatever is left either side, so the text stays centred at any
   width without a fixed rule length to maintain. */
.tcs-label::before,
.tcs-label::after {
	content: '';
	flex: 1 1 auto;
	height: 1px;
	background: #E3E7EC;
}

.tcs-label > span {
	flex: 0 0 auto;
	font-family: 'Inter', sans-serif;
	font-size: 11.5px;
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: 1.6px;
	text-transform: uppercase;
	color: #6B7280;
	white-space: nowrap;
}

.tcs-label > span::before {
	content: '\2022';
	color: #F68B2D;
	margin-right: 8px;
}

/* Full width would otherwise run the hairlines into the very screen edges. */
.tcs.is-full .tcs-label { padding: 30px 24px 0; }

/* Only the first strip. A strip that follows another already carries the 50px
   set in includes/tour-collage.php, and the heading's own top padding on top of
   that reads as a hole rather than a break.

   `.tcs + .tcs` rather than :first-of-type: the strips are siblings on a tour
   page but not on the home page, where each sits in its own Elementor section
   and would therefore be first of its type. */
.tcs + .tcs.is-full .tcs-label { padding-top: 0; }

/*
 * cover, not contain, here. These cells have deliberate mosaic proportions, so
 * filling them is the point — letterbox bars would read as broken in a tight
 * grid. That is the opposite of the tour hero, where the image's own shape wins.
 */
.tcs .collage-item img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* The width/height attributes are on the tag for the intrinsic ratio; the box
	   is decided by the grid, so they must not size it. */
	max-width: none;
}

/* ==========================================================================
   Responsive
   ==========================================================================
 * --tcs-scale is the only size lever here, and it has to be: --tcs-height itself
 * is an inline style from the shortcode and would win against anything written in
 * a media query. See the note at the top of the file.
 *
 * One multiplier scales the whole mosaic in proportion — the group's width is
 * derived from its height and every cell is a grid fraction, so there is no
 * per-cell sizing to keep in step and the layout cannot distort.
 *
 * The JS re-measures on resize and re-clones to suit, so a smaller group simply
 * means more of them on screen. Speed is px/second, so the strip keeps drifting
 * at the same physical pace rather than appearing to race once the photos shrink.
 *
 * Resulting sizes, against the default height="400":
 *   <=1024   x 0.72   288 x 553
 *   <= 767   x 0.62   248 x 476
 *   <= 480   x 0.55   220 x 422
 *   <= 420   x 0.50   200 x 384
 *
 * These are sized for legibility rather than for saving space. The two narrow
 * columns are a quarter of the group's width, so a group has to stay reasonably
 * large before they hold a recognisable photograph — at half this size they read
 * as coloured noise, which is what "not clear" meant.
 *
 * A consequence worth knowing: at the bottom two steps one group is wider than a
 * small phone's screen, so only one is visible at a time. That is fine and
 * intended — the group is the unit that moves, it is clipped by .scroll-outer,
 * and a partly visible group entering from the edge is what makes the strip read
 * as continuous rather than as a slideshow.
 *
 * The label gap shrinks more gently than the mosaic does. It is breathing room
 * around type, not part of the mosaic, so scaling it alongside the photos would
 * close it back up on exactly the screens that need it most.
 *
 * Widest-first, so each block only narrows what the one above it set.
 */

/* Tablet. */
@media (max-width: 1024px) {
	.tcs {
		--tcs-scale: 0.72;
		--tcs-gap-scale: 0.8;
		--tcs-cell-gap: 9px;
		--tcs-radius: 13px;
		--tcs-label-gap: 26px;
	}
}

/* Phones, landscape and large portrait. */
@media (max-width: 767px) {
	.tcs {
		--tcs-scale: 0.62;
		--tcs-gap-scale: 0.65;
		--tcs-cell-gap: 8px;
		--tcs-radius: 12px;
		--tcs-label-gap: 22px;
	}

	.tcs-label { gap: 10px; }
	.tcs-label > span { font-size: 10.5px; letter-spacing: 1.2px; }
	.tcs.is-full .tcs-label { padding: 30px 16px 0; }
}

/* Most phones in portrait. */
@media (max-width: 480px) {
	.tcs {
		--tcs-scale: 0.55;
		--tcs-gap-scale: 0.55;
		--tcs-cell-gap: 7px;
		--tcs-radius: 11px;
		--tcs-label-gap: 18px;
	}
}

/* Small phones. */
@media (max-width: 420px) {
	.tcs {
		--tcs-scale: 0.50;
		--tcs-gap-scale: 0.5;
		--tcs-cell-gap: 6px;
		--tcs-radius: 10px;
		--tcs-label-gap: 16px;
	}

	.tcs-label > span { font-size: 10px; letter-spacing: 1px; }
	.tcs.is-full .tcs-label { padding: 30px 14px 0; }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */
/*
 * Motion off, but the photos must stay reachable — so the strip becomes a normal
 * horizontal scroller the visitor drives. The clones are still in the DOM and
 * harmless: they read as more of the same gallery.
 *
 * The JS also honours the same query and skips starting the animation, so this is
 * belt and braces rather than the only guard.
 */
@media (prefers-reduced-motion: reduce) {

	.tcs.is-ready .track-right,
	.tcs .track-right {
		animation: none !important;
		transform: none !important;
		will-change: auto;
	}

	.tcs .scroll-outer {
		overflow-x: auto;
		scroll-snap-type: x proximity;
		-webkit-overflow-scrolling: touch;
	}

	.tcs .travel-collage { scroll-snap-align: start; }
}
