/* ==========================================================================
   Game Cartridges — compact right-to-left spectrum ladder

   Loaded only by page-dedicated-product-system.php. Resting content remains
   visible by default; JS opts the section into entrance states with .is-armed.
   ========================================================================== */

#dedicated-product .dp-cartridges {
	--cart-ground: #121212;
	--cart-base-width: 420px;
	--cart-cap: 38vw;
	--cart-ease: cubic-bezier(0.16, 1, 0.3, 1);
	/* Includes the section heading/seams plus the two fixed navigation bars, so
	   five rows fit in the visible 1080p area rather than only in document flow. */
	--cart-section-head-budget: 310px;
	--cart-line-origin: 0px;
	--cart-line-width: 100%;
	/* Title-card staircase. The first row sits at the base offset and every row
	   below it steps the same distance further right, mirroring the staircase the
	   cartridges themselves already walk — so the two columns descend together
	   instead of the titles hanging in one straight edge beside a diagonal.
	   Derived from --cart-i (the row's own index, emitted per row by the
	   template), so the ladder stays open-ended: there are no per-row rules. */
	/* Row one's own position, and the origin the whole staircase is measured
	   from. 0 seats the first card flush against the right edge of its grid
	   column instead of overhanging it, which is where it had been sitting.
	   Because every row resolves as base + index x step, changing this moves the
	   ENTIRE ladder by the same amount: the steps stay equal, the cards stay
	   parallel to the cartridge staircase, and each callout line simply grows by
	   the same distance. Nothing else has to be re-tuned to follow it. */
	--cart-title-base: 0px;
	/* Matched to the cartridges' own staircase rather than picked by eye. Those
	   advance 13% of the pane per row (renewal_dp_cartridge_offset_config), which
	   measures 78px per row at a 1440 viewport, 55px at 1024 and 22px at 390 —
	   a curve 5.4vw tracks at every one of those widths. The ceiling matches the
	   pane's own max-width cap, past which the cartridge staircase stops growing
	   too. Equal steps mean the two columns descend in parallel and every callout
	   line comes out the same length. */
	--cart-title-step: clamp(16px, 5.4vw, 78px);
	/* How far right of its resting place the card begins its slide. Deliberately
	   far shorter than --cart-travel: the cartridge enters from off-canvas, while
	   the card only has the gap between itself and the line to move through, and
	   must not cross into the cartridge's lane on its way in. */
	--cart-title-travel: clamp(56px, 9vw, 130px);
	/* One shared correction keeps the entire staircase slightly farther left
	   without changing the saved/editor-facing per-row offsets. */
	--cart-media-shift: -3%;

	position: relative;
	width: 100%;
	padding: clamp(56px, 7vw, 80px) 0;
	background: var(--cart-ground);
	color: #fff;
	font-family: var(--dp-font);
	overflow-x: clip;
	/* Rows may bleed into one another, but never into the neighbouring page
	   sections above or below this module. */
	overflow-y: clip;
}

/* Kept 1:1 with the established System section heading. */
#dedicated-product.dp-page .dp-cartridges__title {
	max-width: var(--dp-content-max, none);
	margin: 0 auto clamp(28px, 4vw, 48px);
	padding: 0 1.25rem;
	color: var(--dp-text, #fff);
	font-family: var(--dp-font);
	font-size: clamp(28px, 4vw, 48px);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.2;
	text-align: center;
}

#dedicated-product .dp-cartridges__ladder {
	display: flex;
	flex-direction: column;
	width: 100%;
}

/* Five rows plus the heading fit below the fixed masthead at 1080p. */
#dedicated-product .dp-cartridges__row {
	--cart-delay: min(calc(var(--cart-i, 0) * 45ms), 270ms);
	--cart-title-shift: calc(var(--cart-title-base) + var(--cart-i, 0) * var(--cart-title-step));
	--cart-row-h: clamp(124px, calc((100vh - var(--cart-section-head-budget)) / 5), 156px);
	--cart-row-h: clamp(124px, calc((100svh - var(--cart-section-head-budget)) / 5), 156px);
	/* Resolve the responsive standard size first. The saved percentage then
	   multiplies that true 100% baseline without being capped back down. The row
	   deliberately clips any resulting overspill at its viewport edge. */
	--cart-standard-width: min(
		var(--cart-base-width),
		var(--cart-cap),
		calc((var(--cart-row-h) - 20px) * 2.65)
	);
	--cart-width: calc(var(--cart-standard-width) * var(--cart-scale, 1));
	--cart-travel: calc(var(--cart-width) + 18vw);

	position: relative;
	display: flex;
	justify-content: center;
	width: 100%;
	height: var(--cart-row-h);
	background: var(--cart-ground);
	overflow: hidden;
}

