/*
 * The products: the composed slide, the carousel's no-JS rail and its controls, the /products/ index
 * and the chip (includes/component.php, includes/carousel.php; design §1, §4, §5).
 *
 * One sheet for the four blocks, entered per block by wp_enqueue_block_style. Colour comes from two
 * places only, and neither is a literal (tools/audit/tokens.py):
 *   - the slide and the chip read the `--ti-product-*` variables the server prints in `style`,
 *     already measured by palette.php (text 4.5:1 on the stage, the light lowered until it holds);
 *     they may fall back to a contract token, never the other way round;
 *   - everything on the page field (heading, controls, index) reads the bare contract `--ti-*`.
 *
 * The carousel's state (stack, fade, is-active, is-leaving) is the theme's engine contract, in its
 * style.css. Here the rail is only what it is without script: a horizontal scroll-snap track where
 * every slide is readable and clickable. Nothing here starts hidden, nothing waits for an animation
 * to exist: no @keyframes, no view() timeline.
 */

/*
 * The single box: the band's inner width, the same box as the slide's frame and the hero's
 * .ti-arrival__panel, so the left edge of the band title, the slide's copy, the controls and "All
 * products" is the hero's (design §1, measured 0px apart on the mock).
 */
.ti-products-band__inner,
.ti-product__frame {
	box-sizing: border-box;
	max-width: var( --wp--style--global--wide-size, 86rem );
	margin-inline: auto;
	padding-inline: var( --wp--preset--spacing--40 );
}

/* In an article the reading column is the width: the box steps aside (0-2-1 beats 0-1-0). */
aside.ti-product--slide > .ti-product__frame {
	max-width: none;
	padding: 2rem;
	min-height: 0;
}

/* ---- The band ------------------------------------------------------------------------------- */

/* Under the title, contained; no rule under it (the stage below is the separation). */
.ti-products-band__head {
	margin-block-end: clamp( 1.5rem, 2.5vw, 2.25rem );
}

.ti-products-band__head .ti-section__title,
.ti-products-showcase__all .ti-section__title {
	color: var( --ti-strong );
}

.ti-products-band .ti-section__more {
	margin-block: 1.25rem 0;
}

.ti-products-band .ti-section__more a {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
}

/* ---- The carousel without script, and its frame -------------------------------------------- */

.ti-products-carousel {
	--ti-carousel-fade: 480ms;
}

/* The stage's edge, a page token: faint on the light page, the line that separates the default
 * stage from the dark page, where both are the canvas. */
.ti-products-carousel__viewport {
	box-shadow: 0 -1px 0 var( --ti-line ), 0 1px 0 var( --ti-line );
}

/* The engine's 0-3-0 stack (style.css) overrides this 0-1-0 rail once it has validated the markup. */
.ti-products-carousel__rail {
	display: flex;
	margin: 0;
	padding: 0;
	overflow-x: auto;
	list-style: none;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	scrollbar-color: var( --ti-accent ) var( --ti-well );
}

.ti-products-carousel__rail > li {
	flex: 0 0 100%;
	min-width: 0;
	margin: 0;
	scroll-snap-align: start;
}

/* ---- The composed slide ------------------------------------------------------------------- */

/*
 * The stage. Two classes: the default stage also carries .ti-counter-field (for --ti-line, focus and
 * selection inside it), whose own background and colour would otherwise win, the theme sheet loading
 * after the block sheets.
 */
.ti-product.ti-product--slide {
	position: relative;
	box-sizing: border-box;
	height: 100%;
	margin: 0;
	overflow: clip; /* the product's light never spills onto the page */
	isolation: isolate;
	container-type: inline-size;
	background: var( --ti-product-stage, var( --ti-field ) );
	color: var( --ti-product-ink, var( --ti-strong ) );
}

.ti-product__frame {
	display: grid;
	grid-template-columns: repeat( 12, minmax( 0, 1fr ) );
	column-gap: clamp( 1.25rem, 2.5vw, 2.25rem );
	align-items: center;
	min-height: clamp( 34rem, 42vw, 38rem );
	padding-block: clamp( 2.5rem, 5vw, 4.5rem ); /* width and inline padding: the single box above */
}

.ti-product__copy {
	grid-column: 1 / span 6;
	grid-row: 1;
	min-width: 0;
}

/*
 * Positioned for the light below, so it paints after the copy and above the primary link's stretched
 * ::after: without pointer-events none it took the click, and the logo or art led nowhere. Nothing in
 * it is interactive; the image's alt is still read.
 */
