/**
 * Single Blog Post — Layout, Callout block, Author bio, Related posts
 *
 * Loaded only on is_singular('post') via ad_enqueue_single_post() in
 * functions.php.
 *
 * Includes:
 *   - 40/60 Offset layout (sticky featured image left, body right)
 *   - Callout block (atomicdust/callout) — inline mobile, fixed-stage desktop
 *   - Featured image overlay (gradient + title injected by JS)
 *   - Author chip + meta row + tags
 *   - Author bio card
 *   - Related posts grid
 *
 * Carved out of custom.css (2026-05-18, batch 3).
 */

/* ==========================================================================
   Single Post — 40/60 Offset Layout

   Desktop: CSS grid places featured image in col 1 of row 2 and the article
   body in col 3 of row 2 (header/footer/bio span row 2 boundaries in col 3
   so they're aligned with the body). position:sticky on the featured image
   handles the "image locks to viewport while body scrolls" effect — no
   ScrollTrigger.pin needed. The image naturally releases when row 2 (the
   article body's row) ends, which is exactly the footer boundary.

   The scrub tween in single-featured.js animates the image from viewport-
   wide down to its grid-cell width (40vw) over the first 500px of scroll.
   Because the image never leaves flow, there's no release snap.
   ========================================================================== */

.ad-single__featured {
	margin-block-start: 0;
}

.ad-single__featured img {
	aspect-ratio: 16 / 9;
	object-fit: cover;
	width: 100%;
}

@media (min-width: 1024px) {
	main.wp-block-group.ad-single {
		display: grid;
		grid-template-columns: 40% 3rem 1fr;
	}

	/* All sections default to the right column (aligns with the body). */
	.ad-single > * {
		grid-column: 3;
		min-width: 0;
	}

	.ad-single__header { grid-row: 1; }

	.ad-single__featured {
		grid-column: 1;
		grid-row:    2;
		position:    sticky;
		top:         var(--ad-header-height);
		align-self:  start;
		/* Initial paint: break out of col 1 and cover the full viewport so
		   the image reads as a hero. z-index keeps it above the body (which
		   lives in col 3 and would otherwise show through on the right). The
		   JS scrub collapses width back to 40vw on scroll, uncovering body. */
		width:     100vw;
		max-width: 100vw;
		z-index:   1;
	}

	.ad-single__body   {
		grid-row: 2;
		/* Offset body content down by the full-bleed image's height (16:9 of
		   100vw = 56.25vw) so it sits BELOW the image instead of behind it
		   in col 3. As the user scrolls, the body cell rises naturally and
		   the image (sticky at top) shrinks — the two motions roughly cancel
		   so the body's first line trails the image's shrinking bottom edge
		   throughout the scrub, never crossing into the image's region.

		   Use padding-top (not position:relative + top): `top` only shifts
		   paint without growing the layout box, so grid row 2 sized to the
		   body's intrinsic height and the painted body bottom overflowed
		   into row 3 (footer/bio). padding-top expands row 2 by 56.25vw so
		   the footer/bio start where the body actually ends visually, and
		   the sticky image releases at the painted body's bottom as intended. */
		padding-top: 56.25vw;
	}
	.ad-single__footer { grid-row: 3; }
	.ad-single__bio    { grid-row: 4; }

	/* Admin bar offsets the sticky top position (32px at >=1024px, always). */
	body.admin-bar .ad-single__featured {
		top: calc( var(--ad-header-height) + 32px );
	}
}

/* ==========================================================================
   Callout block (atomicdust/callout)

   - Mobile / tablet (< 1024px): renders inline in the body as a soft callout.
   - Desktop (>= 1024px): the body copy is hidden, and callout-stage.js
     mounts each callout into a fixed stage at the lower-left of the
     viewport (col 1, beneath the featured image). Activation is driven by
     the reader's scroll position — see callout-stage.js for the trigger
     spec.
   ========================================================================== */

