/**
 * Services page DICIT VISIO (template-parts/services/services-visio.php).
 *
 * Image left, text and a one-at-a-time accordion right. No section header
 * spans the page: the eyebrow, headline and description live in the right
 * column, which is what makes the section open straight into its columns.
 */

.visio {
	padding-block: var(--section-pad-y);
}

/* --------------------------------------------------------------------
 * Two columns
 *
 * 45fr/55fr rather than 45%/55%: percentages plus the gap would sum past
 * the container. The columns split what is left after the gap, in 45:55,
 * which is the ratio the ruling asks for. 64px is the gap used by
 * deliver__header, contact and what-we-do, so it needs no new number.
 *
 * The DOM is content first, image second. Desktop places them explicitly
 * instead of reordering, so below the switch the source order IS the layout
 * and nothing has to be undone.
 * -------------------------------------------------------------------- */

.visio__layout {
	display: grid;
	grid-template-columns: 45fr 55fr;
	gap: 64px;
	align-items: stretch;
}

.visio__content {
	grid-column: 2;
	grid-row: 1;
}

.visio__media {
	grid-column: 1;
	grid-row: 1;
	position: relative;
	min-height: 0; /* the picture must never drive the row height */
	border-radius: 6px;
	overflow: hidden;
}

/* Absolutely positioned so the image takes the height the CONTENT column
   sets rather than contributing its own intrinsic height back into the row,
   which would make the two columns size each other. */
.visio__image {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* With no image there is no left column to balance. */
.visio__layout--text-only {
	grid-template-columns: 1fr;
}

.visio__layout--text-only .visio__content {
	grid-column: 1;
}

/* --------------------------------------------------------------------
 * Text stack. Spacing is the site's measured convention: 32px under the
 * eyebrow, 32px from headline to running text, 64px to the next block.
 * -------------------------------------------------------------------- */

.visio .eyebrow {
	margin-bottom: 32px;
}

.visio__text {
	margin-top: 32px;
	font-size: var(--type-body-lg-size);
	line-height: var(--type-body-lg-line);
	letter-spacing: var(--type-body-lg-spacing);
	font-weight: var(--type-body-lg-weight);
	color: var(--color-body-text);
}

.visio__accordion {
	margin-top: 64px;
}

/* --------------------------------------------------------------------
 * Accordion rows
 *
 * Hairlines between rows plus a closing line under the last, so the set
 * reads as one block rather than six boxes.
 * -------------------------------------------------------------------- */

.visio__item {
	border-top: 1px solid var(--color-border-subtle);
}

.visio__item:last-child {
	border-bottom: 1px solid var(--color-border-subtle);
}

/* The heading exists so the triggers are a real heading level inside the
   section, not for its own type: the button carries the styling. */
.visio__heading {
	margin: 0;
}

.visio__trigger {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 24px;
	width: 100%;
	padding: 20px 0;
	border: 0;
	background: none;
	cursor: pointer;
	text-align: left;
	font-family: var(--font-heading);
	font-size: var(--type-h4-size);
	line-height: var(--type-h4-line);
	letter-spacing: var(--type-h4-spacing);
	font-weight: var(--type-h4-weight);
	color: var(--color-heading-text);
}

.visio__chevron {
	flex-shrink: 0;
	display: flex;
	color: var(--color-text-secondary);
}

/* --------------------------------------------------------------------
 * Expand in place
 *
 * grid-template-rows 0fr -> 1fr with the inner wrapper at min-height 0 and
 * overflow hidden, per the house mechanism in deliver.css. Never max-height.
 * That one is hover-driven; this one is driven by accordion.js.
 *
 * The RESTING state here is open. accordion.js adds .is-enhanced, which is
 * what switches the closed state on, so a visitor with JS blocked reads all
 * six bodies instead of one. Same contract as fade-in.js.
 * -------------------------------------------------------------------- */

.visio__panel {
	display: grid;
	grid-template-rows: 1fr;
}

.visio__panel-inner {
	min-height: 0;
	overflow: hidden;
}

.visio__body {
	padding-bottom: 24px;
	font-size: var(--type-body-size);
	line-height: var(--type-body-line);
	font-weight: var(--type-body-weight);
	color: var(--color-body-text);
}

.visio__accordion.is-enhanced .visio__panel {
	grid-template-rows: 0fr;
}

/* Collapsed copy leaves the accessibility tree as well as the viewport, so
   a screen reader is not read six bodies when one is open. */
.visio__accordion.is-enhanced .visio__panel-inner {
	visibility: hidden;
}

.visio__accordion.is-enhanced .visio__item.is-open .visio__panel {
	grid-template-rows: 1fr;
}

.visio__accordion.is-enhanced .visio__item.is-open .visio__panel-inner {
	visibility: visible;
}

/* --------------------------------------------------------------------
 * Motion, switched on one frame AFTER the initial state is applied so the
 * page does not load with six panels animating shut. The chevron shares the
 * panel's duration and curve exactly, so the rotation and the opening read
 * as one gesture.
 *
 * visibility cannot be transitioned, so it is delayed instead: held until
 * the collapse has finished, and released immediately on opening. The
 * reduced-motion block in base.css zeroes both duration and delay, so the
 * state still changes there and nothing waits.
 * -------------------------------------------------------------------- */

.visio__accordion.is-ready .visio__panel {
	transition: grid-template-rows 650ms var(--motion-ease);
}

.visio__accordion.is-ready .visio__panel-inner {
	transition: visibility 0s linear 650ms;
}

.visio__accordion.is-ready .visio__item.is-open .visio__panel-inner {
	transition-delay: 0s;
}

.visio__accordion.is-ready .visio__chevron {
	transition: transform 650ms var(--motion-ease);
}

.visio__item.is-open .visio__chevron {
	transform: rotate(180deg);
}

/* --------------------------------------------------------------------
 * Height reservation
 *
 * The image column stretches to the content column, so without this the
 * picture resizes every time the reader opens a different item. Measured
 * across the six open states at 1440 with representative copy, the content
 * column ranged 700.6px to 751.8px: 51px of movement, past the threshold
 * where it stops being imperceptible.
 *
 * accordion.js publishes the tallest state as --accordion-reserve and
 * re-measures it after fonts load and on resize, so the value tracks the
 * real copy rather than a number frozen from the placeholder text.
 *
 * It is width-dependent and must never be hardcoded: the same six bodies
 * reserved 504px at a 686px column and 555px at a 499px one, because a
 * narrower column rewraps the longest body onto more lines.
 *
 * Only above the layout switch: below it the image is stacked underneath,
 * where a shorter open state moves nothing beside it and a reservation
 * would just leave dead space above the picture.
 * -------------------------------------------------------------------- */

@media (min-width: 1025px) {
	.visio__accordion.is-enhanced {
		min-height: var(--accordion-reserve, 0px);
	}
}

/* --------------------------------------------------------------------
 * Responsive: one column, content above the image.
 *
 * Nothing imposes a height on the picture once it is stacked, so it flows
 * at its natural ratio: no crop, and no invented aspect number. The house
 * rule bans aspect-ratio outright and a min-height floor here would only be
 * guessing at a shape the design has not specified.
 * -------------------------------------------------------------------- */

@media (max-width: 1024px) {
	.visio__layout {
		grid-template-columns: 1fr;
		gap: 48px;
	}

	.visio__content,
	.visio__media {
		grid-column: auto;
		grid-row: auto;
	}

	.visio__media {
		position: static;
	}

	.visio__image {
		position: static;
		height: auto;
	}
}