.ti-product__visual {
	position: relative;
	display: grid;
	grid-column: 7 / span 6;
	grid-row: 1;
	place-items: center;
	min-width: 0;
	pointer-events: none;
}

.ti-product--art .ti-product__copy {
	grid-column: 1 / span 5;
}

.ti-product--art .ti-product__visual {
	grid-column: 6 / span 7;
}

/*
 * The brand light: a radial glow centred on the visual, at half the strength palette.php measured.
 * Drawn behind the visual rather than on the slide's own background, so it follows the visual in
 * every layout (beside the copy, above it on a phone): a container cannot query its own width, and
 * the mock's per-layout glow position on the slide never applied. Light lies under no text it was
 * not measured against: the model's worst case is this glow plus the shadow below, at full strength.
 */
.ti-product__visual::before {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	z-index: -1;
	width: 52rem;
	height: 52rem;
	translate: -50% -50%;
	background: radial-gradient( closest-side, color-mix( in srgb, var( --ti-product-glow ) calc( var( --ti-product-glow-strength ) / 2 ), transparent ), transparent );
	pointer-events: none;
}

.ti-product--light-stage .ti-product__visual::before {
	content: none;
}

/* Display type: the only one on the slide. The bucket comes from component.php (length and longest word). */
.ti-product__name {
	margin: 0;
	color: var( --ti-product-ink, var( --ti-strong ) );
	font-family: var( --wp--preset--font-family--display );
	font-weight: 400;
	line-height: 0.95;
	letter-spacing: -0.035em;
	overflow-wrap: break-word; /* net only: breaks without a hyphen, never clips */
	hyphens: manual;
}

.ti-product__name--xx-large {
	font-size: var( --wp--preset--font-size--xx-large );
}

.ti-product__name--x-large {
	font-size: var( --wp--preset--font-size--x-large );
	line-height: 1;
	letter-spacing: -0.025em;
}

.ti-product__name--large {
	font-size: var( --wp--preset--font-size--large );
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.ti-product__pitch {
	max-width: 30ch;
	margin: clamp( 1rem, 1.6vw, 1.5rem ) 0 0;
	color: var( --ti-product-soft, var( --ti-quiet ) );
	font-family: var( --wp--preset--font-family--body );
	font-size: var( --wp--preset--font-size--large );
	line-height: 1.4;
	text-wrap: pretty;
	hyphens: manual;
}

.ti-product__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	margin: clamp( 1.75rem, 3vw, 2.5rem ) 0 0;
}

/* Buttons: one geometry for the slide and the index; colours per surface below. */
.ti-product__button {
	display: inline-flex;
	align-items: center;
	gap: 0.7rem;
	box-sizing: border-box;
	min-height: 3.25rem;
	padding: 0 1.5rem;
	border: 1.5px solid transparent;
	border-radius: 0;
	font-family: var( --wp--preset--font-family--body );
	font-size: 1.0625rem;
	font-weight: 600;
	line-height: 1.1;
	letter-spacing: 0.005em;
	text-decoration: none;
}

.ti-product__button svg {
	flex: none;
	width: 1.1rem;
	height: 1.1rem;
}

.ti-product__button:hover,
.ti-product__button:focus {
	text-decoration: none;
}

/* Hover and pressed reuse the measured pairs only: no colour enters that palette.php did not check. */
.ti-product__button:hover .ti-product__label {
	text-decoration-line: underline;
	text-decoration-thickness: 1.5px;
	text-underline-offset: 0.2em;
}

.ti-product__button:active {
	transform: translateY( 1px );
}

/*
 * The stretched link presses by its margins instead, the same 1px. A transform makes an element the
 * containing block of its absolute ::after: on mousedown the link's cover shrank to the button, the
 * mouseup landed on the frame, and a click anywhere on the slide but the button went nowhere
 * (measured in Chrome). The two margins cancel, so the actions line keeps its height.
 */
.ti-product__link:active {
	margin-block: 1px -1px;
	transform: none;
}

.ti-product--slide .ti-product__button--primary {
	background: var( --ti-product-action, var( --ti-strong ) );
	color: var( --ti-product-on-action, var( --ti-field ) );
}

.ti-product--slide .ti-product__button--secondary {
	border-color: var( --ti-product-ink, var( --ti-strong ) );
	background: transparent;
	color: var( --ti-product-ink, var( --ti-strong ) );
}

.ti-product--slide .ti-product__button--secondary:hover {
	background: var( --ti-product-ink, var( --ti-strong ) );
	color: var( --ti-product-stage, var( --ti-field ) );
}