.ad-callout {
	margin: 1.5rem 0;
	padding: 1.25rem 1.5rem;
	background: var(--wp--preset--color--muted);
	border-radius: 0.25rem;
	font-size: var(--wp--preset--font-size--md);
	color: var(--wp--preset--color--primary);
}

.ad-callout > * {
	margin: 0;
}
.ad-callout > * + * {
	margin-top: 0.75rem;
}

@media (min-width: 1024px) {
	/* Hide the inline body copy on desktop — the sidebar stage has the
	   visible version. The body copy still occupies its scroll position
	   so the IntersectionObserver can use it as a trigger anchor. */
	.ad-single__body .ad-callout {
		visibility: hidden;
		margin: 0;
		padding: 0;
		background: none;
	}

	/* Stage — fixed to the lower-left of the viewport, matching col 1. */
	.ad-single__callout-stage {
		position:      fixed;
		bottom:        2rem;
		left:          0;
		width:         40vw;
		max-width:     40vw;
		padding:       0 var(--wp--preset--spacing--40);
		z-index:       2;
		pointer-events: none;
	}

	body.admin-bar .ad-single__callout-stage {
		bottom: calc( 2rem + 32px );
	}

	/* Each slot stacks at the bottom of the stage; only one is `is-active`
	   at a time. Default state = below + invisible. Active = in place +
	   opaque. Leaving = above + invisible (cleared after the transition). */
	.ad-single__callout-stage__slot {
		position:    absolute;
		bottom:      0;
		left:        0;
		right:       0;
		padding:     0 var(--wp--preset--spacing--40);
		opacity:     0;
		transform:   translateY( 16px );
		transition:  opacity 350ms ease-out, transform 400ms ease-out;
		pointer-events: none;
	}

	.ad-single__callout-stage__slot.is-active {
		opacity:   1;
		transform: translateY( 0 );
	}

	.ad-single__callout-stage__slot.is-leaving {
		opacity:   0;
		transform: translateY( -16px );
	}

	/* Editorial styling inside the stage — strip the soft-card backdrop
	   the inline version uses, lean into a quote-like presence. */
	.ad-single__callout-stage .ad-callout {
		background: none;
		padding:    0;
		margin:     0;
		font-size:  var(--wp--preset--font-size--lg);
		font-weight: 400;
		line-height: 1.4;
		color:      var(--wp--preset--color--primary);
	}
}

/* Featured image — gradient + title overlay (injected by JS) */
.ad-single__featured img {
	display: block;
}

.ad-single__featured-overlay {
	position: relative;
	display: inline-block;
	width: 100%;
}

.ad-single__featured-gradient {
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
	height: 50%;
	background: linear-gradient(to top, rgba(0, 0, 0, 0.55) 0%, transparent 100%);
	opacity: 0;
	pointer-events: none;
}

.ad-single__featured-title {
	position: absolute;
	bottom: 1.25rem;
	left: 1.25rem;
	right: 1.25rem;
	margin: 0;
	color: var(--wp--preset--color--secondary);
	font-family: var(--wp--preset--font-family--sohne);
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 400;
	line-height: 1.3;
	opacity: 0;
	pointer-events: none;
}

/* Author — circle avatar + name aligned horizontally */
.ad-single__author {
	display: flex !important;
	flex-direction: row !important;
	align-items: center !important;
	gap: 0.125rem !important;
}

.ad-single__author .wp-block-post-author__avatar {
	flex-shrink: 0;
	line-height: 0;
}

.ad-single__author .wp-block-post-author__avatar img {
	border-radius: 50%;
	display: block;
}

.ad-single__author .wp-block-post-author__content {
	display: flex;
	align-items: center;
}

.ad-single__author .wp-block-post-author__name {
	font-weight: 400;
	margin: 0;
}