/* Per-row editor opt-in. Do not assign a z-index here: making each row its own
   stacking context lets later opaque band backgrounds cover the preceding
   cartridge's lower spill. With a flat row stack, every z-index:10 cartridge
   paints above every z-index:0 band background in both directions. */
#dedicated-product .dp-cartridges__row--allow-y-overflow {
	overflow: visible;
}

#dedicated-product .dp-cartridges__row::before {
	content: '';
	position: absolute;
	inset: 0;
	background: radial-gradient(
		circle at 76% 50%,
		var(--cart-base) 0%,
		var(--cart-mid) 50%,
		var(--cart-edge) 100%
	);
	z-index: 0;
}

#dedicated-product .dp-cartridges__row::after {
	content: '';
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 1px;
	background: linear-gradient(
		90deg,
		rgba(255, 255, 255, 0) 0%,
		rgba(255, 255, 255, 0.2) 50%,
		rgba(255, 255, 255, 0) 100%
	);
	z-index: 20;
}

#dedicated-product .dp-cartridges__inner {
	position: relative;
	display: grid;
	grid-template-columns: minmax(220px, 38%) minmax(80px, 18%) minmax(280px, 44%);
	align-items: stretch;
	width: 100%;
	max-width: var(--dp-content-max, 1280px);
	height: 100%;
	padding: 0 clamp(16px, 3vw, 40px);
}

/* Title sits to the left of the media. The card is intentionally compact: the
   removed description no longer reserves a second text band. */
#dedicated-product .dp-cartridges__content {
	position: relative;
	left: var(--cart-title-shift);
	display: flex;
	align-items: center;
	justify-content: flex-end;
	min-width: 0;
	z-index: 20;
}

#dedicated-product .dp-cartridges__card {
	position: relative;
	z-index: 3;
	/* One uniform box for every row. The cards read as a set stepping down the
	   ladder in parallel with the cartridges, which a per-row width undercut —
	   the staircase is the thing carrying the eye now, and five different card
	   widths competed with it.
	 *
	 * 330px, not the 300px this was before the width briefly became adaptive: the
	 * longest title measures 262px on one line, and the inline padding is 30px a
	 * side at this width, so 300px would wrap it. The box is sized to hold the
	 * longest title AND the padding rather than making one give way to the other.
	 *
	 * The width never affects the callout line. .dp-cartridges__content is
	 * `justify-content: flex-end`, so the card is pinned to the RIGHT of its grid
	 * column and any width change moves only its left edge — the right edge, which
	 * is what game-cartridges-scroll.js measures for the line's start, is fixed by
	 * the alignment and the row's staircase offset. */
	width: min(92%, 330px);
	max-width: 100%;
	min-height: 54px;
	display: flex;
	/* Column, so an optional description can sit under the title. With only a
	   title present this is identical to the previous row layout: the main axis
	   is now vertical, so justify-content:center still centres the single child
	   in the card, and `stretch` keeps it full width — align-items:center on a
	   column would shrink-wrap it instead. */
	flex-direction: column;
	align-items: stretch;
	justify-content: center;
	gap: 6px;
	padding: clamp(10px, 1vw, 13px) clamp(20px, 2.2vw, 30px);
	border: 1px solid rgba(255, 255, 255, 0.12);
	border-radius: 10px;
	background: rgba(0, 0, 0, 0.32);
	box-shadow: 0 7px 24px rgba(0, 0, 0, 0.24);
	-webkit-backdrop-filter: blur(14px);
	backdrop-filter: blur(14px);
}