.ti-product--slide .ti-product__button--secondary:hover .ti-product__label {
	text-decoration-line: none;
}

.ti-product--slide .ti-product__button:focus-visible {
	outline: 2px solid var( --ti-product-ink, var( --ti-strong ) );
	outline-offset: 4px;
}

/* The one link of the product covers the whole slide or row: the visual is the way in. */
.ti-product__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

/* "Read the article" is a real link above the stretched one. */
.ti-product__story {
	position: relative;
	z-index: 1;
}

/* The visual. Every image declares its proportion: logos from the attachment, inline. Nothing is cropped. */
.ti-product__logo {
	display: block;
	height: auto;
	aspect-ratio: var( --ti-product-logo-ratio, auto );
}

/* Icon: the logo as an object, a tile with the product's own light under it (the app-icon shape is
 * the slide's one rounded corner). */
.ti-product__logo--icon {
	width: min( 100%, 24rem );
	border-radius: 22.5%;
	box-shadow:
		0 0 0 1px color-mix( in srgb, var( --ti-product-ink ) 9%, transparent ),
		0 2.75rem 6rem -1.5rem color-mix( in srgb, var( --ti-product-glow ) var( --ti-product-glow-strength ), transparent ),
		0 1rem 2.5rem -1rem color-mix( in srgb, var( --ti-shade ) 35%, transparent );
}

/* Mark: straight on the stage. A symbol is sized like the icon; a wordmark (>= 2.5:1) is held small,
 * so it accompanies the display name instead of repeating it at the same size. */
.ti-product__logo--mark {
	width: auto;
	max-width: min( 100%, 22rem );
	max-height: 20rem;
}

.ti-product__logo--wordmark {
	max-width: min( 100%, 18rem );
}

/* Wide artwork: whole, square corners like the rest of the site; the text never sits on it. */
.ti-product__art {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1200 / 630;
	object-fit: contain;
	box-shadow:
		0 2.5rem 5rem -2rem color-mix( in srgb, var( --ti-product-glow ) var( --ti-product-glow-strength ), transparent ),
		0 1rem 2.5rem -1rem color-mix( in srgb, var( --ti-shade ) 35%, transparent );
}

/* A light stage takes no shadow (shade under dark text would lower its contrast): a hairline separates. */
.ti-product--light-stage .ti-product__logo--icon,
.ti-product--light-stage .ti-product__art {
	box-shadow: 0 0 0 1px color-mix( in srgb, var( --ti-product-ink ) 12%, transparent );
}

/* The same slide in the article column and on a phone: by the slide's own width, not the window's. */
@container ( max-width: 47.99rem ) {
	.ti-product__frame {
		grid-template-columns: minmax( 0, 1fr );
		row-gap: 2rem;
		align-content: start;
		min-height: 0;
	}

	.ti-product__copy,
	.ti-product--art .ti-product__copy {
		grid-column: 1;
		grid-row: 2;
	}

	.ti-product__visual,
	.ti-product--art .ti-product__visual {
		grid-column: 1;
		grid-row: 1;
		justify-items: start;
	}

	.ti-product__visual::before {
		inset-inline-start: 5.5rem;
		width: 26rem;
		height: 26rem;
	}

	.ti-product__logo--icon {
		width: clamp( 8rem, 38cqi, 11rem );
	}

	.ti-product__logo--mark {
		max-width: min( 100%, 11rem );
		max-height: 9rem;
	}

	.ti-product__logo--wordmark {
		max-width: min( 100%, 12rem );
	}

	.ti-product__actions {
		flex-direction: column;
		align-items: stretch;
	}

	.ti-product__button {
		justify-content: center;
	}
}

/* The reading column: the logo beside the copy, not above it with half the stage empty. */
@container ( min-width: 36rem ) and ( max-width: 47.99rem ) {
	.ti-product__actions {
		flex-direction: row;
		align-items: center;
	}

	.ti-product--logo .ti-product__frame {
		grid-template-columns: minmax( 0, 13rem ) minmax( 0, 1fr );
		column-gap: 2rem;
		align-items: center;
	}

	.ti-product--logo .ti-product__visual {
		grid-column: 1;
		grid-row: 1;
	}

	.ti-product--logo .ti-product__copy {
		grid-column: 2;
		grid-row: 1;
	}

	.ti-product--logo .ti-product__logo--icon {
		width: 100%;
	}

	.ti-product--logo .ti-product__visual::before {
		inset-inline-start: 50%;
		width: 30rem;
		height: 30rem;
	}
}

