/**
 * case-study.css — case-study detail-page layout.
 *
 * Loaded by ALL case-study detail pages via the `styles:` cascade in
 * src/case-studies/case-studies.json (directory data file). Every .md
 * file under src/case-studies/ inherits this CSS plus _partials/case-
 * study-overlay.css automatically — no per-file frontmatter needed.
 *
 * In-development case studies (Phlip-style — status === 'in-development')
 * use a sibling layout (in-development-case-study.njk) that loads this
 * file PLUS _partials/in-development-case-study.css for the variant
 * additions (status pill, live chip, latest-update meta, CTA overrides).
 *
 * Seven vertically-stacked sections (graceful-degrade — sections with
 * empty data don't emit any chrome):
 *
 *   1. Hero (eyebrow + title + lead)
 *   2. Client + metadata strip
 *   3. Metric callouts (4-up outcomes grid)
 *   3.5. Hero image / problem-approach-outcome bridge
 *   4. Markdown body
 *   5. Image gallery (device-frame grouped by platform)
 *   6. Related case studies (via `fwCard` filter)
 *   7. CTA banner (innov8-cs-cta-* — distinct from innov8-cta-banner)
 *
 * Class prefix: `innov8-cs-`. Mirrors `innov8-hero-`, `innov8-nav-`,
 * `innov8-fw-` partial conventions so the section-scoped rules can't
 * collide across pages.
 *
 * File-size cap rationale: 1,105 lines (2.2× the 500-line cap). The
 * case-study detail layout is the single most content-rich page type
 * on the site (every section above + responsive treatments + device-
 * frame gallery + reduced-motion fallbacks + every brand-specific
 * outcome treatment). Sub-splitting into sub-sections would fragment
 * what is fundamentally one layout; the page-as-a-whole IS the cohesive
 * unit. Documented exception per docs/engineering-standards.md §
 * file-size cap.
 *
 * Extracted from src/assets/css/app.css CASE STUDY DETAIL section as
 * part of #147 PR 3 — CSS file split: complex pages. Content byte-
 * for-byte preserved.
 */

/* ─────────────────────────────────────────────────────────────────────
	CASE STUDY DETAIL
	─────────────────────────────────────────────────────────────────────
	The long-form per-case-study page layout. Markup lives in
	`src/_includes/layouts/case-study.njk` (chained off `base.njk`).
	Composed by every Markdown file under `src/case-studies/` via the
	directory data file `src/case-studies/case-studies.json` setting
	`layout: "layouts/case-study.njk"`.

	Seven vertically-stacked sections:

		1. Hero            — breadcrumb + h1 title + optional summary lead
		2. Meta strip      — client logo block (or fallback name) + year +
												duration + optional agency/team-size columns
		3. Metrics         — "At a glance" outcome callouts. Conditional —
												renders only when `outcomes` frontmatter (a
												Sprint 4 content-rewrite field) lands.
		4. Body + sidebar  — sticky sidebar (stack + URL + industry) plus
												the case-study Markdown body slot
		5. Gallery         — `images: [{ url, platform }]` grid. Conditional;
												plain `<img loading="lazy">` per #40 scope
												decision (responsive `<picture>` deferred to
												ticket #66 — eleventy-img full pipeline).
		6. Related         — same-industry sibling case studies via the
												`relatedCaseStudies` filter, rendered with the
												shared `featured-work-card.njk` macro so the
												card visual language stays single-sourced.
		7. CTA banner      — inline conversion prompt. Lightweight inline
												version until the dedicated `cta-banner.njk`
												partial lands (separate ticket).

	All class names use the `innov8-cs-` prefix (mirrors `innov8-hero-`,
	`innov8-nav-`, `innov8-fw-` conventions) so the section-scoped rules
	can't collide with anything outside this layout.

	Sections 3, 5, and the agency/team-size columns of section 2 are
	wrapped in `{% if %}` guards in the layout — they render nothing
	until the relevant frontmatter populates, then appear automatically.
	The styles below are present unconditionally so the moment the data
	lands the visuals come along for the ride with no further markup
	work.
	───────────────────────────────────────────────────────────────────── */