#dedicated-product.dp-page .dp-cartridges__blurb-title {
	display: block;
	width: 100%;
	margin: 0;
	color: #fff;
	/* Exact rendered typography contract from the Choosing a Game card title. */
	font-family: 'Montserrat-Bold', Helvetica, Arial, sans-serif;
	font-size: 1.25rem;
	font-weight: 400;
	letter-spacing: normal;
	line-height: 1.4;
	text-align: left;
	/* break-word, not anywhere: only break a word that cannot fit a line by
	   itself, rather than offering every character as a break opportunity. */
	overflow-wrap: break-word;
}

#dedicated-product.dp-page .dp-cartridges__blurb-desc {
	display: block;
	width: 100%;
	margin: 0;
	color: rgba(255, 255, 255, 0.82);
	font-family: var(--dp-font);
	font-size: 0.9375rem;
	font-weight: 400;
	line-height: 1.5;
	text-align: left;
	overflow-wrap: break-word;
}

/* Block content from the editors.
 *
 * Both fields are authored with a <p> root block — that is what gives the
 * alignment buttons something to act on — so the saved value now arrives
 * wrapped. An unqualified <p> would re-inherit the base theme's paragraph
 * sizing and margins and quietly shrink the copy. `font: inherit` keeps each
 * block tied to its own container's contract above, edge margins are flattened
 * so a block never adds outer spacing the plain field did not have, and
 * `text-align` is deliberately NOT reset — it is the point of the exercise. */
#dedicated-product.dp-page .dp-cartridges__blurb-title > :first-child,
#dedicated-product.dp-page .dp-cartridges__blurb-desc > :first-child { margin-top: 0; }
#dedicated-product.dp-page .dp-cartridges__blurb-title > :last-child,
#dedicated-product.dp-page .dp-cartridges__blurb-desc > :last-child { margin-bottom: 0; }

#dedicated-product.dp-page .dp-cartridges__blurb-title p,
#dedicated-product.dp-page .dp-cartridges__blurb-desc p {
	margin: 0 0 .4em;
	font: inherit;
	color: inherit;
	letter-spacing: inherit;
}
#dedicated-product.dp-page .dp-cartridges__blurb-title h1,
#dedicated-product.dp-page .dp-cartridges__blurb-title h2,
#dedicated-product.dp-page .dp-cartridges__blurb-title h3,
#dedicated-product.dp-page .dp-cartridges__blurb-title h4,
#dedicated-product.dp-page .dp-cartridges__blurb-title h5,
#dedicated-product.dp-page .dp-cartridges__blurb-title h6,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h1,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h2,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h3,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h4,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h5,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h6 {
	margin: 0 0 .3em;
	color: inherit;
	font-family: inherit;
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: -0.01em;
}
#dedicated-product.dp-page .dp-cartridges__blurb-title h1,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h1 { font-size: 1.4em; }
#dedicated-product.dp-page .dp-cartridges__blurb-title h2,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h2 { font-size: 1.26em; }
#dedicated-product.dp-page .dp-cartridges__blurb-title h3,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h3 { font-size: 1.14em; }
#dedicated-product.dp-page .dp-cartridges__blurb-title h4,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h4 { font-size: 1em; }
#dedicated-product.dp-page .dp-cartridges__blurb-title h5,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h5 { font-size: 0.9em; }
#dedicated-product.dp-page .dp-cartridges__blurb-title h6,
#dedicated-product.dp-page .dp-cartridges__blurb-desc h6 { font-size: 0.82em; }

/* The card is narrow; keep list markers inside it. */
#dedicated-product.dp-page .dp-cartridges__blurb-title ul,
#dedicated-product.dp-page .dp-cartridges__blurb-title ol,
#dedicated-product.dp-page .dp-cartridges__blurb-desc ul,
#dedicated-product.dp-page .dp-cartridges__blurb-desc ol {
	margin: 0 0 .3em;
	padding-left: 1.1em;
}
#dedicated-product.dp-page .dp-cartridges__blurb-title li,
#dedicated-product.dp-page .dp-cartridges__blurb-desc li {
	font: inherit;
	color: inherit;
}

/* JS expands this line from the title-card edge to underneath the cartridge. The
   grid centres both the spacer and the title card on the same horizontal axis. */
#dedicated-product .dp-cartridges__line-spacer {
	position: relative;
	align-self: center;
	width: 100%;
	height: 2px;
	z-index: 2;
}