/* In an article: the still slide sits apart from the paragraphs around it; the end call stacks them. */
.wp-block-ti-products-product > aside.ti-product--slide {
	margin-block: clamp( 1.5rem, 3vw, 2.5rem );
}

.ti-products-related {
	display: grid;
	gap: clamp( 1.25rem, 2.5vw, 1.75rem );
	margin-block-start: clamp( 2.5rem, 5vw, 4rem );
}

/* ---- The controls: on the page field, under the stage, the same contrast for every product ---- */

/* The controls element is the size container; the bar inside it is the grid it queries for. */
.ti-carousel__controls {
	margin-block-start: 1rem;
	container-type: inline-size;
}

.ti-carousel__controls[hidden],
.ti-carousel__control[hidden],
.ti-carousel__control [hidden] {
	display: none;
}

.ti-carousel__bar {
	display: grid;
	grid-template-areas: "pause dots prev next";
	grid-template-columns: auto minmax( 0, 1fr ) auto auto;
	align-items: center;
	column-gap: 0.25rem;
}

.ti-carousel__control {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	background: transparent;
	color: var( --ti-strong );
	cursor: pointer;
}

.ti-carousel__control svg {
	width: 1rem;
	height: 1rem;
}

.ti-carousel__control--pause {
	grid-area: pause;
}

.ti-carousel__control--previous {
	grid-area: prev;
}

.ti-carousel__control--next {
	grid-area: next;
}

/* Gap 0: adjacent 44px targets; the visible bars keep 0.5rem apart through their own inset. */
.ti-carousel__dots {
	display: grid;
	grid-area: dots;
	grid-auto-columns: minmax( 2.75rem, 9rem );
	grid-auto-flow: column;
	justify-content: start;
	gap: 0;
	min-width: 0;
	margin: 0 0 0 0.5rem;
	padding: 0;
	list-style: none;
}

.ti-carousel__dots > li {
	min-width: 0;
	margin: 0;
}

/* Reduced motion has no autoplay, so the engine hides the pause button. Its empty column and the
 * column gap would still push the indicators 12px inside the shared edge (measured at 1440): the
 * indicators take the pause area instead. The phone layout already gives them a row of their own. */
@container not ( max-width: 30rem ) {
	.ti-carousel__bar:has( > .ti-carousel__control--pause[hidden] ) {
		grid-template-areas: "dots dots prev next";
	}

	.ti-carousel__bar:has( > .ti-carousel__control--pause[hidden] ) > .ti-carousel__dots {
		margin-inline-start: 0;
	}
}

.ti-carousel__dot {
	position: relative;
	display: block;
	width: 100%;
	min-height: 44px;
	padding: 0.85rem 0.5rem 0 0;
	border: 0;
	background: transparent;
	color: var( --ti-muted );
	font-family: var( --wp--preset--font-family--body );
	font-size: var( --wp--preset--font-size--small );
	font-weight: 600;
	line-height: 1.2;
	text-align: start;
	cursor: pointer;
}