@layer components {
	/* ─── Article frame ─────────────────────────────────────────────── */
	.innov8-cs {
		position: relative;
		color: var(--fg-primary);
	}

	/* ─── 1. Hero ───────────────────────────────────────────────────── */
	/* Top padding floors at 120px so the eyebrow clears the floating
		 glass-pill nav (position: fixed; top: 28px; height: ~70px). */
	.innov8-cs-hero {
		position: relative;
		padding: clamp(120px, 11vw, 160px) 0 clamp(40px, 5vw, 64px);
		background:
			radial-gradient(80% 60% at 20% 0%, rgba(31, 86, 245, 0.16), transparent 60%),
			radial-gradient(60% 50% at 90% 20%, rgba(95, 236, 253, 0.08), transparent 60%), var(--color-ink-1000);
	}

	.innov8-cs-hero-inner {
		max-width: 1240px;
		margin: 0 auto;
		padding: 0 32px;
	}

	.innov8-cs-breadcrumb {
		display: flex;
		align-items: center;
		gap: 10px;
		margin-bottom: clamp(20px, 2.4vw, 32px);
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		letter-spacing: 0.14em;
		text-transform: uppercase;
		color: var(--fg-tertiary);
	}

	.innov8-cs-breadcrumb-link {
		color: var(--fg-tertiary);
		text-decoration: none;
		transition: color var(--duration-base) var(--ease-out);
	}

	.innov8-cs-breadcrumb-link:hover,
	.innov8-cs-breadcrumb-link:focus-visible {
		color: var(--accent-spark);
		outline: none;
	}

	.innov8-cs-breadcrumb-sep {
		color: var(--fg-muted);
	}

	.innov8-cs-breadcrumb-current {
		color: var(--accent-spark);
	}

	.innov8-cs-title {
		margin: 0;
		max-width: 18ch;
		font-family: var(--font-display);
		font-weight: 700;
		font-size: var(--text-h1);
		line-height: var(--leading-tight);
		letter-spacing: var(--tracking-snug);
		color: var(--fg-primary);
		text-transform: uppercase;
		text-wrap: balance;
	}

	.innov8-cs-lead {
		margin: clamp(20px, 2.4vw, 28px) 0 0;
		max-width: 64ch;
		font-family: var(--font-sans);
		font-size: var(--text-body-lg);
		line-height: var(--leading-base);
		color: var(--fg-secondary);
		text-wrap: pretty;
	}

	/* ─── 2. Meta strip ─────────────────────────────────────────────── */
	.innov8-cs-meta-strip {
		padding: clamp(28px, 3.6vw, 44px) 0;
		background: var(--color-ink-950);
		border-top: 1px solid var(--border-subtle);
		border-bottom: 1px solid var(--border-subtle);
	}

	.innov8-cs-meta-strip-inner {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: clamp(20px, 3vw, 40px);
	}

	.innov8-cs-client-block {
		display: inline-flex;
		flex-direction: column;
		gap: 10px;
		text-decoration: none;
		color: inherit;
		transition: opacity var(--duration-base) var(--ease-out);
	}

	.innov8-cs-client-block:hover,
	.innov8-cs-client-block:focus-visible {
		opacity: 0.85;
		outline: none;
	}

	/* Logo silhouette filter dropped — see .innov8-cm-logo note. */
	.innov8-cs-client-logo {
		max-height: 44px;
		max-width: 180px;
		width: auto;
		height: auto;
		object-fit: contain;
		opacity: 0.92;
	}

	.innov8-cs-client-name {
		font-family: var(--font-display);
		font-weight: 700;
		font-size: clamp(20px, 2vw, 26px);
		letter-spacing: var(--tracking-snug);
		color: var(--fg-primary);
		text-transform: uppercase;
	}

	.innov8-cs-meta-cols {
		display: flex;
		flex-wrap: wrap;
		gap: clamp(20px, 3vw, 40px);
	}

	.innov8-cs-meta-col {
		display: flex;
		flex-direction: column;
		gap: 6px;
		min-width: 0;
	}

	/* Meta-strip labels — amber per the #164 two-accent semantic duality
		(structured metadata signal, not an interactive element). */
	.innov8-cs-meta-label {
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		font-weight: 500;
		letter-spacing: 0.14em;
		text-transform: uppercase;
		color: var(--accent-data);
	}

	.innov8-cs-meta-value {
		font-family: var(--font-sans);
		font-size: var(--text-body-lg);
		font-weight: 500;
		color: var(--fg-primary);
	}

	/* Duration strings are long ("Jan 2020 → Jun 2020") — drop a pinch
		 so they don't crowd the adjacent column on narrow widths. */
	.innov8-cs-meta-duration {
		font-size: var(--text-body);
		color: var(--fg-secondary);
	}

	/* ─── 3. Metrics ────────────────────────────────────────────────── */
	.innov8-cs-metrics {
		padding: clamp(48px, 6vw, 80px) 0;
		background: var(--color-ink-1000);
	}

	.innov8-cs-eyebrow {
		margin-bottom: clamp(16px, 2vw, 24px);
	}

	/* Up to four cards in a row; collapses to 2 col at tablet width and
		1 col on phones. The data-count attribute on the grid is purely
		informational — the grid is fluid regardless of how many entries
		arrive. */
	.innov8-cs-metrics-grid {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
		gap: clamp(16px, 2vw, 24px);
	}

	.innov8-cs-metric {
		display: flex;
		flex-direction: column;
		gap: 8px;
		padding: clamp(20px, 2.4vw, 28px);
		background: var(--bg-card);
		border: 1px solid var(--border-default);
		border-radius: var(--radius-lg);
		transition:
			border-color var(--duration-base) var(--ease-out),
			transform var(--duration-base) var(--ease-out);
	}

	.innov8-cs-metric:hover {
		border-color: var(--border-brand);
		transform: translateY(-2px);
	}

	.innov8-cs-metric-value {
		font-family: var(--font-display);
		font-weight: 700;
		/* Scales down vs. prior clamp(32, 4vw, 48) so non-numeric values
			like "Untouched" / "WCAG 2.1 AA" don't overflow the card edge
			on standard viewport widths. Numerals still read as the
			headline element; text values now fit cleanly. */
		font-size: clamp(22px, 2.6vw, 32px);
		line-height: 1.05;
		letter-spacing: var(--tracking-snug);
		color: var(--accent-spark);
		word-break: break-word;
	}

	/* Metric label — no color override; inherits --fg-primary (white)
		from the .innov8-cs article root. The numeric value above is the
		cyan headline; the label reads as plain body-weight white text
		so the value stays the star of each metric card. (The amber
		treatment tried in the first pass of #164 read as visual noise
		stacked under the cyan numerals — Mike's design call to drop
		the override entirely rather than swap colors.) */
	.innov8-cs-metric-label {
		font-family: var(--font-sans);
		font-size: var(--text-body);
		line-height: var(--leading-snug);
	}

	.innov8-cs-metric-delta {
		font-family: var(--font-mono);
		font-size: var(--text-caption);
		letter-spacing: 0.08em;
		text-transform: uppercase;
		color: var(--color-success);
	}

	@media (prefers-reduced-motion: reduce) {
		.innov8-cs-metric,
		.innov8-cs-metric:hover {
			transition: none;
			transform: none;
		}
	}

	/* ─── 3.5. Hero image (between metrics + body) ──────────────────── */
	/* Single full-width image — `images[0]` from frontmatter — rendered
		between the metrics strip and the body so the visual lands above
		the long-form text. object-fit: contain preserves the whole
		screenshot (no cropping); a max-height keeps it from dominating
		the page; the dark background fills any letterbox space cleanly.
		The full gallery still renders below the body. */
	.innov8-cs-hero-image-section {
		padding: clamp(32px, 4vw, 56px) 0 0;
		background: var(--color-ink-1000);
	}

	.innov8-cs-hero-image-figure {
		margin: 0;
		padding: clamp(12px, 1.4vw, 20px);
		background: var(--color-ink-950);
		border: 1px solid var(--border-subtle);
		border-radius: var(--radius-lg);
		display: flex;
		align-items: center;
		justify-content: center;
		max-height: 68vh;
	}

	.innov8-cs-hero-image {
		display: block;
		max-width: 100%;
		max-height: calc(68vh - clamp(24px, 2.8vw, 40px));
		width: auto;
		height: auto;
		object-fit: contain;
		border-radius: var(--radius-md);
	}

	/* ─── 4. Body + sidebar grid ────────────────────────────────────── */
	.innov8-cs-body-section {
		padding: clamp(48px, 6vw, 80px) 0;
		background: var(--color-ink-1000);
	}

	/* Sidebar above body on mobile, beside body (sticky) on desktop.
		`align-items: start` keeps the sidebar pinned at the top of the
		grid cell so the sticky offset has somewhere to sit. */
	.innov8-cs-body-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: clamp(32px, 4vw, 56px);
		align-items: start;
	}

	@media (min-width: 960px) {
		.innov8-cs-body-grid {
			grid-template-columns: 260px 1fr;
		}
	}

	.innov8-cs-side {
		display: flex;
		flex-direction: column;
		gap: clamp(24px, 2.4vw, 32px);
	}

	@media (min-width: 960px) {
		.innov8-cs-side {
			position: sticky;
			top: 96px; /* clears the fixed nav (≈64px) + breathing room */
		}
	}

	.innov8-cs-side-block {
		display: flex;
		flex-direction: column;
		gap: 12px;
	}

	.innov8-cs-side-label {
		margin: 0;
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		font-weight: 500;
		letter-spacing: 0.14em;
		text-transform: uppercase;
		color: var(--fg-tertiary);
	}

	.innov8-cs-side-text {
		margin: 0;
		font-family: var(--font-sans);
		font-size: var(--text-body);
		color: var(--fg-secondary);
	}

	.innov8-cs-side-chips {
		display: flex;
		flex-wrap: wrap;
		gap: 6px;
		margin: 0;
		padding: 0;
		list-style: none;
	}

	/* Stack chip — amber per the #164 two-accent semantic duality. The
		technology list IS categorical metadata; the chip's background +
		border tints match the amber color family for consistency with
		the .innov8-fw-overlay-chip (also amber, also tech chips). */
	.innov8-cs-side-chip {
		display: inline-flex;
		align-items: center;
		padding: 4px 10px;
		border-radius: var(--radius-pill);
		background: rgba(245, 166, 35, 0.1);
		border: 1px solid rgba(245, 166, 35, 0.25);
		font-family: var(--font-mono);
		font-size: 10px;
		letter-spacing: 0.08em;
		text-transform: uppercase;
		color: var(--accent-data);
	}

	.innov8-cs-side-link {
		display: inline-flex;
		align-items: center;
		gap: 8px;
		font-family: var(--font-sans);
		font-size: var(--text-body);
		color: var(--accent-spark);
		text-decoration: none;
		transition: gap var(--duration-base) var(--ease-out);
	}

	.innov8-cs-side-link:hover,
	.innov8-cs-side-link:focus-visible {
		gap: 12px;
		outline: none;
	}

	.innov8-cs-side-link-arrow {
		display: inline-block;
		transition: transform var(--duration-base) var(--ease-out);
	}

	.innov8-cs-side-link:hover .innov8-cs-side-link-arrow,
	.innov8-cs-side-link:focus-visible .innov8-cs-side-link-arrow {
		transform: translate(2px, -2px);
	}

	@media (prefers-reduced-motion: reduce) {
		.innov8-cs-side-link,
		.innov8-cs-side-link-arrow,
		.innov8-cs-side-link:hover .innov8-cs-side-link-arrow,
		.innov8-cs-side-link:focus-visible .innov8-cs-side-link-arrow {
			transition: none;
			transform: none;
		}
	}

	/* The body slot — Eleventy emits the case-study Markdown into the
		`content` variable, which the layout `{{ content | safe }}`s into
		`.innov8-cs-main`. Reset the in-flow Markdown-rendered prose to
		our brand voice: comfortable measure, ample leading, and a small
		set of element-level rules (headings, paragraphs, links, lists,
		blockquotes, code, and `markdown-it-anchor`'s `<a class="heading-
		anchor">` permalinks). */
	.innov8-cs-main {
		max-width: 72ch;
		font-family: var(--font-sans);
		font-size: var(--text-body-lg);
		line-height: var(--leading-loose);
		color: var(--fg-secondary);
	}

	/* Block-level prose-flow reset.
		`:where()` drops specificity to (0,0,0) for the inner selector
		list, so this rule's effective specificity is just `.innov8-cs-
		main` = (0,1,0) — the same specificity as the `> * + *` rule
		below it. Source order tiebreak puts the `> * + *` rule LATER,
		so the inter-element `margin-top` cascade actually wins.

		This avoids the trap where a downstream `.innov8-cs-main p {
		margin: 0; }` rule (specificity 0,1,1) silently overrides the
		`> * + *` adjacent-sibling spacing — which was happening here
		and made every value of the inter-paragraph margin (1.25em →
		1.6em → 2em) render as zero. */
	.innov8-cs-main :where(p, ul, ol, blockquote, pre) {
		margin: 0;
	}

	.innov8-cs-main > * + * {
		/* 1.5em at the 18px body size = 27px, just below the 30px line-
			height so paragraph breaks read as deliberate separations
			without going overboard. The cascade for this rule is finally
			working — see the `:where()` reset above for the source-order
			reasoning. */
		margin-top: 1.5em;
	}

	.innov8-cs-main h2,
	.innov8-cs-main h3,
	.innov8-cs-main h4 {
		font-family: var(--font-display);
		font-weight: 700;
		color: var(--fg-primary);
		letter-spacing: var(--tracking-snug);
		text-transform: uppercase;
		text-wrap: balance;
	}

	.innov8-cs-main h2 {
		margin-top: 2em;
		font-size: var(--text-h3);
		line-height: var(--leading-snug);
	}

	.innov8-cs-main h3 {
		margin-top: 1.75em;
		font-size: var(--text-h4);
		line-height: var(--leading-snug);
	}

	.innov8-cs-main h4 {
		margin-top: 1.5em;
		font-size: var(--text-h5);
		line-height: var(--leading-snug);
	}

	.innov8-cs-main a:not(.heading-anchor) {
		color: var(--accent-spark);
		text-decoration: underline;
		text-decoration-color: rgba(95, 236, 253, 0.4);
		text-underline-offset: 3px;
		transition: text-decoration-color var(--duration-base) var(--ease-out);
	}

	.innov8-cs-main a:not(.heading-anchor):hover,
	.innov8-cs-main a:not(.heading-anchor):focus-visible {
		text-decoration-color: var(--accent-spark);
		outline: none;
	}

	.innov8-cs-main ul,
	.innov8-cs-main ol {
		/* `margin: 0` reset now lives in the `:where()` block above so
			 the `> * + *` cascade can win the source-order tiebreak. */
		padding-left: 1.5em;
	}

	.innov8-cs-main li + li {
		margin-top: 0.5em;
	}

	.innov8-cs-main blockquote {
		/* `margin: 0` reset lives in the `:where()` block above. */
		padding: 0 0 0 1.25em;
		border-left: 2px solid var(--border-brand);
		color: var(--fg-primary);
		font-style: italic;
	}

	.innov8-cs-main code {
		padding: 2px 6px;
		border-radius: var(--radius-xs);
		background: rgba(255, 255, 255, 0.06);
		font-family: var(--font-mono);
		font-size: 0.92em;
		color: var(--fg-primary);
	}

	.innov8-cs-main pre {
		/* `margin: 0` reset lives in the `:where()` block above. */
		padding: clamp(16px, 2vw, 20px);
		border-radius: var(--radius-md);
		background: var(--color-ink-950);
		border: 1px solid var(--border-default);
		overflow-x: auto;
		font-family: var(--font-mono);
		font-size: var(--text-body-sm);
		line-height: var(--leading-base);
	}

	.innov8-cs-main pre code {
		padding: 0;
		background: transparent;
		font-size: inherit;
	}

	/* markdown-it-anchor's headerLink wraps the whole heading text in an
		`<a class="heading-anchor">`. Strip its underline so headings read
		as headings, not links, while still allowing keyboard focus. */
	.innov8-cs-main .heading-anchor {
		color: inherit;
		text-decoration: none;
	}

	.innov8-cs-main .heading-anchor:hover,
	.innov8-cs-main .heading-anchor:focus-visible {
		color: var(--accent-spark);
		outline: none;
	}

	/* ─── 4.a Inline figures — SVG wireframes + diagrams ──────────────
		Authored as raw HTML inside the Markdown body via:

			<figure class="innov8-cs-figure">
				<img src="..." alt="..." loading="lazy" decoding="async">
				<figcaption>...</figcaption>
			</figure>

		The SVGs are 16:10 (1600×1000 viewBox) and ship with their own
		`--color-ink-1000` background, so the figure wrapper only needs
		to supply border definition, corner rounding, and figcaption
		styling. The `> * + *` cascade above already gives a 1.5em
		top-margin to any figure that follows a sibling, so the figures
		slot into the prose flow without explicit margin overrides. */
	.innov8-cs-figure {
		/* The `:where()` reset above zeros figure's `margin`; the cascade
			 then provides the inter-element margin-top. */
		padding: 0;
		background: var(--color-ink-950);
		border: 1px solid var(--border-subtle);
		border-radius: var(--radius-md);
		overflow: hidden;
	}

	.innov8-cs-figure > img {
		display: block;
		width: 100%;
		height: auto;
	}

	.innov8-cs-figure > figcaption {
		padding: clamp(10px, 1.2vw, 14px) clamp(14px, 1.6vw, 20px);
		border-top: 1px solid var(--border-subtle);
		background: var(--color-ink-900);
		color: var(--fg-tertiary);
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		letter-spacing: 0.08em;
		line-height: var(--leading-snug);
		text-wrap: balance;
	}

	/* The `:where()` reset above doesn't touch figure (figures aren't
		in its selector list), so we explicitly zero figure's margin
		here to keep the `> * + *` cascade as the single source of
		inter-element spacing. */
	.innov8-cs-main > figure.innov8-cs-figure {
		margin: 0;
	}

	.innov8-cs-main > figure.innov8-cs-figure + * {
		/* The `> * + *` rule already handles this, but specificity-
			matched explicitness here makes the inter-figure-to-text
			spacing readable from the file alone. */
		margin-top: 1.5em;
	}

	/* ─── 4.b Section mini-heroes (umbrella / multi-product pages) ─────
		Full-width visual placed at the opening of a major sub-section in
		umbrella case studies (ea, honda-shopping-tools, topline-game-labs).
		Authored as raw HTML inside the Markdown body:

			<figure class="innov8-cs-section-hero">
			  <img src="..." alt="..." loading="lazy" decoding="async">
			  <figcaption>...</figcaption>
			</figure>

		Lighter than the main innov8-cs-hero-image-figure (between metrics
		and body) — max-height is capped lower so section heroes read as
		"product screenshot" rather than "marketing poster". object-fit:
		cover + top positioning shows the most visually dense part of each
		web screenshot (the nav and above-the-fold area) without letterboxing.
		The cyan ambient glow matches the gallery Web-row bezel so the visual
		language stays consistent across the page. */
	.innov8-cs-section-hero {
		margin: 0;
		border-radius: var(--radius-lg);
		overflow: hidden;
		border: 1px solid var(--border-subtle);
		background: var(--color-ink-950);
		box-shadow:
			0 0 40px 4px rgb(95 236 253 / 0.08),
			0 8px 24px -6px rgb(0 0 0 / 0.45);
	}

	.innov8-cs-section-hero > img {
		display: block;
		width: 100%;
		height: auto;
		max-height: 420px;
		object-fit: cover;
		object-position: center top;
	}

	.innov8-cs-section-hero > figcaption {
		padding: clamp(10px, 1.2vw, 14px) clamp(14px, 1.6vw, 20px);
		border-top: 1px solid var(--border-subtle);
		background: var(--color-ink-900);
		color: var(--fg-tertiary);
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		letter-spacing: 0.08em;
		line-height: var(--leading-snug);
		text-wrap: balance;
	}

	/* This rule (specificity 0,2,1) outranks the > * + * rule (0,1,0),
		so setting margin: 0 here would suppress the heading-to-image gap
		entirely — exactly the "heading touches the image" symptom. We
		zero only the side and bottom margins (stripping browser defaults)
		and explicitly carry the intended top spacing forward. 1.75em sits
		between the 1.5em prose rhythm and the h2's own 2em top margin,
		giving the heading → full-width-image transition enough air. */
	.innov8-cs-main > figure.innov8-cs-section-hero {
		margin: 1.75em 0 0;
	}

	/* ─── 5. Gallery ────────────────────────────────────────────────── */
	.innov8-cs-gallery {
		padding: clamp(48px, 6vw, 80px) 0;
		background: var(--color-ink-950);
		border-top: 1px solid var(--border-subtle);
	}

	/* Outer gallery container — vertical stack of platform-grouped
		rows. The legacy `repeat(auto-fit, minmax(...))` packing was
		replaced (Round 7) so each platform (Web / Tablet Web / Mobile
		Web) keeps its shots on its own line at medium+ breakpoints. */
	.innov8-cs-gallery-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: clamp(24px, 3vw, 40px);
	}

	/* Per-platform row — 1-col by default so shots stack vertically
		at small breakpoints; 2-col at medium+ so two shots of the
		same platform sit side-by-side on one line. */
	.innov8-cs-gallery-row {
		display: grid;
		grid-template-columns: 1fr;
		gap: clamp(16px, 2vw, 24px);
	}

	/* Web (laptop) row — horizontal padding at all breakpoints so
		the keyboard-base pseudo-element (which overhangs the screen
		frame by -4% on each side) doesn't touch the container edge.
		Applied to the row rather than the figure so the indent is
		layout-level, not chrome-level. */
	.innov8-cs-gallery-row-web {
		padding: 0 clamp(20px, 3vw, 60px);
	}

	@media (min-width: 640px) {
		.innov8-cs-gallery-row {
			grid-template-columns: repeat(2, 1fr);
		}

		/* Web (laptop) row override — each web screenshot lands on
			its own line at full container width. Laptop shots are
			landscape with dense detail; a 2-up layout cramps them.
			1-col here lets each screenshot get the real-estate it
			needs to be legible. Source-order tiebreak vs the generic
			`.innov8-cs-gallery-row` rule above lands us at 1-col. */
		.innov8-cs-gallery-row-web {
			grid-template-columns: 1fr;
		}
	}

	/* Empty rows (case studies missing a platform) hide cleanly so
		 the outer stack doesn't carry visible gaps. */
	.innov8-cs-gallery-row:empty {
		display: none;
	}

	.innov8-cs-gallery-item {
		margin: 0;
		display: flex;
		flex-direction: column;
		gap: 10px;
	}

	/* ─── 5.a Frame (default — passthrough for desktop "Web" shots) ──
		The `.innov8-cs-gallery-frame` wrapper sits between the figure
		and the image. For desktop "Web" screenshots it's effectively a
		noop — the image keeps the flat-border treatment it always had.
		For "Mobile Web" + "Tablet Web" platform values the frame picks
		up a device-bezel treatment (rules below). The default rule
		here only carries the hover/focus transition so motion is
		consistent across both modes. */
	.innov8-cs-gallery-frame {
		display: block;
		position: relative;
		transition:
			transform var(--duration-base) var(--ease-out),
			box-shadow var(--duration-base) var(--ease-out);
	}

	/* Screen viewport wrapper — sits between the bezel frame and the image.
		Constrains visible height to a realistic device aspect ratio; overflowing
		screenshot content scrolls within the frame rather than stretching the
		bezel to unrealistic proportions. Each device variant (5.b–5.d below)
		sets its own aspect-ratio. For non-framed screenshots this is a
		transparent passthrough (no aspect-ratio set, just display: block). */
	.innov8-cs-gallery-screen {
		display: block;
		width: 100%;
	}

	.innov8-cs-gallery-image {
		width: 100%;
		height: auto;
		display: block;
		border-radius: var(--radius-md);
		border: 1px solid var(--border-default);
		background: var(--color-ink-900);
		transition:
			border-color var(--duration-base) var(--ease-out),
			transform var(--duration-base) var(--ease-out);
	}

	.innov8-cs-gallery-item:hover .innov8-cs-gallery-image,
	.innov8-cs-gallery-item:focus-within .innov8-cs-gallery-image {
		border-color: var(--border-brand);
		transform: translateY(-2px);
	}

	.innov8-cs-gallery-caption {
		font-family: var(--font-mono);
		font-size: var(--text-overline);
		letter-spacing: 0.14em;
		text-transform: uppercase;
		color: var(--fg-tertiary);
	}

	/* ─── 5.b Web (laptop) device-frame ─────────────────────────────
		Thin-bezel laptop chrome around landscape browser screenshots.
		The frame is the screen; the `::before` + `::after` pseudo-
		elements draw the hinge seam + keyboard base below the screen,
		yielding a literal laptop silhouette in pure CSS. The base sits
		in absolute-position layout below the frame (outside the frame's
		box), so the frame's `overflow` is switched to `visible` (only
		for the web variant — mobile + tablet still clip to keep their
		pure-bezel reads clean). The frame's own `margin-bottom` reserves
		flow space so the figcaption clears the base. */
	.innov8-cs-gallery-item-web .innov8-cs-gallery-frame {
		padding: 8px;
		border-radius: 14px;
		background: linear-gradient(180deg, var(--color-ink-800) 0%, var(--color-ink-900) 50%, var(--color-ink-800) 100%);
		border: 1px solid var(--border-subtle);
		box-shadow:
			0 0 80px 10px rgb(95 236 253 / 0.18),
			0 0 24px rgb(95 236 253 / 0.22),
			0 14px 36px -10px rgb(0 0 0 / 0.55),
			0 2px 4px rgb(0 0 0 / 0.35),
			inset 0 1px 0 0 rgb(255 255 255 / 0.08);
		/* `position: relative` is already on the default frame rule,
			so the absolute-positioned pseudo-elements below anchor to
			the frame's box. */
		overflow: visible;
		margin-bottom: 20px;
	}

	/* Pseudo: hinge seam — the thin dark strip immediately below the
		screen edge. Matches the screen's horizontal width exactly so it
		reads as the gap where the screen folds down onto the chassis. */
	.innov8-cs-gallery-item-web .innov8-cs-gallery-frame::before {
		content: '';
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		height: 2px;
		background: var(--color-ink-1000);
		z-index: 1;
	}

	/* Pseudo: keyboard base — extends ~4% wider on each side than
		the screen, has a tray-like rounded-bottom shape (elliptical
		bottom-corner radius via the slash syntax), and carries its
		own depth shadow to suggest the laptop sitting on a surface. */
	.innov8-cs-gallery-item-web .innov8-cs-gallery-frame::after {
		content: '';
		position: absolute;
		top: calc(100% + 2px);
		left: -4%;
		right: -4%;
		/* Base height bumped 10px → 14px for more visual heft; the
			thinner version read undersized against the full-width
			laptop frame. Border-radius + box-shadow scaled to match. */
		height: 14px;
		background: linear-gradient(180deg, var(--color-ink-700) 0%, var(--color-ink-800) 55%, var(--color-ink-900) 100%);
		border: 1px solid var(--border-subtle);
		border-top: none;
		/* Elliptical bottom corners — gives the "tray" look without
			 needing a clip-path trapezoid. */
		border-radius: 0 0 14px 14px / 0 0 80% 80%;
		box-shadow: 0 8px 18px -4px rgb(0 0 0 / 0.55);
	}

	/* Screen: 16:9 — standard widescreen viewport proportions. Scrolls tall
		page screenshots within a correctly-sized screen area. The frame's
		overflow: visible is preserved so the ::after keyboard base renders
		outside the frame box — the screen wrapper isolates the scroll context.
		background-color: #000 fills the area below short screenshots so the
		viewport reads as a lit screen rather than exposing the bezel fill. */
	.innov8-cs-gallery-item-web .innov8-cs-gallery-screen {
		aspect-ratio: 16 / 9;
		overflow-y: auto;
		border-radius: 8px;
		background-color: #000;
		scrollbar-width: thin;
		scrollbar-color: var(--color-ink-600) transparent;
	}

	.innov8-cs-gallery-item-web .innov8-cs-gallery-image {
		border-radius: 8px;
		border: none;
		background: var(--color-ink-950);
	}

	.innov8-cs-gallery-item-web:hover .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-web:focus-within .innov8-cs-gallery-frame {
		transform: translateY(-2px);
		/* Hover intensifies the cyan halo + bumps shadow depth. */
		box-shadow:
			0 0 96px 12px rgb(95 236 253 / 0.28),
			0 0 30px rgb(95 236 253 / 0.32),
			0 18px 44px -8px rgb(0 0 0 / 0.65),
			0 4px 8px rgb(0 0 0 / 0.4),
			inset 0 1px 0 0 rgb(255 255 255 / 0.1);
	}

	.innov8-cs-gallery-item-web:hover .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-web:focus-within .innov8-cs-gallery-image {
		transform: none;
		border-color: transparent;
	}

	/* ─── 5.c Mobile-Web device-frame ───────────────────────────────
		Phone-bezel chrome around tall + narrow mobile screenshots.
		The frame:
			• Constrains itself to phone-aspect width (max 300px) so a
				phone shot never gets stretched wide inside a grid cell.
			• Centers in its grid cell via align-self on the figure.
			• Owns the outer rounded-corner geometry; the image inside
				carries a slightly tighter radius so the bezel reads as a
				uniform thickness around a rounded screen.
			• Layered shadow: ambient depth + crisp contact + inset
				highlight ring — sells "anodized chassis catches light"
				without drawing a literal notch or speaker. */
	/* Mobile App and Mobile Web share the phone-form-factor bezel treatment —
		native-app screenshots are visually indistinguishable from mobile-web
		shots in a gallery context, so the two platform variants are styled
		together via grouped selectors. Layout-level row ordering still
		separates them into distinct rows (Mobile App row before Mobile Web
		row by default) so the gallery can narrate "native app" vs. "responsive
		web" as a story beat when both are present. */
	.innov8-cs-gallery-item-mobile-web,
	.innov8-cs-gallery-item-mobile-app {
		align-self: center;
	}

	.innov8-cs-gallery-item-mobile-web .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-mobile-app .innov8-cs-gallery-frame {
		max-width: 300px;
		width: 100%;
		margin: 0 auto;
		padding: 10px;
		border-radius: 36px;
		background: linear-gradient(180deg, var(--color-ink-800) 0%, var(--color-ink-900) 50%, var(--color-ink-800) 100%);
		border: 1px solid var(--border-subtle);
		/* Five-layer shadow stack:
			1. Soft outer cyan halo — separates the dark frame from the
				dark section background. Subtle brand-tied glow.
			2. Tight cyan halo — focuses the glow at the edge for a
				more deliberate "this thing is luminous" read.
			3. Ambient depth shadow.
			4. Crisp contact shadow.
			5. Inset top-edge highlight ring — sells the "anodized
					chassis catches light" suggestion. */
		box-shadow:
			0 0 60px 6px rgb(95 236 253 / 0.18),
			0 0 18px rgb(95 236 253 / 0.22),
			0 12px 32px -8px rgb(0 0 0 / 0.55),
			0 2px 4px rgb(0 0 0 / 0.35),
			inset 0 1px 0 0 rgb(255 255 255 / 0.08);
		overflow: hidden;
	}

	/* Screen: 9:17 — practical phone viewport proportions. Replaces the former
		hard-coded max-height: 560px on the img which didn't scale proportionally
		as the frame narrowed on smaller viewports. The frame's overflow: hidden
		clips content at the outer bezel radius; the screen clips at the inner.
		background-color: #000 fills below short screenshots. */
	.innov8-cs-gallery-item-mobile-web .innov8-cs-gallery-screen,
	.innov8-cs-gallery-item-mobile-app .innov8-cs-gallery-screen {
		aspect-ratio: 9 / 17;
		overflow-y: auto;
		border-radius: 28px;
		background-color: #000;
		scrollbar-width: thin;
		scrollbar-color: var(--color-ink-600) transparent;
	}

	.innov8-cs-gallery-item-mobile-web .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-mobile-app .innov8-cs-gallery-image {
		border-radius: 28px;
		border: none;
		background: var(--color-ink-950);
	}

	/* Hover lifts the entire frame, not just the image, when in
		 device mode — the bezel is the affordance now. */
	.innov8-cs-gallery-item-mobile-web:hover .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-mobile-web:focus-within .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-mobile-app:hover .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-mobile-app:focus-within .innov8-cs-gallery-frame {
		transform: translateY(-2px);
		/* Hover state intensifies the cyan halo + bumps shadow depth. */
		box-shadow:
			0 0 72px 8px rgb(95 236 253 / 0.28),
			0 0 22px rgb(95 236 253 / 0.32),
			0 18px 44px -8px rgb(0 0 0 / 0.65),
			0 4px 8px rgb(0 0 0 / 0.4),
			inset 0 1px 0 0 rgb(255 255 255 / 0.1);
	}

	/* Suppress the legacy image-level hover lift inside the frame so
		 the frame + image don't double-translate. */
	.innov8-cs-gallery-item-mobile-web:hover .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-mobile-web:focus-within .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-mobile-app:hover .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-mobile-app:focus-within .innov8-cs-gallery-image {
		transform: none;
		border-color: transparent;
	}

	/* ─── 5.d Tablet-Web device-frame ───────────────────────────────
		Slate-tablet bezel — sits between the laptop and the phone in
		bezel thickness + corner radius. Frame width is unconstrained —
		tablet screenshots are closer to a desktop aspect so they fit
		the grid cell naturally. */
	.innov8-cs-gallery-item-tablet-web .innov8-cs-gallery-frame {
		padding: 14px;
		border-radius: 22px;
		background: linear-gradient(180deg, var(--color-ink-800) 0%, var(--color-ink-900) 50%, var(--color-ink-800) 100%);
		border: 1px solid var(--border-subtle);
		/* Five-layer shadow stack — matches the mobile variant but
			 sized for the larger tablet bezel (wider halo, deeper drop). */
		box-shadow:
			0 0 72px 8px rgb(95 236 253 / 0.18),
			0 0 22px rgb(95 236 253 / 0.22),
			0 14px 36px -10px rgb(0 0 0 / 0.55),
			0 2px 4px rgb(0 0 0 / 0.35),
			inset 0 1px 0 0 rgb(255 255 255 / 0.08);
		overflow: hidden;
	}

	/* Screen: 4:3 — standard tablet viewport proportions.
		background-color: #000 fills below short screenshots. */
	.innov8-cs-gallery-item-tablet-web .innov8-cs-gallery-screen {
		aspect-ratio: 4 / 3;
		overflow-y: auto;
		border-radius: 12px;
		background-color: #000;
		scrollbar-width: thin;
		scrollbar-color: var(--color-ink-600) transparent;
	}

	.innov8-cs-gallery-item-tablet-web .innov8-cs-gallery-image {
		border-radius: 12px;
		border: none;
		background: var(--color-ink-950);
	}

	.innov8-cs-gallery-item-tablet-web:hover .innov8-cs-gallery-frame,
	.innov8-cs-gallery-item-tablet-web:focus-within .innov8-cs-gallery-frame {
		transform: translateY(-2px);
		/* Hover state intensifies the cyan halo + bumps shadow depth. */
		box-shadow:
			0 0 88px 10px rgb(95 236 253 / 0.28),
			0 0 28px rgb(95 236 253 / 0.32),
			0 18px 44px -8px rgb(0 0 0 / 0.65),
			0 4px 8px rgb(0 0 0 / 0.4),
			inset 0 1px 0 0 rgb(255 255 255 / 0.1);
	}

	.innov8-cs-gallery-item-tablet-web:hover .innov8-cs-gallery-image,
	.innov8-cs-gallery-item-tablet-web:focus-within .innov8-cs-gallery-image {
		transform: none;
		border-color: transparent;
	}

	@media (prefers-reduced-motion: reduce) {
		.innov8-cs-gallery-frame,
		.innov8-cs-gallery-image,
		.innov8-cs-gallery-item:hover .innov8-cs-gallery-image,
		.innov8-cs-gallery-item:focus-within .innov8-cs-gallery-image,
		.innov8-cs-gallery-item-web:hover .innov8-cs-gallery-frame,
		.innov8-cs-gallery-item-web:focus-within .innov8-cs-gallery-frame,
		.innov8-cs-gallery-item-mobile-web:hover .innov8-cs-gallery-frame,
		.innov8-cs-gallery-item-mobile-web:focus-within .innov8-cs-gallery-frame,
		.innov8-cs-gallery-item-tablet-web:hover .innov8-cs-gallery-frame,
		.innov8-cs-gallery-item-tablet-web:focus-within .innov8-cs-gallery-frame {
			transition: none;
			transform: none;
		}
	}

	/* ─── 6. Related case studies ───────────────────────────────────── */
	/* The grid below intentionally reuses the `featured-work-card.njk`
		macro — same card visual language across both surfaces. The
		wrapper here just supplies the section frame + spacing; the card
		styling itself lives in the FEATURED WORK SECTION block above. */
	.innov8-cs-related {
		padding: clamp(56px, 7vw, 88px) 0 0;
		background: var(--color-ink-1000);
	}

	.innov8-cs-related-header {
		margin-bottom: clamp(28px, 3.6vw, 48px);
	}

	.innov8-cs-related-title {
		margin: 14px 0 0;
		max-width: 24ch;
		font-family: var(--font-display);
		font-weight: 700;
		font-size: clamp(28px, 3.2vw, 40px);
		line-height: var(--leading-snug);
		letter-spacing: var(--tracking-snug);
		color: var(--fg-primary);
		text-transform: uppercase;
		text-wrap: balance;
	}

	.innov8-cs-related-grid {
		display: grid;
		grid-template-columns: 1fr;
		gap: 0;
	}

	@media (min-width: 640px) {
		.innov8-cs-related-grid {
			grid-template-columns: repeat(2, 1fr);
		}
	}

	@media (min-width: 1024px) {
		.innov8-cs-related-grid {
			grid-template-columns: repeat(3, 1fr);
		}
	}

	.innov8-cs-related-footer {
		margin-top: clamp(28px, 4vw, 48px);
		padding-bottom: clamp(56px, 7vw, 88px);
	}

	.innov8-cs-related-view-all {
		display: inline-flex;
		align-items: center;
		gap: 10px;
		font-family: var(--font-mono);
		font-size: 15px;
		letter-spacing: 0.04em;
		color: var(--accent-spark);
		text-decoration: none;
		transition: gap var(--duration-base) var(--ease-out);
	}

	.innov8-cs-related-view-all:hover,
	.innov8-cs-related-view-all:focus-visible {
		gap: 14px;
		outline: none;
	}

	@media (prefers-reduced-motion: reduce) {
		.innov8-cs-related-view-all,
		.innov8-cs-related-view-all:hover,
		.innov8-cs-related-view-all:focus-visible {
			transition: none;
			gap: 10px;
		}
	}

	/* ─── 7. CTA banner ─────────────────────────────────────────────── */
	.innov8-cs-cta {
		padding: clamp(56px, 7vw, 88px) 0;
		background:
			radial-gradient(60% 80% at 0% 50%, rgba(31, 86, 245, 0.18), transparent 60%),
			radial-gradient(60% 80% at 100% 50%, rgba(95, 236, 253, 0.12), transparent 60%), var(--color-ink-950);
		border-top: 1px solid var(--border-subtle);
	}

	.innov8-cs-cta-inner {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: clamp(24px, 3vw, 40px);
	}

	.innov8-cs-cta-text {
		flex: 1 1 360px;
		min-width: 0;
	}

	.innov8-cs-cta-title {
		margin: 0 0 12px;
		max-width: 24ch;
		font-family: var(--font-display);
		font-weight: 700;
		font-size: clamp(28px, 3.2vw, 40px);
		line-height: var(--leading-snug);
		letter-spacing: var(--tracking-snug);
		color: var(--fg-primary);
		text-transform: uppercase;
		text-wrap: balance;
	}

	.innov8-cs-cta-lead {
		margin: 0;
		max-width: 56ch;
		font-family: var(--font-sans);
		font-size: var(--text-body-lg);
		line-height: var(--leading-base);
		color: var(--fg-secondary);
		text-wrap: pretty;
	}

	/* .innov8-cs-cta-button removed by #124 — consolidated into the global
		.innov8-cta-pill primitive in the BUTTONS section above. Markup
		callsites in case-study.njk + in-development-case-study.njk now use
		the primitive class directly. */
}