#dedicated-product .dp-cartridges__line {
	position: absolute;
	top: 50%;
	left: var(--cart-line-origin);
	width: var(--cart-line-width);
	height: 2px;
	background: linear-gradient(
		90deg,
		rgba(255, 255, 255, 1) 0%,
		rgba(255, 255, 255, 0.5) 60%,
		rgba(255, 255, 255, 0) 100%
	);
	filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.65));
	pointer-events: none;
	transform: translateY(-50%);
	z-index: 1;
}

/* The cartridge remains the top layer so the line can terminate beneath it. */
#dedicated-product .dp-cartridges__pane {
	position: relative;
	min-width: 0;
	z-index: 10;
}

#dedicated-product .dp-cartridges__cart {
	position: absolute;
	top: 50%;
	/* Every row uses the same linear saved offset plus the same small global
	   correction. There is no row-5 exception, so the 13-point rhythm remains
	   intact for an open-ended row list. */
	left: calc(var(--cart-rest, 5%) + var(--cart-media-shift));
	transform: translate3d(0, calc(-50% + var(--cart-nudge, 0px)), 0);
	filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.58));
	z-index: 10;
}

#dedicated-product .dp-cartridges__cart-img {
	display: block;
	width: var(--cart-width);
	height: auto;
	/* Foundation applies a global responsive-image !important cap. This local
	   exception is intentional: the row owns clipping and editor percentages
	   must be allowed to exceed the cartridge pane. */
	max-width: none !important;
	max-height: none;
	color: transparent;
	font-size: 0;
	line-height: 0;
	object-fit: contain;
	object-position: center;
	image-rendering: -webkit-optimize-contrast;
}

/* ==========================================================================
   Entrance choreography — only after JS arms the section
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
	#dedicated-product .dp-cartridges.is-armed {
		opacity: 0;
		transition: opacity 0.5s ease;
	}

	#dedicated-product .dp-cartridges.is-armed.is-visible { opacity: 1; }

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row::before {
		opacity: 0;
		transition: opacity 0.7s ease;
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-active::before {
		opacity: 1;
		transition-delay: var(--cart-delay);
	}

	/* The row arrives as one movement: the title card and the cartridge both
	   travel right-to-left off the row's own --cart-delay, on the same curve and
	   over the same 0.65s, with the line drawn between them as they land. The
	   card used to lead the pair by 300ms; they now share a start so the row
	   reads as a single sweep rather than as three staged events.

	   Two details keep the card safe as the line's occluding layer. Its opacity
	   settles in 0.22s — well before the line, growing from `right center`, has
	   extended far enough left to reach the card at all — which is what stops the
	   line showing through a still-translucent background, the failure that
	   forced the original card-first ordering. And the line takes a 120ms beat so
	   its leading edge can never outrun that fade.

	   0.22s, not the 0.3s first tried: the margin is smallest on the TOP row at
	   phone widths, where the card sits closest to its cartridge and the line it
	   has to cover is only ~23px long. That row cleared by 3px at 0.3s, which is
	   not a margin — it is a coincidence waiting for a slower device.

	   translateX has a consequence the old translateY entrance did not: the card's
	   bounding rect is now the animation's business, not the layout's. The line's
	   alignment pass in game-cartridges-scroll.js therefore reads the card's
	   RESTING edge from offsetLeft/offsetWidth instead — measuring the live rect
	   pinned the line a full --cart-title-travel to the right of the card, which
	   is the gap that had to be chased back out. Do not reintroduce a rect read
	   there. */
	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__card {
		opacity: 0;
		transform: translate3d(var(--cart-title-travel), 0, 0);
		transition: transform 0.65s var(--cart-ease), opacity 0.22s ease;
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-active .dp-cartridges__card {
		opacity: 1;
		transform: translate3d(0, 0, 0);
		transition-delay: var(--cart-delay);
	}

	/* Positive X is the inverted entrance: right side -> leftward rest. */
	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__cart {
		opacity: 0;
		transform: translate3d(var(--cart-travel), calc(-50% + var(--cart-nudge, 0px)), 0);
		transition: transform 0.65s var(--cart-ease), opacity 0.45s ease;
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-active .dp-cartridges__cart {
		opacity: 1;
		transform: translate3d(0, calc(-50% + var(--cart-nudge, 0px)), 0);
		transition-delay: var(--cart-delay);
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__line {
		transform: translateY(-50%) scaleX(0);
		transform-origin: right center;
		transition: transform 0.6s var(--cart-ease);
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-active .dp-cartridges__line {
		transform: translateY(-50%) scaleX(1);
		transition-delay: calc(var(--cart-delay) + 120ms);
	}

	/* The content column itself is never animated — only the card inside it. It
	   carries no background of its own, and pinning it here keeps the card's
	   stacking context stable for the whole run. */
	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__content,
	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-active .dp-cartridges__content {
		opacity: 1;
		transform: none;
		transition: none;
	}

	/* Scrolled up past: the pair leaves together, upward, mirroring the entrance. */
	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-past .dp-cartridges__cart {
		opacity: 0;
		transform: translate3d(0, calc(-50% + var(--cart-nudge, 0px) - 28px), 0);
	}

	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-past .dp-cartridges__card {
		opacity: 0;
		transform: translate3d(0, -14px, 0);
	}


	#dedicated-product .dp-cartridges.is-armed .dp-cartridges__row.is-past .dp-cartridges__content {
		opacity: 1;
		transform: none;
	}

	/* The two moving layers get a temporary compositor hint. The LINE still must
	   not be promoted: giving it its own layer let it composite above the
	   backdrop-filtered title card until is-animating expired. */
	#dedicated-product .dp-cartridges .dp-cartridges__row.is-animating .dp-cartridges__cart,
	#dedicated-product .dp-cartridges .dp-cartridges__row.is-animating .dp-cartridges__card {
		will-change: transform, opacity;
	}
}

/* ==========================================================================
   Responsive geometry
   ========================================================================== */
@media (orientation: portrait) and (min-width: 900px) {
	#dedicated-product .dp-cartridges { --cart-cap: 42vw; }
}

@media (max-width: 900px) {
	#dedicated-product .dp-cartridges {
		--cart-cap: 40vw;
		--cart-section-head-budget: 260px;
	}

	#dedicated-product .dp-cartridges__inner {
		grid-template-columns: minmax(180px, 42%) minmax(60px, 12%) minmax(220px, 46%);
	}

	#dedicated-product .dp-cartridges__card { padding: 10px 22px; }
}