/* The full name stays in the DOM: the accessible name starts with what is seen (2.5.3). */
.ti-carousel__dot-name {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* Without names on screen the bar is what identifies the control: the muted ink, above 3:1. */
.ti-carousel__dot::before {
	content: "";
	position: absolute;
	inset: 0 0.5rem auto 0;
	height: 2px;
	background: var( --ti-muted );
}

.ti-carousel__dot[aria-current="true"] {
	color: var( --ti-strong );
}

.ti-carousel__dot[aria-current="true"]::before {
	height: 4px;
	background: var( --ti-strong );
}

.ti-carousel__control:focus-visible,
.ti-carousel__dot:focus-visible {
	outline: 2px solid var( --ti-accent );
	outline-offset: 4px;
}

/* Names only where the row is wide; below, bars centred in the 44px target. */
@container ( max-width: 60rem ) {
	.ti-carousel__dot {
		padding: 0;
	}

	.ti-carousel__dot::before {
		inset: calc( 50% - 1px ) 0.25rem auto 0.25rem;
	}

	.ti-carousel__dot[aria-current="true"]::before {
		inset-block-start: calc( 50% - 2px );
	}

	.ti-carousel__dot-name {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset( 50% );
		white-space: nowrap;
	}
}

/* A phone: up to six indicators (6 x 44px = 264px) get their own row; 320px leaves 272px. */
@container ( max-width: 30rem ) {
	.ti-carousel__bar {
		grid-template-areas: "dots dots dots dots" "pause . prev next";
		row-gap: 0.25rem;
	}

	.ti-carousel__dots {
		margin: 0;
	}
}

/* ---- /products/ ------------------------------------------------------------------------------ */

/* The stage meets the header, as the hero does on the home page (design review, NIT 1). 0-2-0, so the
 * order of this sheet and the theme's does not matter. */
.ti-section.ti-products-showcase {
	padding-block-start: 0;
}

/* The pattern's screen-reader h1 comes first, so the flow layout's block gap (24px measured at 1440)
 * would open a light strip above the stage: the block starts at the header instead. */
.ti-products-showcase > .ti-products-showcase__content {
	margin-block-start: 0;
}

.ti-products-showcase__empty-wrap {
	padding-block-start: var( --wp--preset--spacing--60 );
}

.ti-products-showcase__empty {
	max-width: 52ch;
	margin: clamp( 1rem, 2vw, 1.5rem ) 0 0;
	color: var( --ti-muted );
	font-size: var( --wp--preset--font-size--medium );
}

.ti-products-showcase__all {
	padding-block-start: clamp( 3.25rem, 5vw, 5rem );
}

/* The index: lines ruled apart, not a grid of cards, and without the pitch. */
.ti-products-showcase__rows {
	margin-block-start: clamp( 1.5rem, 2.5vw, 2.25rem );
	border-block-start: 1px solid var( --ti-line );
	container-type: inline-size;
}

.ti-product--row {
	position: relative;
	display: grid;
	grid-template-columns: auto minmax( 0, 1fr ) auto;
	align-items: center;
	gap: 1rem clamp( 1rem, 2.5vw, 2rem );
	margin: 0;
	padding-block: clamp( 1rem, 2vw, 1.5rem );
	border-block-end: 1px solid var( --ti-line );
}

.ti-product--row .ti-product__name {
	color: var( --ti-strong );
	font-size: var( --wp--preset--font-size--large );
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.ti-product--row .ti-product__actions {
	margin: 0;
}

.ti-product--row .ti-product__button {
	min-height: 44px;
	padding-inline: 1.1rem;
	font-size: var( --wp--preset--font-size--medium );
}

/* The index's buttons are the page's: the page ink, never the ticket's red. */
.ti-product--row .ti-product__button--primary {
	background: var( --ti-strong );
	color: var( --ti-field );
}

.ti-product--row .ti-product__button--secondary {
	border-color: var( --ti-strong );
	background: transparent;
	color: var( --ti-strong );
}

.ti-product--row .ti-product__button--secondary:hover {
	background: var( --ti-strong );
	color: var( --ti-field );
}

.ti-product--row .ti-product__button--secondary:hover .ti-product__label {
	text-decoration-line: none;
}

.ti-product--row .ti-product__button:focus-visible {
	outline: 2px solid var( --ti-accent );
	outline-offset: 4px;
}

/* A phone: chip and name on the first line, the buttons under them. */
@container ( max-width: 40rem ) {
	.ti-product--row {
		grid-template-columns: auto minmax( 0, 1fr );
	}

	.ti-product--row .ti-product__actions {
		grid-column: 1 / -1;
	}
}

/* ---- The chip: the logo on the product's stage colour, or the wide artwork ------------------- */

.ti-product-chip {
	display: grid;
	flex: none;
	place-items: center;
	overflow: hidden;
	background: var( --ti-product-stage, var( --ti-field ) );
}

.ti-product-chip--row {
	inline-size: 4rem;
	aspect-ratio: 1;
}

.ti-product-chip--row.ti-product-chip--art {
	inline-size: 7.5rem;
	aspect-ratio: 1200 / 630;
}

.ti-product-chip__image {
	display: block;
	box-sizing: border-box;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

/* A mark sits on its stage with room around it; an icon is its own plate, in the app-icon shape. */
.ti-product-chip--mark .ti-product-chip__image {
	padding: 0.5rem;
}

.ti-product-chip--icon {
	border-radius: 22.5%;
}

/* ---- The editor's notice for a block whose product is not chosen or not shown. Editor only. ---- */

.ti-product-placeholder {
	margin: 0;
	padding: 1rem 1.25rem;
	border: 1px dashed var( --ti-line );
	color: var( --ti-muted );
	font-size: var( --wp--preset--font-size--small );
}

@media ( prefers-reduced-motion: reduce ) {
	.ti-product__button:active {
		transform: none;
	}
	/* The stretched link presses by its margins, not by transform: both go (design §1). */
	.ti-product__link:active {
		margin-block: 0;
	}
}