/* Author team link — bottom border draw-on */
.ad-single__author-link {
	color: inherit;
	text-decoration: none;
	background-image: linear-gradient(var(--wp--preset--color--primary), var(--wp--preset--color--primary));
	background-size: 0% 1px;
	background-position: left bottom;
	background-repeat: no-repeat;
	transition: background-size 0.3s ease;
}

.ad-single__author-link:hover,
.ad-single__author-link:focus-visible {
	background-size: 100% 1px;
}

@media (prefers-reduced-motion: reduce) {
	.ad-single__author-link {
		transition: none;
	}
}

/* Meta row — align author and date to same center line */
.ad-single__meta {
	align-items: center !important;
}

.ad-single__meta .wp-block-post-date {
	display: flex;
	align-items: center;
}

/* Tags — badge pills matching insights card style */
.ad-single__tags {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	margin-block-start: 0.75rem;
}

.ad-single__tags a {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	padding: 0.375rem 0.875rem;
	border-radius: 0.125rem;
	background: var(--wp--preset--color--muted);
	color: var(--wp--preset--color--primary);
	text-decoration: none;
	font-size: var(--wp--preset--font-size--xs);
}

.ad-single__tags a::after {
	content: '+';
}

.ad-single__tags .wp-block-post-terms__separator {
	display: none;
}

/* ==========================================================================
   Single Post — Author Bio Card
   Avatar on the left, stacked [name → position → bio] on the right.
   The !important-heavy .ad-single__author row styles above (needed for the
   small meta-row author chip) also apply here via shared classes, so the
   bio-card rules below must re-declare layout with !important to win.
   ========================================================================== */

.ad-single__bio-card {
	background: var(--wp--preset--color--muted);
	border-radius: 0.5rem;
	padding: 2rem;
	display: flex !important;
	flex-direction: row !important;
	align-items: flex-start !important;
	gap: 1.5rem !important;
	flex-wrap: nowrap !important;
}

.ad-single__bio-card .wp-block-post-author__avatar {
	flex-shrink: 0;
	line-height: 0;
}

.ad-single__bio-card .wp-block-post-author__avatar img {
	border-radius: 50%;
	display: block;
	width: 96px;
	height: 96px;
	object-fit: cover;
}

/* Override the small-author rule (`display:flex; align-items:center`) so
   the name + bio stack vertically inside the content column. */
.ad-single__bio-card .wp-block-post-author__content {
	display: flex !important;
	flex-direction: column !important;
	align-items: flex-start !important;
	flex-grow: 1;
	gap: 0.25rem;
	padding-top: 0.125rem;
}

.ad-single__bio-card .wp-block-post-author__name {
	font-size: var(--wp--preset--font-size--lg);
	font-weight: 500;
	color: var(--wp--preset--color--primary);
	line-height: 1.2;
	margin: 0;
}

.ad-single__bio-card .wp-block-post-author__name a {
	color: inherit;
	text-decoration: none;
}

.ad-single__bio-card .wp-block-post-author__name a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* Role / position injected after the name from the matching team CPT post. */
.ad-single__bio-card .ad-single__bio-role {
	font-size: var(--wp--preset--font-size--sm);
	color: var(--wp--preset--color--body);
	margin: 0;
}

.ad-single__bio-card .wp-block-post-author__bio {
	color: var(--wp--preset--color--body);
	font-size: var(--wp--preset--font-size--sm);
	line-height: 1.6;
	margin: 0.5rem 0 0;
}

@media (max-width: 599px) {
	.ad-single__bio-card {
		flex-direction: column !important;
		align-items: flex-start !important;
		gap: 1rem !important;
	}
}

/* ==========================================================================
   Single Post — Related Posts
   ========================================================================== */

.ad-single-related {
	margin-block-start: 0;
}

.ad-single-related .wp-block-query.ad-single-related__grid {
	margin-block-start: 2rem;
}

.ad-single-related .wp-block-post-template.is-layout-grid {
	row-gap: clamp(2.5rem, 5vw, 4rem);
}
