/* Case study grid
   ------------------------------------------------------------------
   Row-aligned grid, not masonry. Cards in a row share a top edge because
   that is what a normal CSS grid does. Large cards span two columns AND
   two rows, so the two standard cards beside them stack into the leftover
   column — which is how the comp is built. */

.cs {
	--cs-accent: #e6004f;        /* swap for the exact Figma pink */
	--cs-ink: #111;
	--cs-col-gap: 1.5rem;
	--cs-row-space: 2.5rem;
	--cs-radius: 1.5rem;
	--cs-media-ratio: 3 / 2;     /* card image crop — set from Figma */

	max-width: 1120px;
	margin-inline: auto;
	padding-inline: 1.25rem;
}

/* Filter bar
   ------------------------------------------------------------------ */

.cs-filters__list {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem 1.5rem;
	margin: 0 0 2.5rem;
	padding: 0;
	list-style: none;
}

/* Default, and explicitly for :link / :visited so a global a:visited rule in
   the theme stylesheet can't repaint these. */
.cs-filters__link,
.cs-filters__link:link,
.cs-filters__link:visited {
	color: var(--cs-ink);
	text-decoration: none;
	padding: 0.125rem 0;
}

/* Pink is reserved for the active category. */
.cs-filters__link[aria-current="true"],
.cs-filters__link[aria-current="true"]:link,
.cs-filters__link[aria-current="true"]:visited {
	color: var(--cs-accent);
}

/* Hover affordance without borrowing the active state's colour.
   Delete this block if you want no hover feedback at all. */
.cs-filters__link:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.cs-filters__link:focus-visible {
	outline: 2px solid var(--cs-accent);
	outline-offset: 2px;
}

.cs-status {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.cs-empty {
	margin: 3rem 0;
	text-align: center;
	color: #555;
}

/* Grid
   ------------------------------------------------------------------
   Row height is set by the standard cards. Dense packing lets the short
   cards fall into the column left open beside a large one. */

.cs-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	grid-auto-flow: row dense;
	column-gap: var(--cs-col-gap);
	row-gap: var(--cs-row-space);
	align-items: stretch; /* required: cards fill their row(s) */
}

.cs-item {
	min-width: 0;
}

.cs-item[hidden] {
	display: none;
}

/* Longhand, not the grid-column / grid-row shorthands: those would reset
   the start lines and cancel the column pinning below. */
.cs-item--wide {
	grid-column-end: span 2;
	grid-row-end: span 2;
}

/* Per-card column, set from the Card layout box in the editor.
   Explicitly placed items are laid out before auto-placed ones, so a pinned
   card holds its column even with dense packing on. */
.cs-item[data-cs-column="1"] { grid-column-start: 1; }
.cs-item[data-cs-column="2"] { grid-column-start: 2; }
.cs-item[data-cs-column="3"] { grid-column-start: 3; }

/* Card
   ------------------------------------------------------------------
   Flex column: the media absorbs whatever height the row gives the card,
   the text sits underneath at its natural height. A large card is two rows
   plus the gap tall, so its image grows to match — no measurement needed. */

.cs-item__link {
	display: flex;
	flex-direction: column;
	height: 100%;
	color: inherit;
	text-decoration: none;
}

/* Cards with no destination set render on a div instead of an anchor. */
div.cs-item__link {
	cursor: default;
}

.cs-item__link:focus-visible {
	outline: 2px solid var(--cs-accent);
	outline-offset: 4px;
}

.cs-item__media {
	flex: 1 1 auto;
	min-height: 0;
	aspect-ratio: var(--cs-media-ratio);
	overflow: hidden;
	border-radius: var(--cs-radius);
}

.cs-item__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
}

.cs-item__title {
	margin: 0.75rem 0 0.125rem;
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.3;
	color: var(--cs-ink);
}

.cs-item__type {
	margin: 0;
	font-size: 0.8125rem;
	font-weight: 400;
	line-height: 1.4;
	color: var(--cs-accent);
}

/* Breakpoints
   ------------------------------------------------------------------ */

@media (max-width: 900px) {
	.cs-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/* Column 3 no longer exists, and pinning two of two columns would force
	   a single file. Auto-place everything below desktop. */
	.cs-item[data-cs-column] {
		grid-column-start: auto;
	}
}

@media (max-width: 560px) {
	.cs-grid {
		grid-template-columns: minmax(0, 1fr);
	}

	.cs-item--wide {
		grid-column-end: auto;
		grid-row-end: auto;
	}
}

/* Filter animation
   ------------------------------------------------------------------
   The JS names each card, so the browser pairs its before/after snapshots
   and animates between them: leaving cards fade out, surviving cards slide
   to their new position, arriving cards fade in. Browsers without view
   transitions get the instant swap and none of this applies. */

::view-transition-group(*) {
	animation-duration: 320ms;
	animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
}

/* Everything outside the grid is unchanged, so skip the root cross-fade —
   otherwise the page height change reads as a whole-page flash. */
::view-transition-old(root),
::view-transition-new(root) {
	animation: none;
	mix-blend-mode: normal;
}

@media (prefers-reduced-motion: reduce) {
	::view-transition-group(*),
	::view-transition-old(*),
	::view-transition-new(*) {
		animation: none !important;
	}
}