@media (max-width: 767px) {
	#dedicated-product .dp-cartridges {
		--cart-cap: 44vw;
		--cart-section-head-budget: 220px;
		/* Same origin as desktop; the base is not a per-breakpoint value any more.
		   No step override either: 5.4vw already resolves to ~21px here, which is
		   what the cartridges themselves advance at this width. */
		--cart-title-base: 0px;
		/* Shorter than a simple scale-down of the desktop travel. The top row's
		   card sits closest to its cartridge, so its line is only ~23px long, and
		   the further right the card starts the sooner it is sitting over that
		   line while still fading up. Keeping the slide short is what holds the
		   clearance open at the one width where the geometry is tightest. */
		--cart-title-travel: clamp(20px, 6vw, 40px);
	}

	#dedicated-product .dp-cartridges__row {
		--cart-row-h: clamp(116px, calc((100svh - var(--cart-section-head-budget)) / 5), 140px);
		--cart-travel: calc(var(--cart-width) + 34vw);
	}

	#dedicated-product .dp-cartridges__inner {
		grid-template-columns: minmax(0, 43%) minmax(28px, 12%) minmax(0, 45%);
		padding: 0 12px;
	}

	#dedicated-product .dp-cartridges__card {
		padding: 9px 18px;
		-webkit-backdrop-filter: blur(9px);
		backdrop-filter: blur(9px);
	}
}

@media (max-width: 420px) {
	#dedicated-product .dp-cartridges__row { --cart-row-h: 116px; }
	#dedicated-product .dp-cartridges__inner {
		grid-template-columns: minmax(0, 45%) minmax(22px, 8%) minmax(0, 47%);
	}
}

/* Short landscape tablets need the smaller floor to keep four complete rows
   below the fixed navigation without crushing the desktop composition. */
@media (min-width: 768px) and (max-height: 900px) {
	#dedicated-product .dp-cartridges__row {
		--cart-row-h: clamp(112px, calc((100svh - var(--cart-section-head-budget)) / 5), 148px);
	}
}
