/**
 * 组件样式。颜色与字号只使用 theme.json 令牌。
 *
 * WordPress 会把 slug h1 编成 --wp--preset--font-size--h-1。
 * 再给未加连字符的名字做别名，避免全局样式仍指向 --h1。
 */

:root {
	--wp--preset--font-size--h1: var(--wp--preset--font-size--h-1);
	--wp--preset--font-size--h2: var(--wp--preset--font-size--h-2);
	--wp--preset--font-size--h3: var(--wp--preset--font-size--h-3);
	--wp--preset--font-size--h4: var(--wp--preset--font-size--h-4);

	--tg-topbar-height: 38px;
	--tg-header-height: 88px;
	--tg-header-height-lg: calc(var(--tg-topbar-height) + 88px);
}

/* Heading sizes live in theme.json's `elements` (h1 → display, h2 → h2, …) and, on secondary
 * pages, in the `document` block-style variation (`styles/document.json`). They are NOT repeated
 * here: core wraps a variation's selectors in `:where()`, so any bare `h1 { font-size: … }` rule
 * in this file outranks it and silently cancels the whole variation. */

:where(a, button, input, select, textarea, summary):focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

/* Primary buttons get a two-tone ring.
 *
 * The accent outline above was drawn in the button's own colour on the button's own background —
 * measured, `outline: 2px solid #2E682E` on `background: #2E682E`, so a keyboard user saw nothing.
 * A white ring hugged by a dark one stays visible on the accent fill, on paper, and on the dark
 * bands, which is what a focus indicator has to do. */
:where(.wp-element-button, .wp-block-button__link, .tg-btn):focus-visible {
	outline: 2px solid var(--wp--preset--color--surface);
	outline-offset: 2px;
	box-shadow: 0 0 0 5px var(--wp--preset--color--ink);
}

.tg-skip {
	position: absolute;
	left: var(--wp--preset--spacing--40);
	top: 0;
	z-index: 100;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
	text-decoration: none;
	transform: translateY(-120%);
}

.tg-skip:focus {
	transform: translateY(var(--wp--preset--spacing--40));
	outline-color: var(--wp--preset--color--paper);
}

.tg-container {
	box-sizing: border-box;
	width: min(var(--wp--custom--container--default), 100%);
	margin-inline: auto;
	padding-inline: clamp(24px, 5vw, 56px);
}

.tg-header,
.tg-footer,
.tg-main {
	margin-block: 0;
}

.tg-header {
	position: relative;
	/* The header must own a stacking context above the page. Without it the nav submenu panel
	 * (z-index 2/20, absolute) ties with core's `.wp-block-cover__inner-container` (z-index 2,
	 * relative) in the root context, and the later hero in the DOM wins — so the front page's
	 * headline painted straight over the open dropdown and the menu read as "transparent"
	 * (measured 2026-10-18). 30 sits above page content and the product page's sticky section bar
	 * (20), below the scrolled header state (50) and the skip link/lightbox (100), and matches the
	 * language menu inside the same header. */
	z-index: 30;
	background: var(--wp--preset--color--paper);
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

.tg-header__bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-start;
	gap: var(--wp--preset--spacing--40);
	/* DESIGN §4: the header is 88px including its 1px bottom rule; content is vertically centred. */
	min-height: 87px;
	padding-block: 0;
	max-width: 100%;
}

/* Top info bar (T-317): a quiet contact strip above the main bar on desktop; small screens keep the
 * same links in the footer and on the contact page. The social icons carry the four approved
 * profiles (D-093); a network with no URL renders nothing rather than a slot. */
.tg-topbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	min-height: var(--tg-topbar-height);
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

.tg-topbar__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-topbar__list li {
	margin: 0;
}

.tg-topbar a {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
}

.tg-topbar a:hover {
	color: var(--wp--preset--color--accent);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-topbar__icon svg {
	display: block;
	width: 16px;
	height: 16px;
}

@media (max-width: 1023px) {
	.tg-topbar {
		display: none;
	}
}

.tg-logo {
	display: inline-flex;
	line-height: 0;
	text-decoration: none;
}

.tg-logo img {
	display: block;
	width: auto;
	height: 28px;
}

.tg-logo {
	flex: 0 0 auto;
}

.tg-menu-btn {
	display: none;
	align-items: center;
	justify-content: center;
	gap: var(--wp--preset--spacing--20);
	min-width: 44px;
	min-height: 44px;
	margin-left: auto;
	padding: 0 var(--wp--preset--spacing--40);
	background: transparent;
	border: 1px solid var(--wp--preset--color--ink);
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1;
	cursor: pointer;
}

/* Three-bar hamburger (owner 2026-10-22). The bars are drawn in CSS rather than shipped as an
 * icon: three spans, one border-radius, and the open state turns them into a cross with
 * transforms — no SVG file, no extra request, and the whole control still measures 44px. */
.tg-menu-btn__bars {
	display: inline-flex;
	flex-direction: column;
	justify-content: center;
	gap: 4px;
	width: 18px;
	height: 14px;
	flex: 0 0 auto;
}

.tg-menu-btn__bars > span {
	display: block;
	width: 100%;
	height: 2px;
	background: currentColor;
	border-radius: 1px;
	transform-origin: center;
	transition: transform var(--wp--custom--motion--fast), opacity var(--wp--custom--motion--fast);
}

.tg-menu-btn[aria-expanded="true"] .tg-menu-btn__bars > span:nth-child(1) {
	transform: translateY(6px) rotate(45deg);
}

.tg-menu-btn[aria-expanded="true"] .tg-menu-btn__bars > span:nth-child(2) {
	opacity: 0;
}

.tg-menu-btn[aria-expanded="true"] .tg-menu-btn__bars > span:nth-child(3) {
	transform: translateY(-6px) rotate(-45deg);
}

.tg-menu-btn:hover {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.tg-nav {
	display: none;
	align-items: center;
	justify-content: flex-end;
	flex: 1 1 auto;
	gap: var(--wp--preset--spacing--40);
	min-width: 0;
	max-width: 100%;
}

.tg-nav__menu {
	flex: 1 1 auto;
	min-width: 0;
	max-width: 100%;
}

.tg-nav .wp-block-navigation__container {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
	width: auto;
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-nav .wp-block-navigation-item {
	position: relative;
}

.tg-nav .wp-block-navigation-item__content {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding: 4px 0;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.3;
	text-decoration: none;
	white-space: nowrap;
}

.tg-nav .wp-block-navigation-item__content:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-nav__menu .wp-block-navigation-item__content[aria-current="page"],
.tg-nav__menu .current-menu-item > .wp-block-navigation-item__content,
.tg-nav__menu .wp-block-navigation-submenu__toggle[aria-current="page"] {
	font-weight: 700;
	text-decoration: underline;
	text-decoration-color: var(--wp--custom--color--logo);
	text-decoration-thickness: 2px;
	text-underline-offset: 4px;
}

/* The logo green is the brand's own colour and the owner asked to keep it on the current item
 * (D-33), but its label measured 1.97:1 on white. The palette has no darker approved green, so the
 * text moves to `accent-dark` (the palette's own dark brand, 8.6:1) and the underline keeps the logo
 * green — the underline stays as the redundant marker, so the current page is still marked twice. */
.tg-nav__menu .wp-block-navigation-item__content[aria-current="page"],
.tg-nav__menu .current-menu-item > .wp-block-navigation-item__content,
.tg-nav__menu .wp-block-navigation-submenu__toggle[aria-current="page"] {
	color: var(--wp--preset--color--accent-dark);
}

.tg-nav .wp-block-navigation__submenu-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding: 0;
	background: transparent;
	border: 0;
	color: var(--wp--preset--color--ink);
	cursor: pointer;
}

.tg-nav .wp-block-navigation__submenu-container {
	position: absolute;
	top: 100%;
	/* Pin both edges so WordPress's own justify-right offset (it computes a negative `left` to
	 * right-align the panel, which pushed it 176px away from its trigger) cannot move it. */
	left: 0;
	right: auto;
	min-width: 16rem;
	width: max-content;
	max-width: min(24rem, calc(100vw - 48px));
	margin: 0;
	padding: var(--wp--preset--spacing--20) 0;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--rule);
	list-style: none;
	z-index: 20;
	display: none;
	/* WordPress clips the panel while it animates; with a hover-opened panel that clipping is what
	 * collapsed it to an 18px sliver and hid the four links. `visible` keeps the full list, and the
	 * max-height transition is not used here at all. */
	overflow: visible;
	max-height: none;
	flex-direction: column;
}

/* WordPress right-aligns every submenu under `items-justified-right`
 * (`.wp-block-navigation.items-justified-right .wp-block-navigation__container .has-child
 * .wp-block-navigation__submenu-container { left:auto; right:0 }`, four classes). That put the
 * Products panel 120px to the left of its own trigger, where it read as a detached box. This
 * selector carries five classes so it wins, and the panel sits under the item it belongs to.
 * The last items are pulled right again below so they cannot run past the viewport edge. */
.tg-nav .wp-block-navigation__container .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container {
	left: 0;
	right: auto;
}

.tg-nav .wp-block-navigation__container > .wp-block-navigation-item.has-child:nth-last-child(-n + 2) > .wp-block-navigation__submenu-container {
	left: auto;
	right: 0;
}

/* Hover opens the dropdown on a pointer device (owner 2026-10-22, following the two reference
 * sites). This is the *addition*, never the only way in: `focus-within` still opens it for the
 * keyboard and the click handler in `nav.js` still opens it for touch, so the DESIGN.md rule
 * "no hover-only menus" holds. `:hover` is scoped to `(hover: hover)` so a phone does not leave a
 * submenu stuck open after a tap. The pointer gap between trigger and panel is bridged by a
 * transparent pseudo-element, otherwise moving the mouse down crosses dead space and the panel
 * closes before it is reached. */
@media (hover: hover) and (pointer: fine) {
	.tg-nav .wp-block-navigation-item.has-child:hover > .wp-block-navigation__submenu-container {
		display: block;
	}

	.tg-nav .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container::before {
		content: "";
		position: absolute;
		inset-inline: 0;
		bottom: 100%;
		height: var(--wp--preset--spacing--20);
	}
}

/* What opens a panel: `.is-open` (hover and tap, set by `nav.js`) and keyboard focus.
 *
 * Keyboard is spelled `:has(> toggle:focus-visible)` rather than plain `:focus-within`, because a
 * tap also focuses the button. With `:focus-within`, tapping an open item could never close it —
 * focus put the panel straight back — and the phone accordion had two things deciding its state.
 *
 * `visibility` is forced as well as `display`: core sets `visibility: hidden` on the container and
 * only its own state machine clears it, so a panel we opened on tap stayed invisible even at
 * `display: block`. Four classes beat core's three.
 */
.tg-nav .wp-block-navigation__container .wp-block-navigation-item.is-open > .wp-block-navigation__submenu-container,
.tg-nav .wp-block-navigation__container .wp-block-navigation-item:has(> .wp-block-navigation-submenu__toggle:focus-visible) > .wp-block-navigation__submenu-container {
	display: block;
	visibility: visible;
}

.tg-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	white-space: normal;
	height: auto;
	padding: 8px var(--wp--preset--spacing--50);
}

.tg-header .wp-block-navigation__responsive-container-open,
.tg-header .wp-block-navigation__responsive-container-close {
	display: none;
}

.tg-header .wp-block-navigation__responsive-container {
	display: block;
	position: static;
	width: auto;
	height: auto;
	padding: 0;
	background: transparent;
}

.tg-nav__contact {
	flex: 0 0 auto;
	max-width: 100%;
}

.tg-nav__contact .wp-block-button__link {
	padding-inline: var(--wp--preset--spacing--40);
}

.tg-lang {
	position: relative;
	display: flex;
	align-items: center;
	flex: 0 0 auto;
	max-width: 100%;
	margin: 0;
}

.tg-header__bar > p:has(> .tg-logo),
.tg-nav > p:has(> .tg-lang) {
	display: contents;
	margin: 0;
}

.tg-lang__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--wp--preset--spacing--10);
	min-width: 44px;
	min-height: 44px;
	padding: 0 var(--wp--preset--spacing--20);
	background: transparent;
	border: 0;
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1;
	cursor: pointer;
}

.tg-lang__chevron {
	display: block;
	width: 12px;
	height: 12px;
}

.tg-lang__menu {
	position: absolute;
	z-index: 30;
	top: 100%;
	inset-inline-end: 0;
	min-width: 11.5rem;
	max-width: calc(100vw - 48px);
	margin: 0;
	padding: var(--wp--preset--spacing--10) 0;
	list-style: none;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--rule);
}

.tg-lang__menu[hidden] {
	display: none;
}

.tg-lang__menu a {
	display: flex;
	align-items: baseline;
	gap: var(--wp--preset--spacing--30);
	min-height: 44px;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.3;
	text-decoration: none;
	white-space: nowrap;
}

.tg-lang__menu a:hover,
.tg-lang__menu a[aria-current="page"] {
	color: var(--wp--preset--color--ink);
}

.tg-lang__menu a[aria-current="page"] {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-lang__name {
	color: var(--wp--preset--color--ink-muted);
	font-weight: 400;
}

@media (min-width: 1280px) {
	.tg-header__bar {
		flex-wrap: nowrap;
	}

	.tg-nav {
		display: flex;
		margin-left: auto;
	}

	.tg-nav .wp-block-navigation__container {
		flex-wrap: nowrap;
	}

	.tg-nav .wp-block-navigation-item {
		display: flex;
		align-items: center;
	}

	.tg-nav .wp-block-navigation-item__content {
		font-size: 0.9375rem;
	}

	.tg-lang,
	.tg-nav__contact,
	.tg-nav .wp-block-navigation {
		align-self: center;
		margin-block: 0;
	}

	/* 箭头贴在标签后 4px，条目右缘就是箭头右缘，项与项只留同一条间距. */
	.tg-nav .wp-block-navigation__container > .has-child > .wp-block-navigation-item__content {
		padding-inline-end: calc(12px + var(--wp--preset--spacing--10));
	}

	.tg-nav .wp-block-navigation-item > .wp-block-navigation__submenu-icon {
		position: absolute;
		inset-inline-end: 0;
		top: 0;
		justify-content: flex-end;
		margin: 0;
	}

	.tg-nav .wp-block-navigation__submenu-icon svg {
		display: block;
		width: 12px;
		height: 12px;
	}
}

@media (max-width: 1279px) {
	.tg-menu-btn {
		display: inline-flex;
	}

	.tg-nav[data-open="true"] {
		display: flex;
		position: absolute;
		left: 0;
		right: 0;
		top: 100%;
		z-index: 45;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: var(--wp--preset--spacing--50) clamp(24px, 5vw, 56px) var(--wp--preset--spacing--70);
		background: var(--wp--preset--color--surface);
		border-bottom: 1px solid var(--wp--preset--color--rule);
	}

	.tg-nav .wp-block-navigation,
	.tg-nav .wp-block-navigation__container,
	.tg-nav .wp-block-navigation-item,
	.tg-lang,
	.tg-nav__contact {
		margin: 0;
	}

	.tg-nav .wp-block-navigation__container {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		width: 100%;
		padding: 0;
	}

	.tg-nav .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
		box-sizing: border-box;
		align-items: center;
		justify-content: flex-start;
		white-space: normal;
		min-height: 48px;
		padding: 0;
		line-height: 1;
	}

	.tg-nav .wp-block-navigation__container > .wp-block-navigation-item {
		min-height: 48px;
	}

	.tg-lang {
		align-self: stretch;
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		width: 100%;
		margin: 0;
	}

	.tg-lang__toggle {
		padding-inline: 0;
	}

	.tg-lang__menu {
		position: static;
		inset: auto;
		width: 100%;
		min-width: 0;
		max-width: none;
		margin: 0;
		padding: 0 0 0 var(--wp--preset--spacing--40);
		background: transparent;
		border: 0;
		border-left: 1px solid var(--wp--preset--color--rule);
	}

	.tg-nav .wp-block-navigation__submenu-container {
		position: static;
		width: 100%;
		min-width: 0;
		max-width: 100%;
		border: 0;
		border-left: 1px solid var(--wp--preset--color--rule);
		padding-left: var(--wp--preset--spacing--40);
	}

	/* Core's `.wp-block-navigation .has-child .wp-block-navigation__submenu-container` carries three
	 * classes and sets `position: absolute`, so the two-class rule above never applied on a phone
	 * and an opened submenu floated over the items beneath it. Same declarations, five classes, so
	 * it wins and the list flows: opening Products pushes Applications down instead of covering it.
	 *
	 * This needs the state machine to cooperate: with the list flowing, a panel that closes while a
	 * finger is still down re-flows everything and the tap lands on whatever slid under it. That is
	 * why `nav.js` closes the previous panel on `click`, not on `focusout` — see its comment. */
	.tg-nav .wp-block-navigation__container .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container {
		position: static;
		width: 100%;
		min-width: 0;
		max-width: 100%;
		border: 0;
		border-left: 1px solid var(--wp--preset--color--rule);
		padding-left: var(--wp--preset--spacing--40);
	}

	/* The row wraps instead of stacking: `flex-wrap` keeps the label and its chevron on one line
	 * and drops the expanded panel onto its own full-width line beneath them. A plain column
	 * direction put the chevron on a line of its own, and `align-items: center` (from the desktop
	 * flex row) had left the label floating halfway down beside its own panel. */
	.tg-nav .wp-block-navigation__container .wp-block-navigation-item.has-child {
		flex-wrap: wrap;
		align-items: center;
	}

	.tg-nav .wp-block-navigation__container .wp-block-navigation-item.has-child > .wp-block-navigation__submenu-container {
		flex: 0 0 100%;
		order: 3;
	}

	/* A closed panel still occupies ~16px of padding, because core keeps it at `display: flex` and
	 * only hides its contents. In a flowing list that is a visible gap after every collapsed item. */
	.tg-nav .wp-block-navigation__container .wp-block-navigation-item.has-child:not(.is-open) > .wp-block-navigation__submenu-container {
		display: none;
		visibility: hidden;
	}
}

.tg-wordmark {
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: 1.25rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	line-height: 1;
}

.tg-main {
	padding-block: var(--wp--custom--section--padding);
}

.wp-block-post-excerpt,
.wp-block-post-excerpt__excerpt {
	max-width: 100%;
	overflow-wrap: anywhere;
}

.tg-main h1 {
	max-width: 22em;
	text-wrap: balance;
}

.tg-main :where(p, figcaption, dd) {
	max-width: 62ch;
}

.tg-main h2 {
	margin-top: var(--wp--preset--spacing--80);
}

.tg-main h2:first-child,
.tg-section h2:first-child,
.tg-cta-band h2 {
	margin-top: 0;
}

.tg-main :where(p, li) {
	line-height: 1.6;
}

.tg-main a,
.tg-footer a {
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	transition: text-decoration-thickness 150ms;
}

.tg-main a:hover,
.tg-footer a:hover {
	text-decoration-thickness: 2px;
}

.tg-main :where(ul, ol) {
	padding-left: var(--wp--preset--spacing--50);
}

.tg-main li + li {
	margin-top: var(--wp--preset--spacing--20);
}

.tg-main figcaption {
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-main details {
	max-width: 62ch;
	border-bottom: 1px solid var(--wp--preset--color--rule);
	padding-block: var(--wp--preset--spacing--40);
}

/* P1-9: an FAQ item is as wide as the column it sits in. `details.tg-faq__item` is named on its
 * own because the items on the Applications children sit directly in a `.tg-split__body` with no
 * `.tg-faq` wrapper — there the 62ch reading cap left them 92px narrower than the table above. */
.tg-main .tg-faq,
.tg-main .tg-faq details,
.tg-main details.tg-faq__item,
.tg-main .tg-related,
.tg-main .tg-related li,
.tg-main .tg-insight-list li {
	max-width: none;
	width: 100%;
}

.tg-main details:first-of-type {
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-main summary {
	font-weight: 600;
	cursor: pointer;
}

.tg-main details p {
	margin-top: var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--ink-muted);
}

/* Serif only for the article / story body; breadcrumbs, meta, related rows and CTA bands stay grotesk. */
.tg-longform .tg-main .wp-block-post-content :where(p, li):not(:where(.tg-cta-band, .tg-breadcrumbs, .tg-related, .tg-article__meta) *) {
	max-width: 66ch;
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--body-serif);
	line-height: 1.7;
}

.tg-longform .tg-main :is(.tg-ruled, .tg-related, .tg-insight-list, .tg-faq) li {
	max-width: none;
}

.tg-longform .tg-main :where(h1, h2, h3, summary) {
	font-family: var(--wp--preset--font-family--grotesk);
}

.tg-footer {
	background: var(--wp--preset--color--slate);
	color: var(--wp--preset--color--paper);
}

.tg-footer__inner {
	padding-block: var(--wp--preset--spacing--80);
}

.tg-footer a {
	color: var(--wp--preset--color--paper);
	text-decoration: none;
}

/* T-327: one link rule for the whole footer — hover/focus only, like the nav links. */
.tg-footer a:hover,
.tg-footer a:focus-visible {
	color: var(--wp--preset--color--surface);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-footer__meta {
	max-width: 62ch;
	margin: var(--wp--preset--spacing--30) 0 0;
	font-size: var(--wp--preset--font-size--small);
}

.tg-footer__grid {
	display: grid;
	gap: var(--wp--preset--spacing--70);
}

/* Column headings are small, uppercase and muted; the links below stay `paper`. */
.tg-footer h2 {
	margin: 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--slate-muted);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	line-height: 1.4;
	text-transform: uppercase;
}

.tg-footer__strapline {
	margin: var(--wp--preset--spacing--30) 0 0;
	max-width: 30ch;
	font-size: 1.125rem;
	line-height: 1.5;
	text-wrap: balance;
}

.tg-footer__certs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	margin: var(--wp--preset--spacing--50) 0 0;
}

/* T-339: six pills, three per row — the sixth (REACH) used to hang on its own line.
 * Owner review 2026-10-15: `max-content` let each column size itself, so the FCC pill (which shares
 * a column with REACH) came out wider than CE and UKCA. Equal `1fr` columns give every pill the
 * same box. */
.tg-footer__certs-list {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--20);
}

.tg-footer__certs .tg-icon {
	width: 16px;
	height: 16px;
	flex: none;
	color: var(--wp--preset--color--paper);
}

/* T-328: the approved certification list as small pills — the trust element the owner asked to
 * strengthen. Replace with real badge artwork once the assets exist (Q-010). */
.tg-footer__cert {
	padding: 3px 8px;
	border: 1px solid var(--wp--preset--color--slate-muted);
	border-radius: 999px;
	color: var(--wp--preset--color--paper);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.04em;
	line-height: 1.3;
	text-align: center;
}

.tg-footer__links {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

/* Hours and address are not links: muted, so the links keep the emphasis. */
.tg-footer__links li:not(:has(a)) {
	color: var(--wp--preset--color--slate-muted);
}

/* Footer navigation is the core Navigation block (T-318 / D-33); keep the quiet footer link look. */
.tg-footer__nav {
	margin: 0;
}

.tg-footer__nav .wp-block-navigation__container {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-footer__nav .wp-block-navigation-item__content {
	color: var(--wp--preset--color--paper);
	font-size: 1rem;
	text-decoration: none;
}

.tg-footer__nav .wp-block-navigation-item__content:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-footer__rule {
	border: 0;
	border-top: 1px solid var(--wp--preset--color--rule);
	margin: var(--wp--preset--spacing--80) 0 var(--wp--preset--spacing--50);
}

.tg-footer__legal {
	max-width: none;
	margin: 0;
	color: var(--wp--preset--color--slate-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-footer__legal a {
	margin-left: var(--wp--preset--spacing--50);
}

/* Social icons: two placements only (P0-6) — the utility bar (32px, one tone, unlabelled) and
 * the footer brand column (44px, `slate-muted` → `paper` on hover). `/contact/` keeps its own
 * Follow row, in the same monochrome treatment. There is no brand-hue variant any more: the
 * closing band's coloured row T-645 added was the only place on the site that broke the
 * palette, and it is gone with the row itself. */
.tg-social {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-social li + li {
	margin-top: 0;
}

.tg-social a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

/* Top bar: the same social links, at utility-bar scale. The 44px hit area used on Contact and in
 * the closing band is taller than the 38px top bar and would push it open. */
.tg-topbar .tg-social {
	gap: var(--wp--preset--spacing--10);
	margin-inline-start: auto;
}

.tg-topbar .tg-social a {
	width: 32px;
	height: 32px;
	color: var(--wp--preset--color--ink-muted);
}

.tg-topbar .tg-social svg {
	width: 16px;
	height: 16px;
}

.tg-topbar .tg-social a:hover {
	color: var(--wp--preset--color--accent);
}

/* Footer brand column (P0-6): under the certification pills, on `slate`. Monochrome
 * `slate-muted` at rest and `paper` on hover/focus, so the row reads as secondary and never
 * competes with the nav columns beside it. */
.tg-footer .tg-social {
	margin-top: var(--wp--preset--spacing--40);
}

.tg-footer .tg-social a {
	color: var(--wp--preset--color--slate-muted);
}

.tg-footer .tg-social svg {
	width: 20px;
	height: 20px;
}

.tg-footer .tg-social a:hover,
.tg-footer .tg-social a:focus-visible {
	color: var(--wp--preset--color--paper);
}

/* Placeholder-free since 2026-10-19 (D-093): every network in `tg_social_links()` has a real
 * profile URL, so the shortcode only ever prints links. There is no `.tg-social__slot` any more —
 * a network without a URL is omitted from the list instead of drawn as a dead icon. */
.tg-social a:hover {
	color: var(--wp--preset--color--accent);
}

.tg-social svg {
	display: block;
	width: 24px;
	height: 24px;
	fill: currentColor;
}

/* Contact-information card in the closing band (T-645). Icon + value rows, no labels, as in the
 * client's reference. Values come from tg_public_contact() — the same source as the header
 * utility bar — so the band and /contact/ cannot drift apart. */
.tg-contact-info {
	display: grid;
	gap: var(--wp--preset--spacing--30);
	margin: var(--wp--preset--spacing--60) 0 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-contact-info li + li {
	margin-top: 0;
}

.tg-contact-info__item,
.tg-contact-info__link {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
}

.tg-contact-info__link {
	color: inherit;
	text-decoration: none;
}

.tg-contact-info__link:hover .tg-contact-info__value {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-contact-info__icon {
	display: inline-flex;
	flex: none;
	color: var(--wp--preset--color--accent-dark);
}

.tg-contact-info__icon svg {
	display: block;
	width: 20px;
	height: 20px;
}

@media (min-width: 640px) and (max-width: 899px) {
	.tg-footer__grid {
		grid-template-columns: 1fr 1fr;
	}

	.tg-footer__grid > :nth-child(1) {
		grid-column: 1 / -1;
	}
}

/* T-327: the same 12-column grid as the closing band, so the nav columns and the band's
 * right column share a line. Brand (no social row since D-076) / Solutions / Company / Resources /
 * Contact. */
@media (min-width: 900px) {
	.tg-footer__grid {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		column-gap: var(--wp--preset--spacing--60);
		row-gap: var(--wp--preset--spacing--70);
	}

	.tg-footer__grid > :nth-child(1) { grid-column: 1 / 4; }
	.tg-footer__grid > :nth-child(2) { grid-column: 4 / 6; }
	.tg-footer__grid > :nth-child(3) { grid-column: 6 / 8; }
	.tg-footer__grid > :nth-child(4) { grid-column: 8 / 10; }
	.tg-footer__grid > :nth-child(5) { grid-column: 10 / 13; }
}

.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.tg-whatsapp {
	position: fixed;
	right: max(16px, env(safe-area-inset-right));
	bottom: max(16px, env(safe-area-inset-bottom));
	z-index: 40;
	width: 56px;
	height: 56px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--surface);
	text-decoration: none;
}

.tg-whatsapp:hover {
	background: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--surface);
}

.tg-whatsapp:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

.tg-whatsapp svg {
	display: block;
	width: 28px;
	height: 28px;
	fill: currentColor;
}

@media (max-width: 1280px) {
	.tg-whatsapp {
		bottom: max(96px, calc(24px + env(safe-area-inset-bottom)));
	}
}
/* Contact information and the footer retain the direct WhatsApp link, so avoid a redundant floating control there. */
@media (max-width: 1280px) {
	.tg-contact-page ~ .wp-block-template-part .tg-whatsapp {
		display: none;
	}
}


.tg-breadcrumbs {
	margin: 0 0 var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--small);
}

.tg-breadcrumbs ol {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-breadcrumbs ol {
	padding-left: 0;
}

.tg-main .tg-breadcrumbs li + li {
	margin-top: 0;
}

.tg-breadcrumbs li {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
}

/* Separator trails each crumb, so a wrapped line never starts with "/". */
.tg-breadcrumbs li:not(:last-child)::after {
	content: "/";
	content: "/" / "";
	color: var(--wp--preset--color--ink-muted);
}

.tg-breadcrumbs a {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
}

.tg-breadcrumbs a:hover {
	color: var(--wp--preset--color--ink);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-breadcrumbs [aria-current="page"] {
	color: var(--wp--preset--color--ink);
}

.tg-ruled {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-ruled__row {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	padding-block: var(--wp--preset--spacing--50);
	border-bottom: 1px solid var(--wp--preset--color--rule);
	color: inherit;
	text-decoration: none;
}

/* The category index on /products/ is the only way into a category from the archive, and its rows
 * measured 16–18px tall at 375px — a link a thumb has to aim at. The rows keep their hairline and
 * their rhythm; the link inside the row simply reaches the touch minimum, which is what a desktop
 * pointer wants too. */
a.tg-ruled__row {
	min-height: 44px;
}

.tg-main .tg-category-index a.tg-ruled__row {
	align-content: center;
	padding-block: var(--wp--preset--spacing--30);
}

@media (min-width: 900px) {
	.tg-ruled__row {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		gap: var(--wp--preset--spacing--50);
		align-items: baseline;
	}

	.tg-ruled__row:not(:has(.tg-ruled__desc)) {
		grid-template-columns: minmax(0, 1fr);
	}
}

.tg-ruled__title {
	font-weight: 600;
	font-size: var(--wp--preset--font-size--h-3);
	/* The row's 24px padding is the air; inheriting the body's 1.6 gave the title a 43px
	 * line box at 1280 and pushed it off the description's first baseline. 114px → 102px
	 * for a two-line row, 92px → 82px for a title-only one. */
	line-height: 1.25;
}

.tg-ruled__desc {
	color: var(--wp--preset--color--ink-muted);
	max-width: 62ch;
	line-height: 1.5;
}

a.tg-ruled__row:hover .tg-ruled__title {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-main .tg-ruled {
	padding-left: 0;
}

.tg-main .tg-ruled li + li {
	margin-top: 0;
}

.tg-spec {
	margin: var(--wp--preset--spacing--60) 0 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-spec__row {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	padding-block: var(--wp--preset--spacing--40);
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

/* Same 5/7 split as the ruled rows below it, so a page that uses both reads as one column of
 * definition rows rather than a narrow table next to a wide list. */
@media (min-width: 900px) {
	.tg-spec__row {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		gap: var(--wp--preset--spacing--50);
		align-items: baseline;
	}
}

.tg-spec dt {
	color: var(--wp--preset--color--ink-muted);
}

.tg-spec dd {
	margin: 0;
}

/* 按钮：随文案变宽，可折成两行，不设固定宽度（D-25）。 */
.wp-block-buttons {
	flex-wrap: wrap;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--40);
	max-width: 100%;
}

.wp-block-button {
	width: auto;
	max-width: 100%;
	height: auto;
}


.tg-card {
	position: relative;
}

.tg-card .tg-card__link a::after,
.tg-card .wp-block-post-title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.tg-card:focus-within {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 3px;
}

.tg-chip {
	display: inline-block;
	margin: 0 6px 4px 0;
	padding: 2px 8px;
	border-radius: var(--wp--custom--radius--s, 8px);
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--accent-dark);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.4;
}


.wp-block-button__link {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: auto;
	max-width: 100%;
	height: auto;
	min-height: 48px;
	margin: 0;
	padding: 12px var(--wp--preset--spacing--50);
	border: 1px solid transparent;
	border-radius: var(--wp--custom--radius--button);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
	line-height: 1.25;
	text-align: center;
	text-decoration: none;
	white-space: normal;
	overflow-wrap: break-word;
	transition: background-color 150ms, color 150ms, border-color 150ms;
}

.wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--surface);
}

.wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--surface);
}

.wp-block-button.is-style-outline .wp-block-button__link {
	background: transparent;
	border-color: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--ink);
}

.wp-block-button.is-style-outline .wp-block-button__link:hover {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.wp-block-button__link:disabled,
.wp-block-button__link[aria-disabled="true"] {
	background: var(--wp--preset--color--rule);
	border-color: var(--wp--preset--color--rule);
	color: var(--wp--preset--color--ink-muted);
	cursor: not-allowed;
}

.has-slate-background-color :where(a, button):focus-visible,
.tg-footer :where(a, button):focus-visible,
/* Shared band buttons on the slate tone: the tinted band's accent fill would sit on a dark ground
 * at 4.0:1, so the primary flips to paper and the label takes the ink colour (the Contact page's
 * long-standing treatment). */
.tg-cta-band--slate .tg-btn-icon--solid {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
}

.tg-cta-band--slate .tg-btn-icon--solid:hover {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--accent-dark);
}

.tg-cta-band--slate :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--paper);
}

/* The band carries the container gutter itself, whatever its tone: the tint runs to the viewport
 * edge (inside a container it pulls out by the same amount — `.tg-container > .tg-cta-band--bleed`
 * below) and the copy comes back onto the container gutter. A band whose main column is not a
 * `.tg-container` — the front page, Contact — needs this most: without it its copy sits one gutter
 * left of every other band's (measured on /contact/ before D-71). */
.tg-cta-band {
	padding-block: var(--wp--preset--spacing--70);
	/* P0-5: the band supplies the background only; its content sits in `.tg-cta-band__grid`,
	 * which carries `tg-container` — so the copy lines up with every other band's content edge
	 * whether the band is a root-level `alignfull` block or still inside a container. */
	padding-inline: 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}

/* On an inner page the band is the last block in <main> and its top hairline landed 17px
 * under the closing paragraph — measured on /applications/ — which read as no gap at all.
 * The slate tone is still excluded, as it was when Contact's band used it. */
.tg-main > .tg-cta-band:not(.tg-cta-band--slate) {
	margin-block-start: var(--wp--preset--spacing--70);
}

/* Section bar (T-634). A child page used to open straight into its H1 with no statement of which
 * section it belongs to; the sibling list sat at the very bottom, after the content. One rule of
 * links under the breadcrumb fixes both without adding another heading to every page. */
.tg-section-bar {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--wp--preset--spacing--20);
	margin-bottom: var(--wp--preset--spacing--60);
	padding-bottom: var(--wp--preset--spacing--40);
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

/* Sentence case, not the uppercase tracked eyebrow: the eyebrow is a Home-only named exception
 * (DESIGN.md anti-patterns), and a section label on every inner page would turn the exception into
 * the rule. Weight and a muted colour are enough to read as metadata. */
.tg-section-bar__label {
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: 0.01em;
}

/* One scrolling line on phones. Wrapped, the four sibling links stacked into four rows and pushed
 * the H1 about 180px down the first screen. */
.tg-section-bar__nav {
	overflow-x: auto;
	scrollbar-width: none;
	margin-inline: calc(-1 * var(--wp--preset--spacing--40));
	padding-inline: var(--wp--preset--spacing--40);
}

.tg-section-bar__nav::-webkit-scrollbar {
	display: none;
}

.tg-section-bar__nav ul {
	display: flex;
	flex-wrap: nowrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
	white-space: nowrap;
}

.tg-main .tg-section-bar__nav li + li {
	margin-top: 0;
}

.tg-section-bar__nav a {
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.9375rem;
	text-decoration: none;
}

.tg-section-bar__nav a:hover,
.tg-section-bar__nav a:focus-visible {
	color: var(--wp--preset--color--accent);
	text-decoration: underline;
	text-underline-offset: 3px;
}

@media (min-width: 900px) {
	.tg-section-bar {
		grid-template-columns: auto minmax(0, 1fr);
		align-items: baseline;
		gap: var(--wp--preset--spacing--60);
	}

	.tg-section-bar__nav {
		overflow-x: visible;
		margin-inline: 0;
		padding-inline: 0;
	}

	.tg-section-bar__nav ul {
		flex-wrap: wrap;
		/* P1-7: left-aligned under the title area, under the same gutter as the H1. It was
		 * `flex-end`, which pushed the four links to the right edge and left the left half of the
		 * bar empty — the client's "靠右对齐，左侧空着". */
		justify-content: flex-start;
		white-space: normal;
	}
}

/* Top-level page: the label is the whole bar, so it needs no second column and no rule below. */
.tg-section-bar--label-only {
	gap: 0;
	/* The label belongs to the H1 below it, so the bar's own 48px bottom margin goes away and the
	 * heading's own top margin does the spacing. */
	margin-bottom: 0;
	padding-bottom: var(--wp--preset--spacing--20);
	border-bottom: 0;
}

@media (min-width: 900px) {
	.tg-section-bar--label-only {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Application grid (T-633): four industry cards on the Applications hub. The card content is the
 * selection field — name, the duty it has to survive, and the product families that serve it — so
 * a buyer can pick a row without opening four pages. Icon, no photograph: the photography we have
 * is product-only, and an industry picture we cannot licence would be a fabricated scene. */
.tg-app-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--wp--preset--spacing--30);
	margin: var(--wp--preset--spacing--60) 0 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-app-grid li + li {
	margin-top: 0;
}

@media (min-width: 640px) {
	.tg-app-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.tg-app-card {
	position: relative;
	/* A one-cell grid: the row stretches the `<li>`, and the link inside stretches to it. Without
	 * this the link's `height: 100%` resolves against an auto-height parent and the card overflows
	 * its own grid row (measured 211px of card inside a 163px row). */
	display: grid;
	margin: 0;
}

/* The whole card is the link; the arrow is decoration and follows the name on hover. */
.tg-app-card__link {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	grid-template-areas:
		"icon name"
		"icon need"
		"icon supply";
	column-gap: var(--wp--preset--spacing--40);
	align-content: start;
	/* No `height: 100%`: the `<li>` is the grid cell and the link stretches to fill it. A percentage
	 * height here references the row the link itself sizes, and the card then overflowed the row. */
	padding: var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--surface);
	border-radius: 8px;
	box-shadow: var(--wp--custom--shadow--card);
	color: inherit;
	text-decoration: none;
}

.tg-app-card__icon {
	grid-area: icon;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--accent-dark);
}

.tg-app-card__icon .tg-icon {
	width: 20px;
	height: 20px;
}

.tg-app-card__name {
	grid-area: name;
	font-size: 1.125rem;
	font-weight: 600;
	line-height: 1.3;
	text-wrap: balance;
}

.tg-app-card__need {
	grid-area: need;
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
	line-height: 1.5;
	/* Two columns at 1280 give the card ~565px; without a measure the sentence ran to ~70ch.
	 * Four across was tried and rejected: at 250px per card the description broke to five lines
	 * and split `USB-C` across lines. */
	max-width: 44ch;
}

/* The matched families are the row's filter value, so they sit on their own line in small caps
 * weight rather than in the sentence above. */
.tg-app-card__supply {
	grid-area: supply;
	margin-top: var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--accent-dark);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.02em;
}

.tg-app-card__link:hover .tg-app-card__name,
.tg-app-card__link:focus-visible .tg-app-card__name {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-app-card__link:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 4px;
}

/* Closing band (T-632): one implementation, on every page that ends with one. `components.css`
 * loads site-wide; this block used to live in the Home stylesheet, which is why inner pages got a
 * plainer band with different padding. */

.tg-cta-band--brand {
	display: block;
	border-top: 0;
	padding-block: clamp(40px, 3.4vw, 56px);
}

.tg-cta-band--brand > * {
	max-width: none;
}

/* P0-5: the band is a root-level `alignfull` block on every page that ends with one, so it is
 * no longer a child of `.tg-container` and needs no negative margin. The `--bleed` class stays
 * as the marker the templates and scripts read. */

/* Owner review 2026-10-15: the band reads in three parts — the head (eyebrow + H2 + lead), the
 * form, then "what happens next" with the direct contacts. That is the mobile reading order, and
 * it is the DOM order too, so no `order` juggling and no mismatch between what a screen reader
 * announces and what a phone shows. On desktop the form sits in the right column beside both. */
.tg-cta-band__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	column-gap: clamp(48px, 6vw, 96px);
	row-gap: 40px;
	align-items: start;
}

/* ---- No-form band: one text group left, the actions right (client review 2026-10-22) --------
 *
 * The band used to be a 7/5 grid with the promise line parked under the buttons: the heading sat
 * hard left, the buttons hard right with the middle empty, the two halves were top-aligned (the
 * right column ended ~160px above the left), and the bottom padding was larger than the top.
 * Now the copy — heading, lead, promise — is one compact stack on the left and the actions are a
 * single group on the right, both vertically centred; the width of the right side is whatever the
 * buttons need, not a fixed share of the grid. Flex + wrap rather than a grid, so the two halves
 * fall into one column by themselves when the container gets narrow. */
.tg-cta-band__grid--split {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--70) var(--wp--preset--spacing--90);
}

.tg-cta-band__text {
	display: flex;
	flex-direction: column;
	flex: 1 1 30rem;
	max-width: 40rem;
	min-width: 0;
}

/* One stack, no inherited margins: the gaps are the flex column's own. The `.tg-cta-band` in front
 * is there to outrank `.tg-cta-band h2`'s own `margin`/`font-size` below. */
.tg-cta-band .tg-cta-band__text > * {
	margin-block: 0;
}

.tg-cta-band .tg-cta-band__text > .tg-cta-band__lead {
	margin-top: var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--ink-muted);
}

.tg-cta-band .tg-cta-band__text > .tg-cta-band__micro {
	margin-top: var(--wp--preset--spacing--50);
}

.tg-cta-band__grid--split > .tg-cta-band__actions {
	flex: 0 0 auto;
}

@media (max-width: 767px) {
	.tg-cta-band__grid--split {
		flex-direction: column;
		align-items: stretch;
		gap: var(--wp--preset--spacing--60);
	}

	.tg-cta-band__grid--split .tg-cta-band__text {
		flex-basis: auto;
		max-width: none;
	}

	/* Full width and equal: the two actions are one stacked group, not two widths. */
	.tg-cta-band__grid--split .tg-cta-band__actions {
		width: 100%;
		flex-direction: column;
		align-items: stretch;
	}

	.tg-cta-band__grid--split .tg-cta-band__actions .tg-btn-icon {
		width: 100%;
		/* `.tg-btn-icon` is content-box with 24px of side padding: `width: 100%` alone made each
		 * button 393px inside a 327px column and pushed the document to 417px at a 390 viewport. */
		box-sizing: border-box;
		justify-content: center;
	}
}

.tg-cta-band__intro,
.tg-cta-band__tail,
.tg-cta-band__aside {
	grid-column: auto;
	min-width: 0;
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
}

.tg-cta-band__tail .tg-band-steps {
	margin-top: 0;
}

.tg-cta-band--brand h2 {
	grid-column: auto;
	max-width: 16ch;
}

/* Owner 2026-10-18: the band's type scale belongs to the band, not to the page it sits on — the
 * same block has to read the same on an inner page, an archive, a hub and a product page. These
 * are the product page's own values (`.tg-pdp h2.wp-block-heading`): the h3 step, 1.25 leading,
 * `spacing-50` under the heading, and no measure cap (the old 16ch cap turned the longer heading
 * into three short lines). The front page's band is a different variant; its `.tg-front` rules
 * below are more specific and keep their own scale. */
/* P0-5 follow-up (2026-10-22): the band is a root-level block since the closing band moved out of
 * `<main>`, so `.tg-main > .tg-cta-band` stopped matching and the heading fell back to the page's
 * `h2` token — 48px at 1440, a page-title size on a closing strip. The selector moved to the band
 * itself; the Home variant keeps its own scale through `.tg-front .tg-cta-band--brand h2`. */
.tg-cta-band h2 {
	max-width: none;
	margin: 0 0 var(--wp--preset--spacing--50);
	font-size: var(--wp--preset--font-size--h3);
	font-weight: 600;
	line-height: 1.25;
	letter-spacing: -0.01em;
}

.tg-cta-band__intro > p {
	max-width: 42ch;
	color: var(--wp--preset--color--ink);
}

/* The white card belongs to the form, not to the column: a band that only offers two buttons
 * (inner pages, the product page) would otherwise paint an empty panel beside the heading. */
.tg-cta-band__aside:has(.tg-form--quick) {
	align-self: start;
	background: var(--wp--preset--color--surface);
	padding: 18px;
	border-radius: 16px;
	box-shadow: var(--wp--custom--shadow--card);
}

.tg-cta-band__aside .wpcf7,
.tg-cta-band__aside .tg-form--quick {
	width: 100%;
}

.tg-cta-band--brand .tg-form--quick {
	gap: 7px;
}

.tg-cta-band--brand .tg-form--quick .tg-field {
	margin: 0;
}

.tg-cta-band--brand .tg-form--quick input,
.tg-cta-band--brand .tg-form--quick select,
.tg-cta-band--brand .tg-form--quick textarea {
	display: block;
	width: 100%;
	min-height: 44px;
	height: 44px;
	box-sizing: border-box;
	border-radius: 8px;
}

.tg-cta-band--brand .tg-form--quick textarea {
	height: auto;
	min-height: 60px;
	resize: vertical;
}

.tg-cta-band--brand .tg-form--quick input:focus,
.tg-cta-band--brand .tg-form--quick select:focus,
.tg-cta-band--brand .tg-form--quick textarea:focus {
	border-color: var(--wp--preset--color--accent);
	box-shadow: 0 0 0 3px rgb(46 104 46 / 16%);
	outline: none;
}

.tg-cta-band--brand .tg-form--quick .tg-field-hint {
	display: block;
	margin-top: 4px;
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.8125rem;
	font-weight: 400;
}

.tg-cta-band--brand .tg-form--quick .tg-field--send {
	position: relative;
	margin-top: 4px;
	/* Owner review 2026-10-15: the submit and the privacy note sat 42px apart. `margin-bottom` was
	 * only half of it — the other 31px was CF7's AJAX spinner, which the script injects after the
	 * submit and which, in flow, wrapped to a second line and made this paragraph 75px tall. The
	 * spinner is taken out of flow below, so only the grid gap and the note's own 4px are left. */
	margin-bottom: 0;
}

/* CF7's "sending…" indicator: keep it (the quick form submits over AJAX), but out of the flow, over
 * the button's trailing end. It is `visibility: hidden` between submits and 24×24 when active. */
.tg-cta-band--brand .tg-form--quick .wpcf7-spinner {
	position: absolute;
	top: 50%;
	right: 10px;
	width: 24px;
	height: 24px;
	margin: -12px 0 0;
}

/* An `<input type=submit>` is inline-level by default, and the baseline gap under it added ~4px to
 * the paragraph on top of the button's own 44px. */
.tg-cta-band--brand .tg-form--quick .wpcf7-submit {
	display: block;
}

.tg-cta-band--brand .tg-form--quick .tg-consent {
	margin-top: 4px;
}

/* The band's “Prefer email? … WhatsApp” line (`.tg-contact-direct`) was removed with its switch on
 * 2026-10-19 (D-076/T-645): Home's contact-information card states the same address and number
 * once. Its rules — the 16px top margin, the 8px gap before the email link, the 14px inline icons
 * and the dot separator — went with it. */
.tg-form--quick .tg-field-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 16px;
}

.tg-cta-band--brand .wpcf7-submit {
	width: 100%;
	height: 44px;
}

.tg-cta-band__intro .wp-block-shortcode,
.tg-front .tg-contact-card {
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
}

.tg-front .tg-contact-card {
	margin-top: 32px;
	padding: 24px;
	background: var(--wp--preset--color--surface);
	border-radius: var(--wp--custom--radius--button);
}

.tg-front .tg-contact-card p,
.tg-front .tg-contact-card a {
	max-width: none;
}

.tg-front .tg-contact-card__person {
	display: flex;
	gap: 14px;
	align-items: center;
	margin: 0;
}

.tg-front .tg-contact-card__photo {
	width: 52px;
	height: 52px;
	flex: 0 0 52px;
	border-radius: 50%;
	object-fit: cover;
	object-position: 50% 20%;
}

.tg-front .tg-contact-card__role {
	display: block;
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.875rem;
	font-weight: 400;
}

.tg-front .tg-contact-card__channels {
	display: grid;
	gap: 10px;
	margin-top: 20px;
}

.tg-front .tg-contact-card__channel {
	display: flex;
	align-items: center;
	gap: 10px;
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	text-decoration: none;
}

.tg-front .tg-contact-card__channel .tg-icon {
	width: 18px;
	height: 18px;
	flex: none;
	color: var(--wp--preset--color--accent);
}

.tg-front .tg-contact-card__channel:hover {
	color: var(--wp--preset--color--accent);
}

.tg-front .tg-contact-card__wa {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: max-content;
	max-width: 100%;
	min-height: 44px;
	padding: 0 16px;
	border: 1px solid var(--wp--preset--color--ink);
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
}

.tg-front .tg-contact-card__wa .tg-icon {
	width: 16px;
	height: 16px;
	color: var(--wp--preset--color--accent);
}

.tg-front .tg-contact-card__wa:hover {
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--ink);
}

/* P2-3: the steps list is a grid row of the band (`grid-template-areas` + 40px row gap), so its
 * own 32px top margin stacked on that gap and left 72px between the contact list and "What
 * happens next" where the prompt asks for 40. */
.tg-cta-band--brand .tg-band-steps {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}

.tg-cta-band--brand .tg-band-steps p {
	max-width: none;
}

@media (min-width: 640px) {
	.tg-form--quick .tg-field-row {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	/* No form on the right (inner pages, the product page): the copy gets the wider column, so the
	 * heading sets on two lines instead of three. Measured at 1280: 408px → 610px. */
	.tg-cta-band__grid:not(:has(.tg-form--quick)) {
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	}

	.tg-cta-band__grid {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		grid-template-areas:
			"intro aside"
			"tail aside";
		/* The aside spans both rows, so the rows split whatever height it adds. With `auto auto`
		 * that slack landed between the copy and "What happens next" — measured 104px on Home at
		 * 1280 (owner review 2026-10-18: "左栏中间空了一大块"). `min-content` pins the copy row to
		 * its own height and the leftover stays in the tail row, so the left column reads in order:
		 * heading, lead, then the list 40px below it (the row gap only). */
		grid-template-rows: min-content 1fr;
	}

	.tg-cta-band__intro {
		grid-area: intro;
	}

	.tg-cta-band__tail {
		grid-area: tail;
		align-self: start;
	}

	.tg-cta-band__aside {
		grid-area: aside;
	}
}

@media (max-width: 1023px) {
	.tg-cta-band__aside:has(.tg-form--quick) {
		padding: 28px;
	}

	.tg-cta-band--brand h2 {
		max-width: none;
	}
}

/* The band now always wraps its content in `.tg-cta-band__grid` (T-632); the prose column keeps
 * the old 40rem measure, the container itself must not be constrained. */
.tg-cta-band > :not(.tg-cta-band__grid) {
	max-width: 40rem;
}

.tg-cta-band h2 {
	margin-top: 0;
	text-wrap: balance;
}

.tg-cta-band--slate {
	background: var(--wp--preset--color--slate);
	color: var(--wp--preset--color--paper);
	border-top: 0;
}

.tg-cta-band--slate :where(h2, p) {
	color: var(--wp--preset--color--paper);
}

.tg-cta-band--slate .wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
}

.tg-cta-band--slate .wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--accent-dark);
}

@media (prefers-reduced-motion: reduce) {
	.tg-main a,
	.tg-footer a,
	.tg-skip,
	.wp-block-button__link {
		transition: none;
	}
}

/* 首页：英雄区全宽，区块自己留白。 */
.tg-main.tg-front {
	padding-block: 0;
}

/* DESIGN §4: every section gets the section padding.
 *
 * P0-4: the four section variations (`styles/section-*.json`) carry the same padding, so a band
 * that only declares `is-style-section-paper` gets it too. What used to break the rhythm was the
 * sibling rule that zeroed the top padding of every other plain band: it knew the old
 * `tg-section--surface` class, not the variations, so the band under a colour change started at
 * 0px while the band above it ended with 128px. It is gone; a band is symmetrical from both
 * sides, and only `.tg-section--tight` and the title band name an exception. */
.tg-section {
	padding-block: var(--wp--custom--section--padding);
}

/* T-313: a section that continues the colour band above it starts closer (see the Home rhythm in DESIGN §6). */
.tg-section--tight {
	padding-top: var(--wp--custom--section--padding-tight);
}

.tg-section--surface {
	background: var(--wp--preset--color--surface);
}

.tg-section h2 {
	margin-top: 0;
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-section__head {
	max-width: 62ch;
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-section__head h2 {
	margin-bottom: 0;
}

.tg-section__head p {
	margin-top: var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink);
	text-wrap: pretty;
}

@media (min-width: 1280px) {
	.tg-section__head p {
		font-size: 1.1875rem;
		line-height: 1.55;
	}
}

/* T-329: on desktop the full-width Home section heads sit on one line — heading left, lead
 * paragraph right, first baselines aligned. Applied with `tg-section__head--split` (Products,
 * How we work, Insights); the OEM/ODM head stays stacked because it lives in a half-width
 * column beside its image. */
@media (min-width: 1024px) {
	.tg-main .tg-section__head--split {
		display: grid;
		grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
		column-gap: var(--wp--preset--spacing--80);
		align-items: baseline;
		max-width: none;
	}

	.tg-section__head--split > .tg-eyebrow {
		grid-column: 1;
		grid-row: 1;
	}

	.tg-section__head--split > h2 {
		grid-column: 1;
		grid-row: 2;
	}

	.tg-section__head--split > p:not(.tg-eyebrow) {
		grid-column: 2;
		grid-row: 2;
		margin-top: 0;
	}

	.tg-section__head--split > :not(.tg-eyebrow):not(h2):not(p) {
		grid-column: 2;
		grid-row: 3;
		margin-top: var(--wp--preset--spacing--40);
	}
}

.tg-hero {
	position: relative;
	display: flex;
	align-items: center;
	min-height: calc(100vh - var(--tg-header-height));
	min-height: calc(100svh - var(--tg-header-height));
	margin: 0;
	overflow: hidden;
	color: var(--wp--preset--color--paper);
	background: var(--wp--preset--color--photo-ground);
}

/* The poster paints first (it is the LCP element) and the video sits on top of it in the same
 * box: `hero-video.js` removes the video below 1024px, under reduced motion or with Save-Data,
 * so the poster must already be there at the right size. */
.tg-hero .wp-block-cover__image-background,
.tg-hero .wp-block-cover__video-background,
.tg-hero__poster,
.tg-hero__video {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.tg-hero .wp-block-cover__background {
	position: absolute;
	inset: 0;
	z-index: 1;
	background-color: var(--wp--preset--color--ink);
	opacity: 0.7;
}

.tg-hero .wp-block-cover__inner-container {
	position: relative;
	z-index: 2;
	box-sizing: border-box;
	width: min(var(--wp--custom--container--default), 100%);
	margin-inline: auto;
	padding: var(--wp--preset--spacing--80) clamp(24px, 5vw, 56px) 96px;
}

/* T-313 (P4.1): from 1600px the container widens to 1440px. Long-form measures keep their own 62ch/66ch caps. */
@media (min-width: 1600px) {
	.tg-container,
	.tg-hero .wp-block-cover__inner-container {
		width: min(var(--wp--custom--container--wide), 100%);
	}
}

/* From 1024px header + hero fill 85% of the first screen so the fact strip and Products peek above the fold.
 * Below 1024px the portrait poster needs the full height to keep the copy clear of the products. */
@media (min-width: 1024px) {
	.tg-hero {
		min-height: max(30rem, calc(85vh - var(--tg-header-height-lg)));
		min-height: max(30rem, calc(85svh - var(--tg-header-height-lg)));
	}
}

/* Below 1024px the copy stays vertically centred (owner 2026-10-25). It used to sit at the bottom
 * so it would clear the products in the upper half of the old portrait *poster*; the backdrop is
 * now the portrait *video*, whose sprout runs up the middle, so the copy is centred to match the
 * desktop composition and the two are the same block at every width. */
@media (max-width: 1023px) {
	.tg-hero .wp-block-cover__inner-container {
		padding-bottom: var(--wp--preset--spacing--60);
	}
}

/* Base rule for any hero H1 (T-343). The Home front page overrides both the size and the width
 * cap in `home-ui-v2.css`, where the statement is a single line; the 16em cap used to live here
 * and was what broke "Tradition Shaped / by Listening." once the type grew. This stays as the
 * fallback for any other template that renders a hero heading. */
.tg-hero h1 {
	margin: 0;
	color: var(--wp--preset--color--paper);
	font-size: clamp(1.75rem, 1.1rem + 2vw, 2.75rem);
	line-height: 1.12;
	letter-spacing: -0.015em;
}

.tg-hero__copy {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.tg-hero__support {
	max-width: 46ch;
	margin: 0;
	font-size: clamp(1.0625rem, 0.95rem + 0.35vw, 1.125rem);
	line-height: 1.5;
	color: var(--wp--preset--color--paper);
}

/* T-321: the hero poster is now a dark bench photograph, so the still hero keeps the same
 * paper-on-ink treatment as the video hero. The old light-poster variant (ink text, no scrim)
 * would leave dark text on a dark image. */
.tg-hero.tg-hero--still .wp-block-cover__background.has-background-dim {
	opacity: 0.7;
}

.tg-hero__note {
	position: absolute;
	left: clamp(24px, 5vw, 56px);
	right: calc(clamp(24px, 5vw, 56px) + 64px);
	bottom: var(--wp--preset--spacing--50);
	z-index: 2;
	max-width: none;
	margin: 0;
	color: var(--wp--preset--color--paper);
	font-size: var(--wp--preset--font-size--small);
}

/* T-334: the hero's primary action carries the brand green, like the header button and the closing
 * band; the outline button next to it stays a secondary. */
.tg-hero .wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--paper);
}

.tg-hero .wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--paper);
}

.tg-hero .wp-block-button.is-style-outline .wp-block-button__link {
	border-color: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--paper);
}

.tg-hero .wp-block-button.is-style-outline .wp-block-button__link:hover {
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
}

.tg-hero :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--paper);
}

/* The hero video's pause/play control was removed (owner 2026-10-25, D-109). Its styles
 * (`.tg-hero__toggle`, `.tg-hero__ico`) went with it; the block still carries `data-label-pause` /
 * `data-label-play` so a future control has translated labels to read. */

.tg-photo-well {
	display: grid;
	place-items: center;
	position: relative;
	overflow: hidden;
	aspect-ratio: 4 / 3;
	background: var(--wp--preset--color--photo-ground);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

/* Category index cards (T-313 card shape; two-up big cards per the owner's reference, T-317): white
 * `surface` cards with a 10px radius and the `shadow--card` token; the product sits in a wide
 * `photo-ground` well on top, name and spec lines below it, the arrow affordance bottom right.
 * The whole card is one link. */
.tg-cat-index {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--40);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-cat-index > li {
	/* T-332: beats `.tg-main li + li` (8px), which used to inset every card but the first. */
	margin-top: 0;
	background: var(--wp--preset--color--surface);
	border-radius: 8px;
	box-shadow: var(--wp--custom--shadow--card);
	overflow: hidden;
}

.tg-cat-index__item {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	grid-template-areas:
		"thumb"
		"text"
		"go";
	gap: var(--wp--preset--spacing--40);
	padding: 0 0 var(--wp--preset--spacing--50);
	color: inherit;
	text-decoration: none;
}

/* Wide well on top; the normalized WebP files are transparent, so the product sits on the well.
 * T-330: the well is 16:10 from 640px so the cards read as an index rather than a gallery; the
 * product keeps `contain` (a shorter box never crops it). */
.tg-cat-index__thumb {
	grid-area: thumb;
	display: grid;
	place-items: center;
	aspect-ratio: 4 / 3;
	background: var(--wp--preset--color--photo-ground);
	transition: background-color var(--wp--custom--motion--fast);
}

.tg-cat-index__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.tg-cat-index__text {
	grid-area: text;
	min-width: 0;
	padding-inline: var(--wp--preset--spacing--50);
}

.tg-cat-index__name {
	display: block;
	color: var(--wp--preset--color--ink);
	font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.625rem);
	font-weight: 600;
	line-height: 1.25;
	overflow-wrap: break-word;
}

.tg-cat-index__spec {
	display: grid;
	gap: 2px;
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.9375rem;
	line-height: 1.45;
	overflow-wrap: break-word;
}

/* The first spec line is the number a buyer scans for; the second stays secondary. */
.tg-cat-index__spec span:first-child {
	color: var(--wp--preset--color--ink);
	font-weight: 600;
}

/* Arrow affordance, bottom right of the card (owner reference). Not a control of its own: the whole
 * card is the link, so it carries no role, no tab stop and no accessible name. The glyph is
 * `accent-dark` so it reads as an entry point on the tinted disc (T-330). */
.tg-cat-index__go {
	grid-area: go;
	display: grid;
	place-items: center;
	justify-self: end;
	align-self: end;
	margin-right: var(--wp--preset--spacing--50);
	width: 34px;
	height: 34px;
	border-radius: 50%;
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--accent-dark);
	transition: background-color var(--wp--custom--motion--fast);
}

.tg-cat-index__go svg {
	display: block;
	width: 18px;
	height: 18px;
}

.tg-cat-index__item:hover .tg-cat-index__thumb,
.tg-cat-index__item:focus-visible .tg-cat-index__thumb {
	background: var(--wp--preset--color--accent-tint);
}

.tg-cat-index__item:hover .tg-cat-index__go,
.tg-cat-index__item:focus-visible .tg-cat-index__go {
	background: var(--wp--preset--color--accent-tint-strong);
}

.tg-cat-index__item:hover .tg-cat-index__name {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-cat-index__item:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: -2px;
}

@media (min-width: 640px) {
	.tg-cat-index__thumb {
		aspect-ratio: 16 / 10;
	}
}

/* T-330: four across on desktop — one compact index row instead of a two-row gallery. */
@media (min-width: 1024px) {
	.tg-cat-index {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--50);
	}

	.tg-cat-index__item {
		gap: var(--wp--preset--spacing--30);
		padding: 0 0 var(--wp--preset--spacing--40);
	}

	.tg-cat-index__text {
		padding-inline: var(--wp--preset--spacing--40);
	}

	.tg-cat-index__go {
		margin-right: var(--wp--preset--spacing--40);
	}
}

@media (prefers-reduced-motion: reduce) {
	.tg-cat-index__go {
		transition: none;
	}
}

/* P1-9: the application pages' "What we supply" is three categories, not the four of the Home
 * index — same card, its own column count. (The rules live after the Home block so the 1024px
 * step wins on source order.) */
.tg-supply-cards {
	grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
	.tg-supply-cards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.tg-supply-cards {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	/* Two categories (Industrial & security) get two cards, not two cards and a hole. */
	.tg-supply-cards:has(> li:nth-child(2):last-child) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

.tg-gallery-thumbs img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

.tg-photo-well--wide {
	aspect-ratio: 16 / 9;
}

.tg-photo-well--portrait {
	aspect-ratio: 4 / 5;
}

.tg-main :is(.tg-home-insights, .tg-insight-list) li + li {
	margin-top: 0;
}

.tg-factory {
	margin: 0;
}

.tg-insight-row {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	padding-block: 20px;
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

:is(.tg-home-insights, .tg-insight-list) .wp-block-post-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-3);
	line-height: 1.3;
}

:is(.tg-home-insights, .tg-insight-list) .wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}

:is(.tg-home-insights, .tg-insight-list) .wp-block-post-title a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

:is(.tg-home-insights, .tg-insight-list) .wp-block-post-date,
:is(.tg-home-insights, .tg-insight-list) .wp-block-post-excerpt {
	color: var(--wp--preset--color--ink-muted);
}

:is(.tg-home-insights, .tg-insight-list) .wp-block-post-date {
	font-size: var(--wp--preset--font-size--small);
}

/* Client Stories archive and search results: same ruled rows as Insights. */
.tg-main .wp-block-search:has(+ .wp-block-query) {
	margin-bottom: var(--wp--preset--spacing--70);
}

.tg-story-list,
.tg-search-list {
	margin: 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-main :is(.tg-story-list, .tg-search-list) {
	padding-left: 0;
}

.tg-main :is(.tg-story-list, .tg-search-list) > li {
	display: grid;
	gap: var(--wp--preset--spacing--10);
	max-width: none;
	margin: 0;
	padding-block: 20px;
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

:is(.tg-story-list, .tg-search-list) .wp-block-post-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-3);
	line-height: 1.3;
}

:is(.tg-story-list, .tg-search-list) .wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}

:is(.tg-story-list, .tg-search-list) .wp-block-post-title a:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

:is(.tg-story-list, .tg-search-list) .wp-block-post-excerpt {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
}

:is(.tg-story-list, .tg-search-list) .wp-block-post-excerpt__excerpt {
	margin: 0;
}

/* T-317: the category index stays two-up from 640px; the two-column rule lives with the card block. */
@media (min-width: 900px) {
	.tg-insight-row {
		grid-template-columns: 1fr auto;
		column-gap: var(--wp--preset--spacing--50);
		align-items: baseline;
	}

	.tg-insight-row .wp-block-post-excerpt {
		grid-column: 1 / -1;
	}
}

.tg-main .wp-block-term-description {
	margin-bottom: var(--wp--preset--spacing--70);
}

.tg-product-grid {
	display: grid;
	gap: var(--wp--preset--spacing--60);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-product-grid {
	padding-left: 0;
}

.tg-main .tg-product-grid > li + li {
	margin-top: 0;
}

/* Product card (T-631): one implementation, rendered by `tg_product_card_html()` and served to the
 * Home carousel, the Products and category archives, the Related row and the Other-versions row.
 * Optional parts (category, certifications, model, CTA hint) are simply absent when a placement
 * does not ask for them, so nothing below is scoped to a page.
 * The whole card is one link — the name's `::after` covers it, the category link floats above it. */
.tg-product-tile {
	/* T-344: same card language as the category index.
	 *
	 * P1-1: one anatomy for every card in a grid — a flex column that fills its cell, with the
	 * last line (the "View specs & get quote" affordance) pushed to the bottom edge. The pin used
	 * to live in Home's stylesheet only, so on the archives a card with fewer rows would have left
	 * its CTA floating mid-card; the shared rule now does it for all four placements.
	 *
	 * `border-box` is what makes `height: 100%` mean the card's *box*, not its content: as
	 * `content-box` the 32px of vertical padding was added on top of the cell height, so inside the
	 * related carousel's slide (a stretched flex item with a definite height) the card was 32px
	 * taller than its cell and the carousel viewport's `overflow-y: hidden` cut the bottom of the
	 * CTA off. `box-sizing: border-box` is declared here, not inherited, because the card is a
	 * bare `<article>` rendered by PHP. */
	box-sizing: border-box;
	position: relative;
	display: flex;
	flex-direction: column;
	height: 100%;
	padding: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--surface);
	border-radius: 8px;
	box-shadow: var(--wp--custom--shadow--card);
}

.tg-home-products__head {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
}

.tg-home-products__all {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--10);
	color: var(--wp--preset--color--accent);
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
}

.tg-home-products__all .tg-icon {
	width: 14px;
	height: 14px;
}

.tg-home-products__all:hover,
.tg-home-products__all:focus-visible {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-product-tile__media {
	display: block;
	aspect-ratio: 4 / 3;
	background: var(--wp--preset--color--photo-ground);
	transition: background-color var(--wp--custom--motion--fast);
}

.tg-product-tile__img,
.tg-product-tile__media .tg-photo-well {
	display: block;
	width: 100%;
	height: 100%;
}

.tg-product-tile__img {
	object-fit: contain;
}

.tg-product-tile__cat {
	margin-top: var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--accent);
	font-size: var(--wp--preset--font-size--small);
}

/* The category link stays clickable above the card-wide title link and keeps a 44px touch target
 * (the only way into a category from the card). The target is grown by a pseudo-element, NOT by
 * `min-height` on the link: an inline-block with `min-height: 44px` makes its own line box 44px
 * tall, which left ~80px of air between the category and the product name (owner review
 * 2026-10-18). The `::after` overlays the same 44px without touching layout. */
.tg-product-tile__cat a {
	position: relative;
	z-index: 1;
	color: inherit;
	text-decoration: none;
}

.tg-product-tile__cat a::after {
	content: "";
	position: absolute;
	inset: -13px -8px;
}

.tg-product-tile__cat a:hover,
.tg-product-tile__cat a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-product-tile__name {
	display: -webkit-box;
	overflow: hidden;
	margin: var(--wp--preset--spacing--10) 0 0;
	font-size: 1rem;
	font-weight: 600;
	line-height: 1.3;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.tg-product-tile__link {
	color: inherit;
	text-decoration: none;
}

.tg-product-tile__link::after {
	content: "";
	position: absolute;
	inset: 0;
}

.tg-product-tile__link:hover {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-product-tile__spec {
	margin: var(--wp--preset--spacing--20) 0 0;
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 500;
}

.tg-product-tile__model {
	margin: var(--wp--preset--spacing--10) 0 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.9375rem;
	letter-spacing: 0.02em;
}

/* T-332: an always-visible affordance on the product card. The whole card is already one link
 * (the title's ::after covers it), so this is decoration — no second tab stop, clicks pass through.
 *
 * P1-1: it is the card's footer, so it sits on the bottom edge whatever the rows above it do —
 * the last link of every card in a row then shares one baseline. */
.tg-product-tile__cta {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	margin-top: auto;
	padding-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--accent);
	font-size: 0.9375rem;
	font-weight: 600;
	pointer-events: none;
}

.tg-product-tile__cta .tg-icon {
	width: 16px;
	height: 16px;
}

/* Section link buttons that navigate to another page carry one trailing arrow, the same 18px step
 * as `.tg-btn-icon` (button rule: off-page → arrow, in-page → none). */
.wp-block-button__link .tg-icon {
	display: block;
	width: 18px;
	height: 18px;
	color: currentColor;
}

.wp-block-button__link:has(.tg-icon) {
	gap: var(--wp--preset--spacing--30);
}

.wp-block-button.is-style-outline .wp-block-button__link .tg-icon {
	color: var(--wp--preset--color--accent);
}

.wp-block-button.is-style-outline .wp-block-button__link:hover .tg-icon,
.wp-block-button.is-style-outline .wp-block-button__link:focus-visible .tg-icon {
	color: var(--wp--preset--color--paper);
}

/* Per-SKU certifications (buyers filter on these first) — printed only when the field is filled;
 * TODO.md T-607 has the client confirm each SKU's marks. */
.tg-product-tile__certs {
	margin: var(--wp--preset--spacing--20) 0 0;
	color: var(--wp--preset--color--ink);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.02em;
}

.tg-product-tile:hover .tg-product-tile__cta,
.tg-product-tile:focus-within .tg-product-tile__cta {
	color: var(--wp--preset--color--accent-dark);
}

.tg-product-tile:hover .tg-product-tile__media,
.tg-product-tile:focus-within .tg-product-tile__media {
	background: var(--wp--preset--color--photo-ground-hover);
}

.tg-product-tile:has(.tg-product-tile__link:focus-visible) {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
	.tg-product-tile__media {
		transition: none;
	}
}

@media (min-width: 900px) {
	.tg-product-tile__name {
		font-size: 1.125rem;
	}

	.tg-product-tile__spec {
		font-size: 1rem;
	}
}

.tg-category-index {
	margin-bottom: var(--wp--preset--spacing--80);
}

span.tg-ruled__row {
	display: grid;
}

.tg-pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
	margin-top: var(--wp--preset--spacing--70);
}

.tg-pagination .wp-block-query-pagination-numbers {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
}

.tg-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	min-width: 44px;
	min-height: 44px;
	padding: 0 var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	border-bottom: 2px solid transparent;
}

.tg-pagination a.page-numbers:hover {
	border-bottom-color: var(--wp--preset--color--ink);
}

.tg-pagination .page-numbers.current {
	border-bottom-color: var(--wp--preset--color--accent);
}

@media (min-width: 640px) {
	.tg-product-grid {
		grid-template-columns: 1fr 1fr;
	}
}

@media (min-width: 900px) {
	.tg-product-grid {
		grid-template-columns: 1fr 1fr 1fr;
	}
}

.tg-story {
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-story__portrait figure {
	margin: 0;
}

.tg-story figcaption strong {
	display: block;
	color: var(--wp--preset--color--ink);
	font-weight: 600;
}

.tg-longform .tg-story figcaption,
.tg-longform .tg-factory figcaption {
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.5;
}

.tg-factory {
	margin-top: var(--wp--preset--spacing--80);
}

.tg-factory img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

/* Our Story: keep the factory caption off the CTA band rule. */
.tg-longform .tg-factory {
	margin-bottom: var(--wp--preset--spacing--80);
}

@media (min-width: 1280px) {
	.tg-story__portrait {
		position: sticky;
		top: var(--wp--preset--spacing--50);
		align-self: start;
	}
}

.tg-product-page {
	padding-top: var(--wp--preset--spacing--70);
}

/* 产品图库（T-625）：主图 + 缩略图。图是透明 WebP 或 4:3 摄影图，都靠 photo-ground 图槽托住。 */
.tg-gallery {
	display: block;
}

.tg-gallery__stage {
	display: block;
	aspect-ratio: 4 / 3;
	background: var(--wp--preset--color--photo-ground);
}

.tg-gallery--empty .tg-gallery__stage {
	/* 没有图的产品也要占住位置，详情页两栏才不会塌。 */
	min-height: 1px;
}

.tg-gallery__img,
.tg-gallery__thumb-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.tg-gallery__thumbs {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	align-items: start;
	gap: var(--wp--preset--spacing--10);
	margin: var(--wp--preset--spacing--20) 0 0;
	padding: 0;
	list-style: none;
}

/* P0-2: the row is a grid of equal squares. `.tg-main li + li` (8px) still pushed every
 * thumbnail but the first 8px down inside its own cell, so the selected one sat higher than
 * its neighbours and the row grew by exactly that margin. */
.tg-main .tg-gallery__thumbs li + li {
	margin-top: 0;
}

.tg-gallery__thumb {
	display: block;
	aspect-ratio: 4 / 3;
	background: var(--wp--preset--color--photo-ground);
	border: 1px solid var(--wp--preset--color--rule);
	outline: 2px solid transparent;
	outline-offset: 2px;
	transform: scale(1);
	transform-origin: center;
	transition: transform var(--wp--custom--motion--fast), border-color var(--wp--custom--motion--fast);
}

.tg-gallery__thumb:hover {
	background: var(--wp--preset--color--photo-ground-hover);
}

/* The selected state is a slight scale, not an outline.
 *
 * The outline was drawn outside the box and the strip is a fixed-height grid, so the top and
 * bottom of the ring were clipped and the mark read as two stray vertical lines. A transform
 * stays inside the box: `1fr` tracks keep the row from reflowing, so nothing jumps when the mark
 * moves between shots. The colour change on the border still carries the state for anyone who
 * cannot see the 6% difference. */
.tg-gallery__thumb.is-current {
	border-color: var(--wp--preset--color--accent);
	outline: none;
	transform: scale(1.06);
}

.tg-gallery__thumb:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

.tg-story-meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--10) var(--wp--preset--spacing--50);
	margin: 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-product {
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-product__summary > .wp-block-post-title,
.tg-product__summary h1 {
	max-width: 16em;
	margin-top: 0;
}

.tg-product__summary .tg-product-meta--tg_model {
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
}

.tg-product__summary .wp-block-post-excerpt {
	max-width: 42ch;
}

.tg-product__summary .wp-block-buttons {
	margin-top: var(--wp--preset--spacing--50);
}

.tg-related {
	margin-top: var(--wp--preset--spacing--80);
}

.tg-related > :where(h2, .wp-block-heading):first-child {
	margin-top: 0;
}

.tg-related:not(:has(.wp-block-post)) {
	display: none;
}

.tg-filters {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	margin: 0 0 var(--wp--preset--spacing--70);
}

.tg-filters a {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	color: var(--wp--preset--color--ink-muted);
	font-weight: 600;
	text-decoration: none;
}

.tg-filters a[aria-current="page"],
.tg-filters a:hover {
	color: var(--wp--preset--color--ink);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-article__meta {
	gap: var(--wp--preset--spacing--40);
	margin-bottom: var(--wp--preset--spacing--70);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-product-page > h2:has(+ .tg-related) {
	display: none;
}

@media (max-width: 899px) {
	.tg-product {
		flex-direction: column;
	}

	.tg-product__summary {
		order: -1;
	}
}

.tg-404 {
	text-align: center;
}

.tg-404 :where(h1, p) {
	margin-inline: auto;
}

.tg-404 a {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	margin-inline: var(--wp--preset--spacing--30);
}

.wp-block-search__input,
.wp-block-search__button {
	min-height: 48px;
}

.wp-block-search__button {
	padding-inline: var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--accent);
	border: 1px solid transparent;
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--surface);
	font-weight: 600;
}

.wp-block-search__button:hover {
	background: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--surface);
}

/* 联系页：文档顺序堆叠；宽屏表单在右列。 */
.tg-main.tg-contact-page {
	padding-block: 0;
}

.tg-contact-page > .tg-container {
	padding-block: var(--wp--custom--section--padding) var(--wp--preset--spacing--70);
}

/* Until D-71 this page asked the band for the slate tone; its own padding rule went with the
 * switch, because the band now supplies the gutter at every tone (`.tg-cta-band` above). */

.tg-contact {
	display: grid;
	gap: var(--wp--preset--spacing--70);
}

.tg-contact > .wp-block-group {
	margin-block: 0;
}

.tg-contact h1,
.tg-contact h2 {
	margin-top: 0;
}

.tg-contact__form :where(p) {
	max-width: none;
}
.tg-contact__form {
	scroll-margin-top: var(--wp--preset--spacing--60);
}

.tg-inquiry-context {
	margin: 0 0 var(--wp--preset--spacing--50);
	font-weight: 600;
}

.tg-field {
	margin: 0 0 20px;
}

/* CF7 autop adds <br /> after each label; the label's 6px margin is the gap. */
.tg-field br {
	display: none;
}

.tg-field label,
.wpcf7-form label {
	display: block;
	margin-bottom: 6px;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.tg-req {
	font-weight: 400;
	color: var(--wp--preset--color--ink-muted);
}

.tg-field-hint {
	display: block;
	margin: 0 0 6px;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 400;
}

.tg-form :is(input[type="text"], input[type="email"], input[type="tel"], input[type="url"], input[type="number"], input[type="date"], select, textarea, input[type="file"]),
.wpcf7-form :is(input[type="text"], input[type="email"], input[type="tel"], input[type="url"], input[type="number"], input[type="date"], select, textarea, input[type="file"]) {
	box-sizing: border-box;
	width: 100%;
	/* T-647: 44px, the client's own field height in the Contact mockup (measured 44.6). It was
	 * min-height 48 + 10px padding = 52, which stood 8px taller than the mockup on every field and
	 * made the band's card 15% taller than the drawing. 44 is also the touch-target floor. */
	min-height: 44px;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 3px;
	color: inherit;
	font: inherit;
}
/* The file field measured 70px against every other field's 48px: the 48px button sat inside
 * the input's own 10px padding. The button is the field's content, so the input drops its
 * block padding and the button fills the box. */
.tg-form input[type="file"],
.wpcf7-form input[type="file"] {
	padding-block: 0;
}

/* 42px + the input's own 1px border keeps the field on the 44px line the other fields use. */
.tg-form input[type="file"]::file-selector-button,
.wpcf7-form input[type="file"]::file-selector-button {
	min-height: 42px;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	background: transparent;
	border: 1px solid var(--wp--preset--color--ink);
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
	line-height: 1.25;
	cursor: pointer;
}

.tg-form input[type="file"]::file-selector-button:hover,
.wpcf7-form input[type="file"]::file-selector-button:hover {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.tg-form textarea,
.wpcf7-form textarea {
	min-height: 160px;
}

.wpcf7-form input[type="submit"],
.tg-form input[type="submit"] {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: auto;
	min-height: 48px;
	margin: 0;
	padding: 12px var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--accent);
	border: 1px solid transparent;
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--surface);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
	line-height: 1.25;
	cursor: pointer;
	transition: background-color 150ms, color 150ms;
}

.wpcf7-form input[type="submit"]:hover,
.tg-form input[type="submit"]:hover {
	background: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--surface);
}

.wpcf7-not-valid {
	border-color: var(--wp--preset--color--error);
}

.wpcf7-not-valid-tip {
	display: block;
	margin-top: 4px;
	color: var(--wp--preset--color--error);
	font-size: var(--wp--preset--font-size--small);
}

.wpcf7 form.sent .tg-form {
	display: none;
}

.wpcf7 form.sent .wpcf7-response-output {
	text-align: center;
}

.wpcf7-response-output {
	margin: var(--wp--preset--spacing--50) 0 0;
	padding: var(--wp--preset--spacing--40);
	border: 1px solid var(--wp--preset--color--rule);
}

/* FAQ disclosure (D-21). Two things were wrong on every page that carries it.
 * (1) Padding had two owners: `.tg-main details` adds 16px and the summary added 20px,
 * so a closed item measured 100px at 1280 and 111px at 375 around a single question.
 * The summary owns the row padding now.
 * (2) The native marker was hidden and nothing replaced it, so the rows read as plain
 * text. The chevron below is drawn in CSS — no icon file, no JS (D-21).
 *
 * `details.tg-faq__item` is a selector of its own, not just a descendant of `.tg-faq`:
 * the FAQ items on the Applications children sit inside a `tg-split__body` with no
 * `.tg-faq` wrapper, and the native triangle was still painting there (measured
 * 2026-10-18). One component, wherever it is placed. */
.tg-main .tg-faq details,
.tg-main details.tg-faq__item {
	padding-block: 0;
}

.tg-faq {
	margin-top: var(--wp--preset--spacing--70);
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-faq__item,
.tg-faq .wp-block-details,
details.tg-faq__item {
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

/* `position: relative` + an absolutely positioned chevron rather than `display: flex` on the
 * summary: WebKit exposes a flex summary as a plain group instead of a disclosure triangle
 * (VoiceOver stops announcing expanded/collapsed). The 2.5em of right padding keeps a long
 * question from running under the glyph. */
.tg-faq__q,
.tg-faq summary,
details.tg-faq__item > summary {
	position: relative;
	padding: var(--wp--preset--spacing--40) 2.5em var(--wp--preset--spacing--40) 0;
	font-family: var(--wp--preset--font-family--grotesk);
	/* P1-9: the question is the `lead` step (20px at 1440, 18px on a phone) rather than `h4`
	 * (21.8px, which read as a section heading rather than a question). */
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 600;
	line-height: 1.3;
	list-style: none;
	cursor: pointer;
}

.tg-faq__q::after,
.tg-faq summary::after,
details.tg-faq__item > summary::after {
	content: "";
	position: absolute;
	top: calc(var(--wp--preset--spacing--40) + 0.55em);
	right: 0.25em;
	width: 0.5em;
	height: 0.5em;
	border-right: 2px solid var(--wp--preset--color--ink-muted);
	border-bottom: 2px solid var(--wp--preset--color--ink-muted);
	transform: rotate(45deg);
	transition: transform 150ms, border-color 150ms;
}

.tg-faq details[open] > summary::after,
.tg-faq .tg-faq__item[open] > .tg-faq__q::after,
details.tg-faq__item[open] > summary::after {
	transform: rotate(225deg);
}

.tg-faq summary:hover,
details.tg-faq__item > summary:hover {
	color: var(--wp--preset--color--accent-dark);
}

.tg-faq summary:hover::after,
details.tg-faq__item > summary:hover::after {
	border-color: var(--wp--preset--color--accent-dark);
}

.tg-faq__q::-webkit-details-marker,
.tg-faq summary::-webkit-details-marker,
details.tg-faq__item > summary::-webkit-details-marker {
	display: none;
}

.tg-faq__a,
.tg-faq .wp-block-details p,
details.tg-faq__item > p {
	max-width: 62ch;
	padding: 0 0 var(--wp--preset--spacing--50);
	color: var(--wp--preset--color--ink-muted);
}

@media (min-width: 900px) {
	.tg-contact {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		column-gap: var(--wp--preset--spacing--80);
		align-items: start;
	}

	.tg-contact__intro,
	.tg-contact__faq {
		grid-column: 1 / -1;
	}

	.tg-contact__info {
		grid-column: 1;
		grid-row: 2;
	}

	.tg-contact__follow {
		grid-column: 1;
		grid-row: 3;
	}

	.tg-contact__response {
		grid-column: 1;
		grid-row: 4;
	}

	.tg-contact__help {
		grid-column: 1;
		grid-row: 5;
	}

	.tg-contact__form {
		grid-column: 2;
		grid-row: 2 / span 4;
	}
}

@media (max-width: 899px) {
	.tg-contact__intro {
		grid-row: 1;
	}

	.tg-contact__form {
		grid-row: 2;
	}

	.tg-contact__info {
		grid-row: 3;
	}

	.tg-contact__help {
		grid-row: 4;
	}

	.tg-contact__follow {
		grid-row: 5;
	}

	.tg-contact__response {
		grid-row: 6;
	}

	.tg-contact__faq {
		grid-row: 7;
	}
}

/* Contact: the four sidebar blocks stacked 2 109px against a 1 263px form, so the right
 * column showed an ~830px hole under the submit button before the full-width FAQ started.
 * "What Can We Help With?" is a sidebar list, not a page's main list: 16px of row padding
 * instead of 24px and one size down takes a row from 135px to 86.2px, the block to 609px and
 * the whole stack to 1 456px. The four block headings were `h2` and landed at the H1's step
 * (48px at 1280); they are sub-blocks of one page, so they take the `h3` step. */
.tg-contact__info h2,
.tg-contact__follow h2,
.tg-contact__response h2,
.tg-contact__help h2 {
	font-size: var(--wp--preset--font-size--h-3);
}

.tg-contact__help .tg-ruled__row {
	padding-block: var(--wp--preset--spacing--40);
}

.tg-contact__help .tg-ruled__title {
	font-size: var(--wp--preset--font-size--h-4);
}

@media (prefers-reduced-motion: reduce) {
	.wpcf7-form input[type="submit"],
	.tg-form input[type="submit"] {
		transition: none;
	}

	.tg-faq summary::after {
		transition: none;
	}
}

/* ---------------------------------------------------------------
 * Home modules, Oct 8 pass: section intros, step images, OEM figure,
 * founder teaser, Insights link. Product detail rows + datasheet table.
 * ------------------------------------------------------------- */

.tg-section__head--intro {
	margin-bottom: var(--wp--preset--spacing--70);
}

/* The Home Products heading is one step larger than the other section headings and followed by an
 * `ink-muted` intro. T-332: the 56×4px accent marker under it was removed (owner: it was the only
 * place in the site using it, and the heading reads cleaner without). */
.tg-products .tg-section__head--intro h2 {
	font-size: clamp(2rem, 1.5rem + 1.6vw, 2.75rem);
	letter-spacing: -0.02em;
}

.tg-products .tg-section__head--intro p {
	font-size: 1.0625rem;
	line-height: 1.6;
}

@media (min-width: 1280px) {
	.tg-products .tg-section__head--intro p {
		font-size: 1.1875rem;
		line-height: 1.55;
	}
}

/* Product page: description column, detail rows (native columns + image), datasheet table. */
.tg-product-page .wp-block-post-content > :where(h2) {
	margin-top: var(--wp--preset--spacing--80);
}

.tg-product-page .wp-block-post-content > h2:first-child {
	margin-top: 0;
}

.tg-sample-note {
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border-left: 2px solid var(--wp--preset--color--rule);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-detail-rows {
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-main .tg-detail-rows .tg-detail-row {
	gap: var(--wp--preset--spacing--50);
	margin: 0;
	padding-block: var(--wp--preset--spacing--60);
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

.tg-detail-row .wp-block-image {
	margin: 0;
	background: var(--wp--preset--color--photo-ground);
}

.tg-detail-row .wp-block-image img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

.tg-detail-row__text h3 {
	margin: 0;
}

.tg-detail-row__text p {
	margin: var(--wp--preset--spacing--30) 0 0;
	color: var(--wp--preset--color--ink-muted);
}

@media (min-width: 900px) {
	.tg-main .tg-detail-rows .tg-detail-row {
		flex-wrap: nowrap;
		align-items: center;
		gap: var(--wp--preset--spacing--80);
	}

	.tg-detail-row > .tg-detail-row__media {
		flex: 0 0 58%;
	}

	.tg-detail-row > .tg-detail-row__text {
		flex: 1 1 auto;
	}

	.tg-detail-row:nth-child(even) > .tg-detail-row__media {
		order: 2;
	}
}

.tg-main .wp-block-table {
	margin: var(--wp--preset--spacing--50) 0 0;
	overflow-x: auto;
}

.tg-main .wp-block-table table {
	width: 100%;
	max-width: 52rem;
	border-collapse: collapse;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-main .wp-block-table :where(th, td) {
	padding: 12px 16px 12px 0;
	border: 0;
	border-bottom: 1px solid var(--wp--preset--color--rule);
	text-align: left;
	vertical-align: top;
}

.tg-main .wp-block-table td:first-child {
	width: 40%;
	color: var(--wp--preset--color--ink-muted);
}

.tg-main .wp-block-table figcaption {
	max-width: 52rem;
}


.tg-home-insights.wp-block-query .tg-ruled,
.tg-home-insights ul.tg-ruled {
	border-top: 1px solid var(--wp--preset--color--rule);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-home-insights .tg-ruled {
	padding-left: 0;
}

.tg-main .tg-home-insights .tg-ruled > li {
	max-width: none;
	margin: 0;
}

/* ---------------------------------------------------------------
 * Home modules polish (T-301): numbered steps, OEM intro + service
 * rows, production split with a framed photo slot, founder teaser,
 * Insights rows with thumbnails, closing band and footer rhythm.
 * ------------------------------------------------------------- */

/* Shared 3:2 photo-ground well (product detail pattern). */
.tg-media-well {
	position: relative;
	display: block;
	overflow: hidden;
	margin: 0;
	aspect-ratio: 3 / 2;
	background: var(--wp--preset--color--photo-ground);
}

.tg-media-well img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Images inside home modules: flat photo-ground well, no radius. */
.tg-front .tg-oem-intro__media img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

/* How we work: a real sequence, so numbered 01–04 on one connecting rule. */
.tg-steps {
	display: grid;
	gap: var(--wp--preset--spacing--70) var(--wp--preset--spacing--50);
	counter-reset: tg-step;
}

.tg-step {
	position: relative;
	display: flex;
	flex-direction: column;
	counter-increment: tg-step;
}

.tg-step::before {
	content: counter(tg-step, decimal-leading-zero);
	position: relative;
	z-index: 1;
	align-self: flex-start;
	margin-bottom: var(--wp--preset--spacing--30);
	/* The rule is drawn by the ::after at mid-counter height, so the number's own background has to
	 * match the band it sits on (the OEM/ODM section is `paper`) — a literal white block here reads
	 * as a bug. The padding leaves a gap in the rule before the duration. */
	padding-right: var(--wp--preset--spacing--40);
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--accent);
	font-size: var(--wp--preset--font-size--h-3);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: 1;
}

/* Per-step duration (buyers schedule from these). It sits under the rule, not beside the counter:
 * "Reply within 1 business day" is ~200px and a 4-up cell at 1280px is 274px, so a side-by-side
 * placement collided with the next step's number (owner report, 2026-10-12). */
.tg-main .tg-step__time {
	margin: 0 0 var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1.5;
	overflow-wrap: break-word;
}

/* A `[CONTENT NEEDED: …]` duration is a gap, not copy. It reads as an editorial marker rather than
 * a broken value until the client supplies the window (D-089). */
.tg-placeholder {
	color: var(--wp--preset--color--ink-muted);
	font-style: italic;
	font-weight: 400;
}

.tg-step::after {
	content: "";
	position: absolute;
	top: calc(var(--wp--preset--font-size--h-3) / 2);
	right: 0;
	left: 0;
	border-top: 1px solid var(--wp--preset--color--ink);
}

.tg-step__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-3);
	line-height: 1.3;
}

.tg-main .tg-step__text {
	margin: var(--wp--preset--spacing--30) 0 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.9375rem;
	line-height: 1.55;
}

@media (min-width: 640px) {
	.tg-steps {
		grid-template-columns: 1fr 1fr;
	}
}

@media (min-width: 1200px) {
	.tg-steps {
		grid-template-columns: repeat(4, 1fr);
	}

	/* The rule runs on into the gap so the four steps read as one line. */
	.tg-step:not(:last-child)::after {
		right: calc(var(--wp--preset--spacing--40) - var(--wp--preset--spacing--50));
	}
}

/* OEM/ODM: intro beside one supporting image, then the five ruled service rows.
 * T-313: this section continues the How-we-work surface band, separated by a container-width hairline. */
.tg-oem-intro {
	display: grid;
	gap: var(--wp--preset--spacing--60);
	margin-bottom: var(--wp--preset--spacing--80);
	padding-top: var(--wp--preset--spacing--60);
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-oem-intro .tg-section__head {
	margin-bottom: 0;
}

/* T-313: section-level entries ("All products", "Read our story"…) are small outline buttons, not text links. */
.tg-section-link {
	margin-top: var(--wp--preset--spacing--60);
}

.tg-btn-sm .wp-block-button__link {
	min-height: 44px;
	padding: 0 20px;
	border-radius: var(--wp--custom--radius--button);
	font-size: 0.9375rem;
	font-weight: 600;
}

/* Home latest products: title row with the section button on the right, then the card grid.
 * The DOM order stays title → query → link, so reading and tab order match the small-screen layout. */
/* T-330: the category index and the featured row are two modules — the row opens with extra air,
 * and its section link grows to the same 52px as the closing band's buttons. */
.tg-home-products {
	display: grid;
	gap: var(--wp--preset--spacing--60);
	align-items: center;
	margin-top: var(--wp--preset--spacing--90);
	grid-template-areas:
		"title"
		"grid"
		"link";
	margin-top: var(--wp--preset--spacing--80);
}

.tg-home-products__title {
	grid-area: title;
	margin: 0;
	font-size: 1.5rem;
	font-weight: 600;
	line-height: 1.2;
}

.tg-home-products .wp-block-query {
	grid-area: grid;
}

.tg-home-products .tg-section-link {
	grid-area: link;
	justify-self: start;
	margin-top: 0;
}

.tg-home-products .tg-section-link .wp-block-button__link {
	min-height: 52px;
	padding: 0 var(--wp--preset--spacing--60);
	font-size: 1.0625rem;
}

@media (min-width: 640px) {
	.tg-home-products {
		grid-template-areas:
			"title"
			"grid"
			"link";
	}

	/* T-330/T-344: the row keeps its own air above; the white panel is gone — the product cards
	 * are white cards now, the same container language as the category index. */
	.tg-main.tg-front .tg-home-products {
		margin-block-start: var(--wp--preset--spacing--90);
	}
}

.tg-product-grid--home {
	grid-template-columns: 1fr 1fr;
	gap: var(--wp--preset--spacing--50) var(--wp--preset--spacing--40);
}

@media (min-width: 900px) {
	.tg-product-grid--home {
		grid-template-columns: repeat(3, 1fr);
		gap: var(--wp--preset--spacing--60) var(--wp--preset--spacing--50);
	}
}

:is(.tg-ruled--services, .tg-ruled--paths) .tg-ruled__row {
	padding-block: var(--wp--preset--spacing--50);
}

/* Ruled link rows (OEM/ODM services, T-315 audience paths): the whole row is one link; hover and focus change the title, not the layout. */
:is(.tg-ruled--services, .tg-ruled--paths) a.tg-ruled__row:hover .tg-ruled__title,
:is(.tg-ruled--services, .tg-ruled--paths) a.tg-ruled__row:focus-visible .tg-ruled__title {
	color: var(--wp--preset--color--accent);
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 4px;
}

:is(.tg-ruled--services, .tg-ruled--paths) a.tg-ruled__row:hover .tg-ruled__desc,
:is(.tg-ruled--services, .tg-ruled--paths) a.tg-ruled__row:focus-visible .tg-ruled__desc {
	color: var(--wp--preset--color--ink);
}

:is(.tg-ruled--services, .tg-ruled--paths) a.tg-ruled__row:focus-visible {
	outline-offset: 6px;
}

/* T-322: each OEM/ODM service row carries a small service photograph. */
.tg-ruled--services .tg-ruled__thumb {
	display: block;
	overflow: hidden;
	background: var(--wp--preset--color--photo-ground);
	aspect-ratio: 3 / 2;
}

.tg-ruled--services .tg-ruled__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media (max-width: 899px) {
	.tg-ruled--services .tg-ruled__row {
		grid-template-columns: 64px minmax(0, 1fr);
		grid-template-areas:
			"thumb title"
			"thumb desc";
		align-items: start;
	}

	.tg-ruled--services .tg-ruled__thumb {
		grid-area: thumb;
	}
}

@media (min-width: 900px) {
	.tg-ruled--services .tg-ruled__row {
		grid-template-columns: 96px minmax(0, 5fr) minmax(0, 7fr);
		grid-template-areas: "thumb title desc";
	}

	.tg-ruled--services .tg-ruled__thumb {
		grid-area: thumb;
		align-self: center;
	}

	.tg-ruled--services .tg-ruled__title {
		grid-area: title;
	}

	.tg-ruled--services .tg-ruled__desc {
		grid-area: desc;
	}
}

/* T-323 (owner reference 2026-10-11): section eyebrow, OEM/ODM service cards and the icon button.
 * The eyebrow ("OUR SERVICES"), the arrow affordances and the rounded card kit are the named exceptions
 * recorded in DESIGN §10 / D-37 — they apply to this Home module only. */
.tg-eyebrow {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	margin: 0 0 var(--wp--preset--spacing--30);
	color: var(--wp--preset--color--accent);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.tg-eyebrow::after {
	content: "";
	flex: 0 0 56px;
	height: 2px;
	background: var(--wp--preset--color--accent);
}

/* Section CTA with a leading and a trailing icon (raw markup: a core/button cannot hold inline SVG). */
.tg-btn-icon {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	min-height: 44px;
	padding: 0 20px;
	border: 1px solid var(--wp--preset--color--ink);
	border-radius: var(--wp--custom--radius--button);
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 600;
	text-decoration: none;
	transition: background-color var(--wp--custom--motion--fast);
}

.tg-btn-icon:hover {
	background: var(--wp--preset--color--accent-tint);
}

.tg-btn-icon .tg-icon {
	display: block;
	width: 18px;
	height: 18px;
	color: currentColor;
}

/* T-328: leading icons carry the brand tint; mark them with `tg-icon--lead` so a trailing
 * arrow always keeps the button's own colour (a marker span is the first *element* child
 * either way, so :first-child cannot tell them apart). */
.tg-btn-icon .tg-icon--lead {
	color: var(--wp--preset--color--accent);
}

/* T-315: commercial terms row — three label/value pairs in datasheet style (data, not links).
 * Reused on /wholesale/ via the generic `.tg-terms` class (T-316). */
:is(.tg-oem-terms, .tg-terms) {
	display: grid;
	list-style: none;
	margin: 0 0 var(--wp--preset--spacing--50);
	padding: 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}

:is(.tg-oem-terms, .tg-terms) li {
	display: grid;
	gap: 2px;
	padding-block: var(--wp--preset--spacing--30);
}

:is(.tg-oem-terms, .tg-terms) li + li {
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-oem-terms__label,
.tg-terms__label {
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-oem-terms__value,
.tg-terms__value {
	font-weight: 600;
}

@media (min-width: 640px) {
	:is(.tg-oem-terms, .tg-terms) {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	:is(.tg-oem-terms, .tg-terms) li {
		padding-inline: var(--wp--preset--spacing--40);
	}

	:is(.tg-oem-terms, .tg-terms) li:first-child {
		padding-left: 0;
	}

	:is(.tg-oem-terms, .tg-terms) li + li {
		border-top: 0;
		border-left: 1px solid var(--wp--preset--color--rule);
	}
}

@media (min-width: 900px) {
	.tg-oem-intro {
		grid-template-columns: 5fr 7fr;
		gap: var(--wp--preset--spacing--80);
		align-items: center;
	}

}

/* Production: dark slate band (T-615). Checkmarks use accent-on-dark so they hold on slate. */
.tg-front .tg-production {
	background: var(--wp--preset--color--slate);
	color: var(--wp--preset--color--paper);
}

.tg-main.tg-front .tg-production :where(h2, li, strong) {
	color: var(--wp--preset--color--paper);
}

.tg-main.tg-front .tg-production :where(p) {
	color: var(--wp--preset--color--slate-muted);
}

.tg-front .tg-production .tg-checklist li::before {
	background: var(--wp--preset--color--accent-on-dark);
}

.tg-front .tg-production :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--paper);
}

.tg-production__text {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-production__head h2 {
	margin-bottom: var(--wp--preset--spacing--40);
}

.tg-main .tg-production__head p {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
}

.tg-main .tg-checklist {
	margin: var(--wp--preset--spacing--50) 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-main .tg-checklist li {
	margin: 0;
	padding-block: var(--wp--preset--spacing--30);
	border-bottom: 1px solid var(--wp--preset--color--rule);
	font-weight: 500;
}

@media (min-width: 900px) {
	.tg-production__text {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		column-gap: var(--wp--preset--spacing--80);
		align-items: end;
	}

	.tg-main .tg-production__text .tg-checklist {
		margin-top: 0;
	}

	/* Mosaic geometry lives in home-ui-v2.css so the two stylesheets do not fight. */
}

/* Founder teaser: real portrait 4:5, serif pull quote from the approved note. */
.tg-founder {
	display: grid;
	gap: var(--wp--preset--spacing--70);
	align-items: center;
}

.tg-front .tg-founder__portrait img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 5;
	object-fit: cover;
}

.tg-founder__portrait figcaption,
.tg-story__photo figcaption {
	margin: var(--wp--preset--spacing--40) 0 0;
	color: var(--wp--preset--color--ink-muted);
	font-family: var(--wp--preset--font-family--grotesk);
	font-size: 0.9375rem;
	line-height: 1.6;
	text-align: left;
}

/* The byline carries the founder's name at the same weight as the quote it signs off. */
.tg-founder__portrait figcaption a {
	color: var(--wp--preset--color--accent);
	text-underline-offset: 3px;
}

.tg-founder__portrait figcaption strong,
.tg-story .tg-story__photo figcaption strong {
	display: inline;
	color: var(--wp--preset--color--ink);
	font-weight: 600;
}

.tg-founder__body {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	align-content: center;
	max-width: 62ch;
}

.tg-founder__body h2,
.tg-main .tg-founder__body p {
	margin: 0;
}

.tg-main .tg-founder__body > p {
	color: var(--wp--preset--color--ink-muted);
}

.tg-founder__quote {
	margin: 0;
	padding: 0 0 0 var(--wp--preset--spacing--50);
	border-left: 2px solid var(--wp--preset--color--ink);
}

.tg-main .tg-founder__quote p {
	color: var(--wp--preset--color--ink);
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem);
	line-height: 1.5;
}

@media (min-width: 640px) {
	.tg-founder {
		grid-template-columns: 5fr 7fr;
	}
}

/* Production images (AI placeholders until real factory photos, see TODO): one main 16:9 + two small.
 * T-313 (P4.2): the mosaic breaks out of the container to the bleed width, centred on the container,
 * and whatever the viewport it never exceeds 100vw minus the gutters, so no horizontal scrollbar. */
.tg-factory-media {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

.tg-factory-media__row {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: var(--wp--preset--spacing--40);
}

.tg-factory-media .wp-block-image {
	margin: 0;
}

.tg-factory-media img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	background: var(--wp--preset--color--photo-ground);
}

@media (min-width: 900px) {
	.tg-founder {
		gap: var(--wp--preset--spacing--80);
	}

	.tg-front .tg-founder__portrait {
		max-width: 440px;
	}
}

/* Our Story: the same real portrait in the 4:5 column. */
.tg-story__photo {
	margin: 0;
}

.tg-story__photo img {
	display: block;
	background: var(--wp--preset--color--photo-ground);
	width: 100%;
	height: auto;
	aspect-ratio: 4 / 5;
	object-fit: cover;
}

/* Latest Insights: a 3:2 thumbnail, category above the title, date at the end. */
/* T-338: the Home module is a compact text list (owner review: the card grid was too heavy for a
 * secondary entry point). The Insights archive, category and related-post rows keep the ruled
 * layout below. */
.tg-front .tg-home-insights .tg-ruled {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	border-top: 0;
}

.tg-front .tg-insight-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	padding: var(--wp--preset--spacing--50) 0;
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

.tg-front .tg-insight-row__text {
	/* P1-1: the card's text column fills the row and "Read more" is its footer, so the three
	 * rows' affordances share one baseline even when one excerpt runs a line longer. */
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	justify-content: flex-start;
	min-width: 0;
	gap: var(--wp--preset--spacing--30);
	align-content: center;
}

.tg-front .tg-insight-row__text .tg-insight-row__more {
	margin-top: auto;
}

/* The Home news row's headline size lives here, not as a `fontSize` attribute on the
 * `core/post-title` block: spec §10 requires page content and patterns to carry no
 * heading-level size of their own, so every size resolves from `is-style-document`. */
.tg-front .tg-insight-row .wp-block-post-title {
	font-size: var(--wp--preset--font-size--h-4);
	line-height: 1.3;
}

.tg-front .tg-insight-row__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--wp--preset--spacing--30);
}

/* T-334: one primary category per card — the terms block renders every category of the post. */
.tg-front .tg-insight-row__cat a ~ a,
.tg-front .tg-insight-row__cat li + li,
.tg-front .tg-insight-row__cat .wp-block-post-terms__separator {
	display: none;
}

.tg-front .tg-insight-row__cat {
	width: fit-content;
	margin: 0;
	padding: 5px 10px;
	border-radius: 999px;
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--accent);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	line-height: 1.4;
	text-transform: uppercase;
}

.tg-front .tg-insight-row__cat a {
	color: var(--wp--preset--color--accent);
}

.tg-front .tg-insight-row__cat a:hover,
.tg-front .tg-insight-row__cat a:focus-visible {
	color: var(--wp--preset--color--accent-dark);
}

.tg-insight-row__media {
	margin: 0;
	background: var(--wp--preset--color--photo-ground);
}

.tg-insight-row__media img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

.tg-insight-row__text {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	align-content: start;
}

.tg-main .tg-insight-row__text :where(p, div) {
	margin: 0;
}

.tg-insight-row__cat {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.tg-insight-row__cat a {
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
}

.tg-insight-row__cat a:hover,
.tg-insight-row__cat a:focus-visible {
	color: var(--wp--preset--color--ink);
	text-decoration: underline;
}

.tg-front .tg-insight-row__date {
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-home-insights__all {
	margin-top: var(--wp--preset--spacing--50);
}

/* Small screens: compact news rows (square thumb beside the text), wider step images. */
@media (max-width: 639px) {
	.tg-front .tg-insight-row {
		grid-template-columns: minmax(0, 1fr);
		gap: var(--wp--preset--spacing--40);
		padding: var(--wp--preset--spacing--30);
	}

	.tg-front .tg-insight-row__media {
		grid-row: auto;
	}

	.tg-insight-row__media {
		grid-row: 1 / span 2;
	}

	.tg-front .tg-insight-row__media img {
		aspect-ratio: 16 / 9;
	}

	.tg-front .tg-insight-row .wp-block-post-title {
		font-size: var(--wp--preset--font-size--body);
		line-height: 1.35;
	}

	.tg-steps {
		row-gap: var(--wp--preset--spacing--60);
	}

	/* The step grid and the rule position are set in the base block above. The 96px thumb column,
	 * `grid-template-rows` and the `left: 120px` rule start that lived here belonged to the
	 * photo-based How-we-work layout, which T-338 deleted: with no `.tg-step__media` in the markup
	 * they left 120px of dead space, moved the number into the text column and shifted the rule, so
	 * a step duration could not sit beside it without colliding with the next number (owner report,
	 * 2026-10-12). `tg-how` and `tg-step__media` are gone from every template. */

	.tg-oem-process .tg-step {
		display: flex;
		flex-direction: column;
	}
}

@media (min-width: 640px) {
	.tg-insight-row__media {
		grid-row: 1 / span 2;
	}
}

/* T-340/T-342: the closing band hosts the two-field quick form — email and submit share a row, the
 * requirement box stays short, and the whole band is about half its former height. */
.tg-cta-band--brand .tg-form--quick {
	display: grid;
	gap: var(--wp--preset--spacing--30);
}

.tg-cta-band--brand .tg-form--quick label {
	display: block;
	margin-bottom: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 600;
}

.tg-cta-band--brand .tg-form--quick input[type="email"],
.tg-cta-band--brand .tg-form--quick textarea {
	width: 100%;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--button);
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--ink);
	font-size: 1rem;
}

.tg-cta-band--brand .tg-form--quick textarea {
	min-height: 64px;
	resize: vertical;
}

/* The submit is the band's only primary action and sits under the field it submits, so the two
 * fields read in order and there is nothing to press before the requirement is written (owner
 * review, 2026-10-12). */
.tg-cta-band--brand .tg-form--quick p {
	margin: 0;
}

.tg-cta-band--brand .tg-form--quick .tg-field-hint {
	display: inline;
	font-size: 0.875rem;
}

.tg-cta-band--brand .tg-form--quick .tg-field--send {
	margin-top: var(--wp--preset--spacing--40);
}

/* What happens next: three steps under the form, so the visitor knows what the submission starts. */
.tg-band-steps {
	margin-top: var(--wp--preset--spacing--40);
	padding-top: var(--wp--preset--spacing--40);
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-band-steps__lead {
	margin: 0 0 var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-size: 0.875rem;
	font-weight: 600;
}

.tg-main .tg-band-steps__list {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-band-steps__list li {
	display: grid;
	grid-template-columns: 20px minmax(0, 1fr);
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
}

.tg-band-steps__icon {
	display: grid;
	place-items: center;
	color: var(--wp--preset--color--accent);
}

.tg-band-steps__icon svg {
	width: 18px;
	height: 18px;
}

/* The band carries one primary button (the form's submit). WhatsApp is a plain text link so it
 * cannot compete with it. */
.tg-cta-band__ghost {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink);
	font-weight: 600;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

.tg-cta-band__ghost:hover,
.tg-cta-band__ghost:focus-visible {
	text-decoration-thickness: 2px;
}

.tg-cta-band__ghost .tg-icon {
	width: 16px;
	height: 16px;
	color: var(--wp--preset--color--accent);
}

/* one wrapped row of microcopy under the form */
.tg-cta-band--brand .tg-cta-band__micro {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--40);
}

/* It follows the What-happens-next list, so it needs its own breath. */
.tg-band-steps + .tg-cta-band__micro {
	margin-top: var(--wp--preset--spacing--40);
}

.tg-cta-band--brand .tg-form--quick .wpcf7-submit {
	min-height: 52px;
	padding: 0 var(--wp--preset--spacing--60);
	border: 0;
	border-radius: var(--wp--custom--radius--button);
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--paper);
	font-size: 1.0625rem;
	font-weight: 600;
	cursor: pointer;
}

.tg-cta-band--brand .tg-form--quick .wpcf7-submit:hover {
	background: var(--wp--preset--color--accent-dark);
}

.tg-cta-band--brand .tg-form--quick .tg-consent {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: 0.875rem;
}

/* T-326/T-328: closing band — brand-tint block, heading left, actions right, both centred on
 * the same 12-column grid the footer uses, so the columns line up. */
.tg-cta-band--brand {
	background: var(--wp--preset--color--accent-tint);
	border-top: 0;
	color: var(--wp--preset--color--ink);
	/* Client review 2026-10-22: symmetrical padding, 72px at desktop and 48px on a phone. It was
	 * `clamp(40px, 3.5vw, 72px)`, i.e. 50px at 1440 — and the band's last child added its own
	 * margin on top of that. */
	padding-block: clamp(48px, 5vw, 72px);
}

/* P0-5: the band's copy is aligned by `.tg-cta-band__grid` (which carries `tg-container`) on
 * every page, Home included — the Home-only inline-padding formula this replaces was the same
 * alignment written twice, and it double-counted once the grid became a container. */

.tg-cta-band--brand :where(h2, p) {
	color: var(--wp--preset--color--ink);
}

.tg-cta-band--brand :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--accent);
}

/* T-646, client's Contact mockup: the Home band's heading is one step down. It was the `h-1` token
 * (56px at 1440), which is a page-title size, and against the client's own layout it read as the
 * loudest thing on the screen — 2 lines measured 123px against 98px in the mockup. The `h-2` token
 * puts it at 48px, which is what every other section heading on Home uses. */
.tg-front .tg-cta-band--brand h2 {
	font-size: var(--wp--preset--font-size--h2);
	line-height: 1.1;
	letter-spacing: -0.015em;
}

/* The rest of the Home band's rhythm, matched to the same mockup. Each value is the mockup's own
 * measurement at our content width (1056px), not a guess: the lead's line pitch 24px, the contact
 * rows 34px, the steps 28px. Inner pages keep the shared band scale — the product page's band is
 * the reference elsewhere (D-71), and this variant is Home's. */
.tg-front .tg-cta-band--brand .tg-cta-band__intro > p {
	line-height: 1.45;
}

/* The row gap tightens; the icon-to-value gap inside a row does not (that is `spacing-30` and is
 * what the mockup shows between a mark and its text). */
.tg-front .tg-cta-band--brand .tg-contact-info {
	gap: var(--wp--preset--spacing--20);
	line-height: 1.45;
}

.tg-front .tg-cta-band--brand .tg-contact-info__item {
	line-height: 1.45;
}

.tg-front .tg-cta-band--brand .tg-contact-info__icon svg {
	width: 18px;
	height: 18px;
}

.tg-front .tg-cta-band--brand .tg-band-steps__list {
	gap: var(--wp--preset--spacing--20);
}

.tg-front .tg-cta-band--brand .tg-band-steps__list li {
	line-height: 20px;
}

.tg-front .tg-cta-band--brand .tg-band-steps__icon svg {
	width: 16px;
	height: 16px;
}

.tg-cta-band__aside > * + * {
	margin-top: var(--wp--preset--spacing--30);
}

.tg-cta-band__aside p {
	color: var(--wp--preset--color--ink-muted);
}

.tg-cta-band__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
}

/* The band's one primary action; the ghost links sit beside it. */
.tg-btn-icon--solid {
	background: var(--wp--preset--color--accent);
	border-color: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--paper);
}

.tg-btn-icon--solid:hover {
	background: var(--wp--preset--color--accent-dark);
	border-color: var(--wp--preset--color--accent-dark);
	color: var(--wp--preset--color--paper);
}

.tg-btn-icon--solid .tg-icon {
	color: currentColor;
}

.tg-cta-band--brand .tg-btn-icon {
	min-height: 52px;
	padding: 0 var(--wp--preset--spacing--60);
	font-size: 1.0625rem;
}

.tg-cta-band--brand .tg-btn-icon:not(.tg-btn-icon--solid):hover {
	background: var(--wp--preset--color--accent-tint-strong);
}

.tg-cta-band__aside .tg-cta-band__micro {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--50);
	font-size: 0.9375rem;
	color: var(--wp--preset--color--ink);
}

.tg-cta-band__micro-item {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
}

/* Plain status text beside the ghost link needs a separator, or it reads as part of the link. */
.tg-cta-band__ghost + .tg-cta-band__micro-item::before {
	content: "";
	width: 1px;
	height: 16px;
	margin-right: var(--wp--preset--spacing--20);
	background: var(--wp--preset--color--rule);
}

.tg-cta-band__micro-item .tg-icon {
	width: 18px;
	height: 18px;
	color: var(--wp--preset--color--accent);
}

/* The phone size is no longer an override: T-646 moved the Home heading to the `h-2` token, which
 * is already 32px at 375 (the old rule set exactly that when the desktop size was `h-1`). */

/* T-327: the closing band is brand-tinted, so the slate footer needs no divider of its own;
 * the only rule inside the footer is the container-width one above the legal line.
 * Below 640px the short link lists sit two-up.
 *
 * Owner review 2026-10-15: `1fr 1fr` means `minmax(auto, 1fr)`, so an unbreakable value (the email
 * or the WhatsApp number) widened its own column and the second column then started at a different
 * x in each group. `minmax(0, 1fr)` pins both columns to the same line for every group; the two
 * long contact values take the full width so they never fold, and the number stays on one line. */
@media (max-width: 639px) {
	.tg-footer__nav .wp-block-navigation__container,
	.tg-footer__links {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: var(--wp--preset--spacing--50);
	}

	/* The core Navigation block wraps its list in a shrink-to-fit flex item, so the list's own width
	 * followed its content: the group with the shortest labels came out 208px wide against 327px for
	 * the others, and its second column started 60px earlier (measured at 375px). Full width for the
	 * wrapper and the list puts every group on the same two columns. */
	.tg-footer__nav,
	.tg-footer__nav .wp-block-navigation__container {
		width: 100%;
	}

	.tg-footer__links a {
		white-space: nowrap;
	}

	/* P2-6: on a phone the footer is a navigation surface, and its links measured 26px tall —
	 * under the 44px the prompt asks for. The desktop rows keep their density (T-640 left the
	 * 26px header/footer rows alone on the owner's call); only ≤639px grows the target. The
	 * 12px grid gap between items stays, so the extra height is inside the link, not between. */
	.tg-footer__nav .wp-block-navigation-item__content {
		display: inline-flex;
		align-items: center;
		min-height: 44px;
	}

	.tg-footer__links li:first-child,
	.tg-footer__links li:nth-child(2) {
		grid-column: 1 / -1;
	}
}

/* T-327: the hidden "Follow" block used to leave an empty track; the 12-column grid above
 * assigns explicit lines, so that override is gone. */

/* ---------------------------------------------------------------
 * Home audit fixes (Oct 9): fact strip, tile spec lines, quote
 * button after OEM/ODM, client stories teaser, closing band contact
 * line, footer logo, mobile trims.
 * ------------------------------------------------------------- */

/* About band on Home (T-317): a factory image beside the company line and a link to Our Story,
 * placed above the OEM/ODM services. T-319 gives the band its own grey-green surface. */
.tg-about__grid {
	display: grid;
	gap: var(--wp--preset--spacing--60);
	align-items: center;
}

.tg-about__media {
	margin: 0;
}

.tg-about__media img {
	display: block;
	width: 100%;
	height: auto;
}

.tg-about__lead {
	font-size: clamp(1.125rem, 0.95rem + 0.6vw, 1.375rem);
	font-weight: 600;
	line-height: 1.4;
}

@media (min-width: 900px) {
	/* T-339: the portrait was outweighing the copy — give the text the wider column. */
	.tg-about__grid {
		grid-template-columns: 5fr 7fr;
		gap: var(--wp--preset--spacing--80);
	}
}

/* T-339: the merged About + Founder section is a two-level hierarchy: the statement, then the
 * founder's words, then a short company line. */
.tg-about__body h2 {
	text-wrap: balance;
}

.tg-about__body .tg-founder__quote {
	margin: var(--wp--preset--spacing--50) 0 0;
	font-size: 1.0625rem;
	line-height: 1.6;
}

.tg-about__body p {
	max-width: 46ch;
	color: var(--wp--preset--color--ink-muted);
}

.tg-facts + .tg-products {
	padding-top: var(--wp--custom--section--padding-tight);
}

/* T-338/T-339: the OEM/ODM section carries the process timeline; a hairline sets it apart from the
 * copy above, and the sub-heading is a clear second level (owner review). */
.tg-oem-process {
	margin-top: var(--wp--preset--spacing--90);
	padding-top: var(--wp--preset--spacing--80);
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-oem-process h3 {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: clamp(1.375rem, 1.2rem + 0.5vw, 1.625rem);
}

.tg-oem-process > p {
	max-width: 62ch;
	margin: 0 0 var(--wp--preset--spacing--60);
	color: var(--wp--preset--color--ink-muted);
}

.tg-link-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	margin: var(--wp--preset--spacing--90) 0 0;
	padding-top: var(--wp--preset--spacing--50);
	border-top: 1px solid var(--wp--preset--color--rule);
	font-size: 0.9375rem;
}

.tg-link-row strong {
	color: var(--wp--preset--color--ink-muted);
	font-weight: 600;
}

.tg-link-row a {
	display: inline-flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--accent);
	text-decoration: none;
}

.tg-link-row .tg-icon {
	width: 14px;
	height: 14px;
	color: var(--wp--preset--color--accent-dark);
}

.tg-link-row a:hover,
.tg-link-row a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* T-324: the OEM/ODM section head carries the OEM/ODM link and the quote CTA side by side;
 * they stack on phones. */
.tg-oem-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--wp--preset--spacing--40);
	margin: var(--wp--preset--spacing--60) 0 0;
}

.tg-oem-actions .tg-section-link,
.tg-oem-actions .wp-block-buttons {
	margin: 0;
}

/* T-334: the two actions share one size — the primary (Request a Quote) first, the outline link
 * second with a single trailing arrow. */
.tg-oem-actions .tg-btn-icon,
.tg-oem-actions .wp-block-button__link {
	min-height: 48px;
	padding: 0 var(--wp--preset--spacing--50);
	font-size: 1rem;
}

@media (max-width: 639px) {
	.tg-oem-actions {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--wp--preset--spacing--30);
	}
}

/* Client stories teaser: only rendered when real (non-sample) stories exist. */
.tg-main .tg-home-stories .tg-ruled > li {
	max-width: none;
	margin: 0;
}

.tg-story-row {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	padding-block: var(--wp--preset--spacing--50);
}

.tg-story-row .wp-block-post-title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-3);
}

.tg-story-row .wp-block-post-title a {
	color: inherit;
	text-decoration: none;
}

.tg-story-row .wp-block-post-title a:hover,
.tg-story-row .wp-block-post-title a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-main .tg-story-row .wp-block-post-excerpt__excerpt {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
}

@media (min-width: 900px) {
	.tg-story-row {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		column-gap: var(--wp--preset--spacing--50);
		align-items: baseline;
	}
}

/* Footer: the logo SVG (paper letters on slate) replaces the text wordmark. */
.tg-footer__brand .tg-logo {
	margin-bottom: var(--wp--preset--spacing--40);
}

.tg-footer__brand .tg-logo img {
	height: 32px;
}

/* Small screens: the step timeline as a plain numbered list, hero-aware WhatsApp. */
@media (max-width: 639px) {
	/* WhatsApp waits until the hero CTAs have scrolled away (class set by hero-video.js). */
	.tg-hero-in-view .tg-whatsapp {
		visibility: hidden;
		opacity: 0;
	}
}


/* ---------------------------------------------------------------
 * Home module refinements (T-607 round): one 5/7 column line shared
 * by OEM/ODM, Production and the service rows; checklist markers;
 * quieter meta.
 * ------------------------------------------------------------- */

/* OEM/ODM service rows use the same 5/7 split and gutter as the intro above them. */
@media (min-width: 900px) {
	.tg-ruled--services .tg-ruled__row {
		column-gap: var(--wp--preset--spacing--80);
	}
}

/* T-313: the mobile page keeps the same blocks with a tighter vertical rhythm, so the sections do not
 * read as one long strip of heading plus gap on a 375px screen. */
@media (max-width: 639px) {
	.tg-section h2,
	.tg-section__head {
		margin-bottom: var(--wp--preset--spacing--60);
	}

    .tg-home-products {
        margin-top: var(--wp--preset--spacing--50);
        gap: var(--wp--preset--spacing--50);
    }

	.tg-cat-index__item {
		gap: var(--wp--preset--spacing--20);
		padding-bottom: var(--wp--preset--spacing--30);
	}

	.tg-cat-index__text {
		padding-inline: var(--wp--preset--spacing--30);
	}

	.tg-cat-index__name {
		font-size: 1rem;
	}

	.tg-cat-index__spec {
		font-size: var(--wp--preset--font-size--small);
	}

	.tg-cat-index__go {
		width: 28px;
		height: 28px;
		margin-right: var(--wp--preset--spacing--30);
	}

	.tg-cat-index__go svg {
		width: 16px;
		height: 16px;
	}

	/* T-318: compress the About band on phones (16:9 image, tighter gaps). */
	.tg-about__grid {
		gap: var(--wp--preset--spacing--50);
	}

	.tg-about__media:not(.tg-founder__portrait) img {
		aspect-ratio: 16 / 9;
		object-fit: cover;
	}

	.tg-about__lead {
		margin-bottom: var(--wp--preset--spacing--30);
	}

    .tg-product-grid--home {
        row-gap: var(--wp--preset--spacing--40);
    }

    .tg-product-grid--home .tg-product-tile__cat {
        margin-top: var(--wp--preset--spacing--30);
    }

	.tg-product-grid--home :is(.tg-product-tile__spec, .tg-product-tile__certs) {
		margin-top: var(--wp--preset--spacing--10);
	}

	.tg-product-grid--home .tg-product-tile__media {
		aspect-ratio: 16 / 9;
	}


	.tg-oem-intro {
		margin-bottom: var(--wp--preset--spacing--60);
	}
}

/* Checklist: a drawn check marks each item (P1-9). It used to be a 12×2px accent dash, which the
 * client read as a hyphenated list rather than as a list of things that are covered. The check is
 * two borders on a rotated box — no icon file, no JS, the same technique as the FAQ chevron. */
.tg-main .tg-checklist li {
	display: flex;
	align-items: baseline;
	gap: var(--wp--preset--spacing--30);
}

.tg-main .tg-checklist li::before {
	content: "";
	flex: 0 0 8px;
	width: 8px;
	height: 4px;
	/* Pull the tick up off the baseline so it sits on the first line's x-height. */
	transform: translateY(-3px) rotate(-45deg);
	border-left: 2px solid var(--wp--preset--color--accent);
	border-bottom: 2px solid var(--wp--preset--color--accent);
}

/* ---------------------------------------------------------------
 * Secondary-page modules (docs/TGITION-secondary-pages-spec.md).
 *
 * The block-style variants themselves live in `styles/*.json`; only what
 * theme.json cannot express is here — grid placement, sticky columns, the
 * scroll-on-phones rules. Every selector uses `:where()` so the editor and
 * theme.json can still override it.
 * ------------------------------------------------------------ */

/* 4.4 Section split: heading + lead in 4 columns, body in the other 8, so a
 * text module spans the container instead of leaving the right half empty.
 * Below 1024px the two stack. */
.tg-split {
	display: grid;
	gap: var(--wp--preset--spacing--60) var(--wp--preset--spacing--50);
}

.tg-split :where(h2) {
	margin-top: 0;
	max-width: 20em;
}

/* P1-8: the left column is a stack, not a spaced-apart pair. The heading and its lead sit 16px
 * apart — the gap the client measured as ~100px was the section heading's own 64px bottom margin
 * stacking on the paragraph's margin. Nothing inside the column stretches either: it is sticky,
 * so its height has to stay its content (`align-content: start`, no space-between). */
.tg-split__head {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	align-content: start;
}

/* The `:where()` is zero-specificity, so the column needs one class of its own to outrank
 * `.tg-section h2`'s 64px bottom margin. */
.tg-split .tg-split__head > :where(h2, p) {
	margin-block: 0;
}

.tg-split__head :where(p) {
	max-width: 34ch;
	color: var(--wp--preset--color--ink-muted);
}

.tg-split__body > :where(:first-child) {
	margin-top: 0;
}

@media (min-width: 1024px) {
	/* 4/8 of 12: the spec's "4 columns + 8 columns", with the gutter between them. */
	.tg-split {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		gap: 0 var(--wp--preset--spacing--80);
		align-items: start;
	}

	.tg-split__head {
		/* Sticky while a long right-hand column scrolls past it. Core's own
		 * sticky option is top-level only, and this module lives inside content. */
		position: sticky;
		top: calc(var(--tg-header-height) + var(--wp--preset--spacing--50));
	}
}

/* 4.6 Component grid: auto-fitting cards, no media queries. */
.tg-feature-grid {
	display: grid;
	gap: var(--wp--preset--spacing--50);
}

.tg-feature-grid :where(h3) {
	margin-top: 0;
	/* One line, as the spec asks: a two-line capability title unbalances the row. */
	max-width: 22ch;
}

.tg-feature-grid :where(p) {
	color: var(--wp--preset--color--ink-muted);
}

.tg-tag-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
	margin-top: auto;
}

.tg-tag-row .tg-chip {
	margin: 0;
}

/* 4.10 Checklist card: the list fills the card and the action sits at its foot. */
.tg-checklist-card {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--50);
	/* P1-9: the card sits on a `surface` band on the Applications children, where its own white
	 * fill has no edge — one hairline gives it the same box as every other card in the system. */
	border: 1px solid var(--wp--preset--color--rule);
}

.tg-checklist-card__action {
	margin-top: auto;
}

/* The card frame is the edge; the list's own top rule would draw a second one just inside it. */
.tg-checklist-card .tg-checklist {
	margin-top: 0;
	border-top: 0;
}

.tg-checklist-card :where(.wp-block-buttons) {
	margin-top: auto;
}

/* Layout B (article): body in 7 columns, sidebar in 4, one empty column between
 * them. `minmax(0, …)` stops a long word or a table from widening the track.
 * Below 1024px the grid is one column, so the sidebar simply follows the body. */
.tg-article__grid {
	display: grid;
	gap: var(--wp--preset--spacing--70) 0;
}

.tg-article__grid > * {
	min-width: 0;
}

@media (min-width: 1024px) {
	.tg-article__grid {
		grid-template-columns:
			minmax(0, 7fr)
			minmax(0, 1fr)
			minmax(0, 4fr);
		align-items: start;
	}

	.tg-article__body {
		grid-column: 1;
		grid-row: 1;
	}

	.tg-article__aside {
		grid-column: 3;
		grid-row: 1;
		position: sticky;
		top: calc(var(--tg-header-height) + var(--wp--preset--spacing--50));
	}
}

/* Layout B (article) sidebar inquiry card. Text and buttons only: the portrait is
 * not invented, so the card leads with the name. */
.tg-aside-inquiry {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}

.tg-aside-inquiry__eyebrow {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: 1.2;
	text-transform: uppercase;
}

.tg-aside-inquiry__person {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
}

.tg-aside-inquiry__person :where(strong) {
	display: block;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--body);
}

.tg-aside-inquiry :where(.wp-block-buttons) {
	margin: var(--wp--preset--spacing--20) 0 0;
}

.tg-aside-inquiry :where(.wp-block-button__link) {
	width: 100%;
}

.tg-aside-inquiry__direct {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
}

/* Article head: the category is a quiet step above the title, not a second heading. */
.tg-article__terms {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.tg-article__terms :where(a) {
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
}

.tg-article__terms :where(a:hover, a:focus-visible) {
	color: var(--wp--preset--color--accent-dark);
	text-decoration: underline;
}

.tg-article__head :where(.wp-block-post-title) {
	margin: 0;
}

.tg-article__head :where(.tg-article__meta) {
	margin: var(--wp--preset--spacing--40) 0 var(--wp--preset--spacing--70);
}

/* The card variant's 32px padding is right for a wide panel and heavy on a phone;
 * 24px keeps a two-up card readable at 375px. `.wp-block-group` is in the selector
 * so this outranks the variation's `:root :where(…)` rule regardless of load order. */
@media (max-width: 639px) {
	.wp-block-group.is-style-card,
	.wp-block-group.is-style-card-link {
		padding: var(--wp--preset--spacing--50);
	}
}

/* Spec §2.4 (`docs/TGITION-secondary-pages-spec.md`): the first thing under the
 * header on a secondary page is the title area, 48px down (32px on phones) — not
 * the 128px section padding, which is the rhythm *between* modules. Measured before
 * this rule: 304px from the header's bottom edge to the H1 at 1440. */
.tg-main.is-style-document,
.tg-main.is-style-document > .tg-container {
	padding-block-start: clamp(32px, 4vw, 48px);
}

/* §2.4: 64px under the title area (40px on phones) before the first module. The
 * heading's own `spacing-80` margin is the 64px; the lead paragraph must not add to it. */
.tg-main.is-style-document > .wp-block-post-content > :where(h1) {
	margin-bottom: var(--wp--preset--spacing--40);
}

/* Contact (layout D) has no breadcrumb and its own container, so it needs the same
 * 48/32px start instead of the section padding it used to inherit. */
.tg-contact-page > .tg-container.is-style-document {
	padding-block-start: clamp(32px, 4vw, 48px);
}

/* The split modules are siblings inside one post-content flow, so the section
 * rhythm has to come from them rather than from a wrapper: 96px between two
 * modules (40px on phones), and 64px above the first one after the page lead. */
.tg-split + :where(.tg-split, .wp-block-heading, .wp-block-html, .tg-ruled) {
	margin-top: var(--wp--preset--spacing--50);
}

@media (min-width: 1024px) {
	.tg-split + :where(.tg-split, .wp-block-heading, .wp-block-html, .tg-ruled) {
		margin-top: var(--wp--preset--spacing--90);
	}
}

/* ---------------------------------------------------------------
 * Secondary-page imagery (docs/TGITION-product-image-prompts-v2 (1).md §8.2).
 *
 * Slot A is the page's featured image and is already laid out by
 * `.tg-page-header--media` (7fr / 5fr, one column when there is none).
 * Slots B and C are these two classes. Both reserve their aspect ratio in
 * CSS rather than carrying width/height on the <img>, which is the same
 * arrangement the Home modules use: the box is sized before the file
 * arrives, so the aspect-ratio declaration is what prevents layout shift.
 * ------------------------------------------------------------ */

/* B: the 21:9 band that sits between two content modules. The section carrying it adds no padding
 * of its own: the sections either side already pay their full block padding, so a band with padding
 * would double the gap into a hole. */
.tg-section--band {
	padding-block: 0;
}

.tg-page-band {
	aspect-ratio: 21 / 9;
	overflow: hidden;
	margin: 0;
}

.tg-page-band img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* C: the 4:3 figure inside a split module's left column.
 *
 * It was specified as 4:5, but the modules it sits in have a short body on the right — three
 * checklist rows and a button — so a portrait 461px tall made the left column run 900px past its
 * neighbour and the module read as lopsided. 4:3 keeps the figure clearly subordinate to the
 * heading and roughly level with the card beside it. */
.tg-page-column-media {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	margin: 0;
}

.tg-page-column-media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* One page (`/oem-odm/quality-manufacturing-support/`) has no split module at the slot the plan
 * names, so its C image sits directly in a full-width section instead of a 4fr column. Capped so a
 * portrait does not run the height of the page. */
.tg-page-column-media--standalone {
	max-width: 22rem;
	margin-top: var(--wp--preset--spacing--50);
}

/* ---------------------------------------------------------------
 * Page header parts (spec §4.1). One implementation per page type:
 *   page-header          single page      breadcrumb → H1 → lead
 *   page-header-media    + featured image, 7/5 columns (single column with no image)
 *   page-header-archive  archive          breadcrumb → query title → term description
 *   page-header-article  article          breadcrumb → term → H1 → meta → image
 * The H1 and the lead come from the page record, so no page repeats them in its body.
 * ------------------------------------------------------------ */
.tg-page-header {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	/* §2.4: 64px under the title area (40px on phones). */
	margin-bottom: var(--wp--preset--spacing--80);
}

.tg-page-header :where(.wp-block-post-title, .wp-block-query-title) {
	margin: 0;
	max-width: 22em;
	text-wrap: balance;
}

.tg-page-header__lead {
	margin: var(--wp--preset--spacing--30) 0 0;
	max-width: 60ch;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.5;
}

.tg-page-header :where(.wp-block-post-excerpt__more-text) {
	display: none;
}

/* The archive header keeps its own rhythm: the term description is the lead. */
.tg-page-header--archive {
	gap: var(--wp--preset--spacing--30);
}

.tg-page-header--archive :where(.wp-block-term-description p) {
	margin: 0;
	max-width: 60ch;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.5;
}

/* Media header: copy left, 4:3 photograph right. Without a featured image the
 * `:has()` rule collapses it to one column instead of leaving an empty half. */
.tg-page-header--media {
	gap: 0;
}

@media (min-width: 1024px) {
	.tg-page-header--media {
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		gap: var(--wp--preset--spacing--70);
		align-items: center;
	}

	.tg-page-header--media:not(:has(.wp-block-post-featured-image)) {
		grid-template-columns: minmax(0, 1fr);
	}
}

.tg-page-header__copy {
	display: grid;
	gap: var(--wp--preset--spacing--20);
}

.tg-page-header__media :where(img) {
	display: block;
	width: 100%;
	height: auto;
}

/* Article header: the featured image spans the body + sidebar width, so it sits
 * outside the 7/4 grid the article content uses. */
.tg-page-header--article {
	gap: var(--wp--preset--spacing--30);
}

.tg-page-header--article :where(.tg-page-header__media) {
	margin-top: var(--wp--preset--spacing--50);
}

.tg-page-header__terms {
	margin: 0;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.tg-page-header__terms :where(a) {
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
}

.tg-page-header__terms :where(a:hover, a:focus-visible) {
	color: var(--wp--preset--color--accent-dark);
	text-decoration: underline;
}

@media (max-width: 767px) {
	.tg-page-header {
		margin-bottom: var(--wp--preset--spacing--70);
	}
}

/* Layout C ("sections"): the page body is a stack of full-width `tg-section` bands,
 * each holding its own `tg-container` — the shape Home already uses, so a band can run
 * to the viewport edge while its content stays on the container gutter. `main` therefore
 * carries no container and no vertical padding of its own.
 * `padding-block: 0` matches `.tg-main.tg-front`. */
.tg-main--sections {
	padding-block: 0;
}

/* The title band opens the page: same 48/32px start as every other secondary page,
 * then the section's own padding under the title area. */
.tg-main--sections > .tg-section:first-child {
	padding-top: clamp(32px, 4vw, 48px);
}

/* The closing band supplies its own gutters; do not double them inside a section stack. */
.tg-main--sections > .tg-cta-band {
	margin-bottom: 0;
}

/* Spec §4.2: the subnav is a single list that includes the current page, marked with
 * `aria-current` and a 2px underline that sits on the bar's own bottom rule. It no longer
 * carries a separate bold section label — the breadcrumb above names the hub. */
.tg-section-bar--list {
	grid-template-columns: minmax(0, 1fr);
}

.tg-section-bar--list .tg-section-bar__nav a[aria-current="page"] {
	color: var(--wp--preset--color--ink);
	font-weight: 500;
	box-shadow: inset 0 -2px 0 var(--wp--preset--color--accent);
}

@media (min-width: 900px) {
	.tg-section-bar--list {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* The title band is the page header, not a module: the 48/32px start under the header already
 * comes from `.tg-main.is-style-document` (P1-6), so the band adds none of its own — that double
 * count is what put the breadcrumb 96px under the header instead of 48. Its bottom side uses the
 * tight step, which is also what the first module band starts with, so the boundary reads the
 * same from both sides (P0-4). */
.tg-main .tg-title-band {
	padding-block: 0 var(--wp--custom--section--padding-tight);
}

.tg-main--sections > .tg-title-band .tg-page-header {
	margin-bottom: 0;
}

/* The subnav sits in the same title-band as the header, so without this it shares the
 * header's 8px grid gap and the lead reads as one line of the bar. 32px is the same
 * rhythm as the header's own H1 → lead. The header is wrapped in a template-part, so
 * the adjacent sibling is `.wp-block-template-part`, not `.tg-page-header`. */
.tg-title-band .wp-block-template-part:has(.tg-page-header) + .tg-section-bar {
	margin-top: var(--wp--preset--spacing--50);
}

/* The module bands live inside `core/post-content`, so they are grandchildren of `main`,
 * not children: the first one needs the descendant path, not a direct-child `>`. It starts on
 * the same tight step the title band ends with, so the boundary between the title area and the
 * first module is symmetrical (P0-4). */
.tg-main--sections > .tg-title-band + .wp-block-post-content > .tg-section:first-child {
	padding-top: var(--wp--custom--section--padding-tight);
}

/* The grid filler (spec §5.1). Fills the last row's empty cells on a product category
 * whose product count is not a multiple of the column count. `accent-tint` background,
 * one link, no second tab stop. */

/* Stretch to the row height: a short filler beside two full product cards read as a
 * broken row rather than as a card (measured 285px against 505px before this rule). */
.tg-product-tile--custom {
	align-self: stretch;
}

.tg-custom-card {
	position: relative;
	height: 100%;
	display: flex;
	flex-direction: column;
	/* Centred rather than stretched: the card matches the product tiles' height, and a
	 * top-aligned three-line message left a 150px void under it. */
	justify-content: center;
	gap: var(--wp--preset--spacing--20);
	padding: var(--wp--preset--spacing--50);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--accent-tint);
}

/* The whole card is the link, the same way the product tile's title link covers it. */
.tg-custom-card__link a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.tg-custom-card:focus-within {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 3px;
}

.tg-custom-card__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-3);
}

.tg-custom-card__text {
	margin: 0;
	max-width: 26ch;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.5;
}

.tg-custom-card__link {
	margin: var(--wp--preset--spacing--20) 0 0;
	font-weight: 600;
}

.tg-custom-card__link :where(a) {
	color: var(--wp--preset--color--accent-dark);
}

.tg-custom-card:hover .tg-custom-card__title,
.tg-custom-card:focus-within .tg-custom-card__title {
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* Subcategory row (spec §5.1): only rendered when the current category really has
 * children, so it is invisible until the catalogue grows a second level. */
.tg-subcategory-row {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin: 0 0 var(--wp--preset--spacing--70);
	padding: 0;
	list-style: none;
}

@media (min-width: 640px) {
	.tg-subcategory-row {
		grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	}
}

.tg-main .tg-subcategory-row li {
	margin: 0;
}

.tg-subcategory-row__link {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--10);
	padding: var(--wp--preset--spacing--50);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--surface);
	box-shadow: var(--wp--preset--shadow--card, none);
	text-decoration: none;
}

.tg-subcategory-row__link:hover,
.tg-subcategory-row__link:focus-visible {
	box-shadow: var(--wp--preset--shadow--card-hover, none);
}

.tg-subcategory-row__name {
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--h-4);
	font-weight: 600;
}

.tg-subcategory-row__count {
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

/* Empty state: no empty grid, one sentence and the conversion route (spec §5.1). */
.tg-empty-state {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	justify-items: start;
	padding: var(--wp--preset--spacing--70) var(--wp--preset--spacing--50);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--surface);
}

.tg-empty-state__text {
	margin: 0;
	max-width: 46ch;
	color: var(--wp--preset--color--ink-muted);
}

/* Client stories archive (spec §5.5): the same story card the Home teaser uses, laid out
 * as a grid rather than a ruled list. Only the container differs — the card's own head
 * (flag + country / quote / name / type) is injected by the one renderer in
 * `inc/home-stories.php`, so there is still a single story-card implementation. */
.tg-story-grid {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 768px) {
	.tg-story-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1200px) {
	.tg-story-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.tg-main .tg-story-grid > li {
	margin: 0;
	max-width: none;
}

/* The card, not a row: the ruled-list geometry and hairline belong to the Home teaser. */
.tg-story-grid .tg-story-row {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
	height: 100%;
	padding: var(--wp--preset--spacing--50);
	border-bottom: 0;
}

@media (min-width: 900px) {
	.tg-story-grid .tg-story-row {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* The story title is the card's link and the last thing in it.
 *
 * Client request 2026-10-22: the title and the arrow after it read at 小三 (15pt = 20px) on the
 * Client stories page — the shared `h-3` step (27.84px at 1440) was a section-heading size on a
 * card whose body text is 17px. Scoped to the archive's grid: the Home teaser keeps its own
 * smaller row treatment. */
.tg-story-grid .tg-story-row .wp-block-post-title {
	margin: auto 0 0;
	padding-top: var(--wp--preset--spacing--30);
	font-size: 1.25rem;
	line-height: 1.25;
}

/* The arrow rides with the title, so it is set at the title's size — 16px glyph against 20px
 * type, on the text baseline, one 8px step in from the words. */
.tg-story-grid .tg-story-row .wp-block-post-title .tg-icon {
	width: 16px;
	height: 16px;
	margin-left: var(--wp--preset--spacing--20);
	vertical-align: -2px;
}

/* Client request 2026-10-22: on the Client stories page the flag and the country name were set
 * flush against each other — the meta line is a block there (the Home teaser is where the
 * `flex + gap: 10px` lives), so the inline flag and the name measured a 0px visual gap. The
 * `flex` is scoped to the archive's card grid so the Home rows keep their own treatment. */
.tg-story-grid .tg-story-row__meta {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--20);
	margin: 0;
	color: var(--wp--preset--color--ink);
}

.tg-story-grid .tg-flag {
	display: block;
	flex: none;
	/* `border-box`: the 1px rule is part of the 21x14, not extra. Without it the flag measured
	 * 23x16 once the parent became a flex container, because a flex item's width is a border-box
	 * and the inline default here was content-box. */
	box-sizing: border-box;
	width: 21px;
	height: 14px;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 2px;
}

.tg-story-grid .tg-story-row__quote {
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.5;
}

/* ---------------------------------------------------------------
 * Insights list (spec §5.7): one lead article, then a card grid.
 * Both queries carry the same filters as the tab bar below them.
 * ------------------------------------------------------------ */

/* The lead: 7 columns of image, 5 of text (spec §3.2). Not an equal split — the
 * photograph is the reason the reader stops. */
.tg-insight-lead__row {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	overflow: hidden;
}

@media (min-width: 900px) {
	.tg-insight-lead__row {
		grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
		gap: var(--wp--preset--spacing--60);
		align-items: center;
	}
}

/* The card is the padding; the image runs to the card's edge on the wide layout. */
.tg-insight-lead__row .tg-insight-lead__media {
	margin: 0;
}

@media (min-width: 900px) {
	.tg-insight-lead__row .tg-insight-lead__media {
		/* Image runs to the card's left, top and bottom edges; the text column keeps its own
		 * padding (see `.tg-insight-lead__text` below) so the two halves don't glue. */
		margin: 0;
	}
}

.tg-insight-lead__row .tg-insight-lead__media :where(img) {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.tg-insight-lead__text {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	align-content: center;
	padding: var(--wp--preset--spacing--50);
}

@media (min-width: 900px) {
	.tg-insight-lead__text {
		/* Same inset on every side: a 0-padding text column butted against a photograph
		 * reads as two blocks glued together, not as one card (measured 0/0/0, then 24/0/32). */
		padding: var(--wp--preset--spacing--50) var(--wp--preset--spacing--60);
	}
}

.tg-insight-lead__row :where(.wp-block-post-title) {
	margin: 0;
	max-width: 24em;
}

.tg-insight-lead__row :where(.wp-block-post-excerpt__excerpt) {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
}

.tg-insight-lead__terms,
.tg-insight-card__terms {
	margin: 0;
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.tg-insight-lead__terms :where(a),
.tg-insight-card__terms :where(a) {
	color: var(--wp--preset--color--ink-muted);
	text-decoration: none;
}

.tg-insight-lead__terms :where(a:hover, a:focus-visible),
.tg-insight-card__terms :where(a:hover, a:focus-visible) {
	color: var(--wp--preset--color--accent-dark);
	text-decoration: underline;
}

.tg-insight-lead__meta {
	margin: var(--wp--preset--spacing--20) 0 0;
	gap: var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-insight-lead {
	margin-bottom: var(--wp--preset--spacing--70);
}

/* The rest: one card grid, same component as the archives. */
.tg-card-grid__items {
	display: grid;
	gap: var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 640px) {
	.tg-card-grid__items {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.tg-card-grid__items {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.tg-main .tg-card-grid__items > li {
	margin: 0;
	max-width: none;
}

.tg-insight-card {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--20);
	height: 100%;
	padding: var(--wp--preset--spacing--50);
}

.tg-insight-card .tg-insight-card__media {
	margin: calc(-1 * var(--wp--preset--spacing--50)) calc(-1 * var(--wp--preset--spacing--50))
		var(--wp--preset--spacing--30);
}

.tg-insight-card__media :where(img) {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

.tg-insight-card :where(.wp-block-post-title) {
	margin: 0;
	font-size: var(--wp--preset--font-size--h-4);
	line-height: 1.3;
}

.tg-insight-card :where(.wp-block-post-excerpt__excerpt) {
	margin: 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-insight-card__date {
	margin: auto 0 0;
	padding-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

/* A card's title is ink, not an accent link: every other card in the site reads that way
 * (product tiles, story cards, category tiles), and accent-on-white at this size pulled
 * the eye to the wrong element. The underline on hover is the affordance. */
.tg-insight-lead__row :where(.wp-block-post-title a),
.tg-insight-card :where(.wp-block-post-title a) {
	color: var(--wp--preset--color--ink);
	text-decoration: none;
}

.tg-insight-lead__row :where(.wp-block-post-title a:hover, .wp-block-post-title a:focus-visible),
.tg-insight-card :where(.wp-block-post-title a:hover, .wp-block-post-title a:focus-visible) {
	color: var(--wp--preset--color--ink);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* ---------------------------------------------------------------
 * Contact page (layout D, spec §5.9; rebuilt to the client's mockup in T-648).
 *
 * The client's drawing puts the form on the RIGHT and the contact information on the
 * left, which is the reverse of what §5.9 specified. The DOM order follows the drawing
 * (information, then form) and the grid places them by column, so the reading order and
 * the visual order agree and no `order` juggling is needed.
 * ------------------------------------------------------------ */

.tg-contact-grid {
	display: grid;
	gap: var(--wp--preset--spacing--70) var(--wp--preset--spacing--80);
}

/* Side by side from 1152, not 900: at 1024 the 5/7 split left the form 500px wide, and its
 * two-column field grid then gave each field 209px — narrower than the single column it had at
 * 1023. Stacked is the better reading until there is room for both columns and both fields. */
@media (min-width: 1152px) {
	.tg-contact-grid {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	}

	.tg-contact-grid > .tg-contact__aside {
		grid-column: 1;
		grid-row: 1;
	}

	/* The shortcode may be wrapped in a `<p>` or a group; the inquiry card itself is the
	 * cell, wherever it sits. */
	.tg-contact-grid :where(.tg-inquiry-card) {
		grid-column: 2;
		grid-row: 1;
	}
}

/* The inquiry card is `surface` on the `surface` section — the mockup's white card. The border
 * and the radius are what separate it from the page; no shadow (§10). */
.tg-inquiry-card {
	align-self: start;
	padding: var(--wp--preset--spacing--60);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--l);
	background: var(--wp--preset--color--surface);
}

.tg-inquiry-card__title {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--h4);
}

.tg-inquiry-card__lead {
	margin: 0 0 var(--wp--preset--spacing--50);
	max-width: 46ch;
	color: var(--wp--preset--color--ink-muted);
}

/* Two fields per row, as in the drawing: Name|Company, Country|Email, WhatsApp|Quantity.
 * `minmax(0, 1fr)` so a long country name cannot widen its own column. Only once the form is
 * wide enough to give each field a usable width — below 640px they stack. */
@media (min-width: 640px) {
	.tg-form--full .tg-field-row {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--wp--preset--spacing--40);
	}

	/* A row holding one field spans both columns, so "Target date" lines up with the fields
	 * above it instead of shrinking to half width. */
	.tg-form--full .tg-field-row > .tg-field:only-child {
		grid-column: 1 / -1;
	}
}

/* The mockup's Submit is a full-width bar. The shared form puts it inline-left; on this page
 * only, it fills the card. */
.tg-form--full .tg-field--send {
	margin-top: var(--wp--preset--spacing--30);
}

.tg-form--full .tg-field--send input[type="submit"] {
	width: 100%;
	justify-content: center;
}

/* Contact-information card (client's mockup): icon + heading, the four reach-us rows, then the
 * note. The rows reuse `.tg-contact-info` — the same component the Home band uses — so the two
 * surfaces cannot drift. */
.tg-contact-info-card {
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--l);
	background: var(--wp--preset--color--paper);
}

.tg-contact-info-card__title {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--30);
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--h4);
}

/* The circle-and-person mark the mockup puts beside the title. Drawn with CSS so it carries no
 * icon file and inherits `currentColor`. */
.tg-contact-info-card__title::before {
	content: "";
	flex: none;
	width: 28px;
	height: 28px;
	border: 1.5px solid var(--wp--preset--color--accent);
	border-radius: 50%;
	background:
		radial-gradient(circle at 50% 38%, var(--wp--preset--color--accent) 0 3.5px, transparent 4px),
		radial-gradient(circle at 50% 100%, var(--wp--preset--color--accent) 0 6.5px, transparent 7px);
}

.tg-contact-info-card__org {
	margin: 0;
	color: var(--wp--preset--color--ink);
	font-weight: 600;
}

.tg-contact-info-card .tg-contact-info {
	margin-top: var(--wp--preset--spacing--30);
}

.tg-contact-info-card__note {
	margin: var(--wp--preset--spacing--40) 0 0;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

.tg-contact-info-card__sub {
	margin: var(--wp--preset--spacing--40) 0 0;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 600;
}

/* The help band: full width under the two columns, the eight services as a 4×2 icon grid with a
 * hairline between the cells of a row (the mockup's own separators). Below 900px it is two
 * columns, and one below 640px. */
.tg-help-band {
	display: grid;
	gap: var(--wp--preset--spacing--40);
	margin-top: var(--wp--preset--spacing--70);
	padding-top: var(--wp--preset--spacing--60);
	border-top: 1px solid var(--wp--preset--color--rule);
}

@media (min-width: 900px) {
	.tg-help-band {
		grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
		align-items: start;
		gap: var(--wp--preset--spacing--60);
	}
}

.tg-help-band__title {
	margin: 0;
	font-size: var(--wp--preset--font-size--h3);
	line-height: 1.15;
}

.tg-help-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--wp--preset--spacing--40);
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 640px) {
	.tg-help-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1100px) {
	.tg-help-grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

.tg-main .tg-help-grid li {
	display: grid;
	grid-template-columns: 28px minmax(0, 1fr);
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.4;
}

/* The hairline sits between cells of a row, never before the first of a row. */
@media (min-width: 640px) {
	.tg-main .tg-help-grid li:not(:nth-child(2n + 1)) {
		padding-left: var(--wp--preset--spacing--40);
		border-left: 1px solid var(--wp--preset--color--rule);
	}
}

@media (min-width: 1100px) {
	.tg-main .tg-help-grid li:not(:nth-child(4n + 1)) {
		padding-left: var(--wp--preset--spacing--40);
		border-left: 1px solid var(--wp--preset--color--rule);
	}

	.tg-main .tg-help-grid li:nth-child(2n + 1) {
		padding-left: 0;
		border-left: 0;
	}
}

.tg-help-grid__icon {
	display: inline-flex;
	color: var(--wp--preset--color--accent);
}

.tg-help-grid__icon svg {
	width: 26px;
	height: 26px;
}

/* The bottom band: Follow on the left, the Response-time card on the right, on `paper`. */
.tg-contact-foot {
	display: grid;
	gap: var(--wp--preset--spacing--60);
	margin-top: var(--wp--preset--spacing--70);
	padding-top: var(--wp--preset--spacing--60);
	border-top: 1px solid var(--wp--preset--color--rule);
}

@media (min-width: 900px) {
	.tg-contact-foot {
		/* Even halves: the Follow row carries five labelled icons and needs ~530px to stay on one
		 * line, which a 5/7 split (460px) does not give it — TikTok wrapped onto a second row. */
		grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
		align-items: start;
	}
}

.tg-contact-foot__heading {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--h4);
}

.tg-contact-foot__lead {
	margin: 0 0 var(--wp--preset--spacing--40);
	max-width: 48ch;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

/* The coloured row, same component as the Home band (D-076). */
.tg-contact-foot__follow .tg-social {
	margin-top: var(--wp--preset--spacing--30);
}

/* `paper` + a hairline, the same treatment as the information card: the page section is already
 * `surface`, so a `surface` card on it would be invisible (measured: no edge at all). */
.tg-contact-foot__card {
	display: grid;
	grid-template-columns: 32px minmax(0, 1fr);
	gap: var(--wp--preset--spacing--40);
	align-items: start;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--l);
	background: var(--wp--preset--color--paper);
}

.tg-contact-foot__card-icon {
	display: inline-flex;
	color: var(--wp--preset--color--accent);
}

.tg-contact-foot__card-icon svg {
	width: 32px;
	height: 32px;
}

.tg-contact-foot__card-body .tg-contact-foot__lead {
	margin-bottom: 0;
	max-width: none;
}

/* Spec §5.9: the FAQ sits in its own section, no wider than 800px. It follows the bottom band,
 * which is a ruled block — without its own top space the FAQ heading sat flush against the
 * Follow icons (measured 0px). */
.tg-contact-page :where(.tg-faq) {
	max-width: 800px;
}

.tg-contact-foot + h2 {
	margin-top: var(--wp--preset--spacing--80);
}


/* ---------------------------------------------------------------
 * One form component, two variants (spec §5.9).
 *
 * Home passes `variant="quick"`, Contact `variant="full"`; both go through
 * `tg_render_inquiry_form()`. These rules are the shared component spec: 44px
 * fields, `*` for required, helper text under the field, Title Case button.
 * ------------------------------------------------------------- */

/* 44px, the height the client's Contact mockup draws and what T-647 measured (44.6). It was 52px
 * per the older spec §5.9; the file button below is sized against this number, so both move
 * together. */
.tg-form :is(input[type="text"], input[type="email"], input[type="tel"], input[type="url"], input[type="number"], input[type="date"], select),
.wpcf7-form :is(input[type="text"], input[type="email"], input[type="tel"], input[type="url"], input[type="number"], input[type="date"], select) {
	min-height: 44px;
}

/* The native select keeps its own arrow but not the OS chrome. */
.tg-form select,
.wpcf7-form select {
	appearance: none;
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
		linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: calc(100% - 20px) calc(50% + 2px), calc(100% - 15px) calc(50% + 2px);
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	padding-inline-end: 40px;
}

.tg-form select:invalid,
.wpcf7-form select:invalid {
	color: var(--wp--preset--color--ink-muted);
}

/* The required marker is one asterisk everywhere; "(required)" is gone. */
.tg-req {
	margin-inline-start: 2px;
	color: var(--wp--preset--color--accent-dark);
	font-weight: 600;
}

/* "Interested in": checkbox tags, not a multi-line list. */
.tg-field--choice .tg-field-label,
.tg-field--choice label:not(.wpcf7-list-item-label) {
	display: block;
	margin-bottom: 10px;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.tg-field--choice .wpcf7-checkbox .wpcf7-list-item,
.tg-field--choice .wpcf7-list-item {
	display: inline-block;
	margin: 0 8px 8px 0;
}

.tg-field--choice .wpcf7-list-item-label {
	display: inline-block;
	padding: 7px 14px;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 999px;
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
	cursor: pointer;
}

/* The native checkbox is the control; the label is its skin. Keep it focusable. */
.tg-field--choice input[type="checkbox"] {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: 0;
	opacity: 0;
}

.tg-field--choice input[type="checkbox"]:checked + .wpcf7-list-item-label,
.tg-field--choice .wpcf7-list-item-label:has(+ input:checked) {
	border-color: var(--wp--preset--color--accent);
	background: var(--wp--preset--color--accent-tint);
	color: var(--wp--preset--color--accent-dark);
	font-weight: 600;
}

.tg-field--choice input[type="checkbox"]:focus-visible + .wpcf7-list-item-label {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

/* The file field: once the script has built the drop area below, the native input is
 * collapsed to a 1px box that still receives the click and the keystrokes. Scoped to
 * `.tg-form--file-ready`, which only the script adds — with JS unavailable the native
 * control stays visible and the upload still works. */
.tg-form--file-ready input[type="file"],
.wpcf7-form.tg-form--file-ready input[type="file"] {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	border: 0;
	opacity: 0;
}

.tg-form .tg-file,
.wpcf7-form .tg-file {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px 12px;
	min-height: 52px;
	padding: 12px 16px;
	border: 1px dashed var(--wp--preset--color--rule-strong, var(--wp--preset--color--rule));
	border-radius: 3px;
	background: var(--wp--preset--color--surface);
}

.tg-form .tg-file__label,
.wpcf7-form .tg-file__label {
	padding: 6px 14px;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 3px;
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

.tg-form .tg-file__name,
.wpcf7-form .tg-file__name {
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
}

/* The whole drop area is the click target: it forwards the click to the real input, so
 * the field is one big touch target rather than a 1px box. */
.tg-form .tg-file,
.wpcf7-form .tg-file {
	cursor: pointer;
}

.tg-form input[type="file"]:focus-visible + .tg-file,
.wpcf7-form input[type="file"]:focus-visible + .tg-file {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

/* Honey pot: hidden with `clip-path`, not with a negative offset. `left:-9999px` is the
 * usual trick but the element's box then sits outside the viewport and every layout probe
 * (rightly) reports an element crossing the edge. */
.tg-hp {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Article table of contents (spec §5.8). Native `<details>`, no JS and no plugin — the
 * sidebar order is body-then-aside in `single.html`, so the heading list is already
 * collected by the time this renders. */
.tg-toc {
	margin-bottom: var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--surface);
}

.tg-toc__summary {
	cursor: pointer;
	color: var(--wp--preset--color--ink);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.tg-toc__summary::marker {
	color: var(--wp--preset--color--ink-muted);
}

.tg-toc__list {
	margin: var(--wp--preset--spacing--30) 0 0;
	padding: 0;
	list-style: none;
}

.tg-toc__item + .tg-toc__item {
	margin-top: var(--wp--preset--spacing--20);
}

.tg-toc__item a {
	display: block;
	color: var(--wp--preset--color--ink-muted);
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.4;
	text-decoration: none;
}

.tg-toc__item a:hover,
.tg-toc__item a:focus-visible {
	color: var(--wp--preset--color--accent-dark);
	text-decoration: underline;
	text-underline-offset: 3px;
}

/* One section, so the heading sizes come from the `document` variation. The TOC links
 * themselves are the exception the spec allows: they are navigation, not content. */
.tg-toc a:target,
.tg-toc__item a[aria-current="true"] {
	color: var(--wp--preset--color--accent-dark);
	font-weight: 600;
}

/* From 1024px the sidebar is always visible, so the disclosure is redundant there. */
@media (min-width: 1024px) {
	.tg-toc__summary {
		cursor: default;
	}

	.tg-toc__summary::marker {
		content: "";
	}
}

/* Header search (T-724) ------------------------------------------------- */

.tg-search-btn {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 8px 12px;
	border: 0;
	border-radius: var(--wp--custom--radius--s);
	background: none;
	color: var(--wp--preset--color--ink);
	font-size: 0.9375rem;
	font-weight: 500;
	cursor: pointer;
}

.tg-search-btn:hover {
	background: var(--wp--preset--color--surface);
}

/* The icon is drawn in CSS: no request, and it inherits `currentColor` so it needs no second
 * colour for the hover and dark states. */
.tg-search-btn__icon {
	position: relative;
	display: block;
	width: 14px;
	height: 14px;
	border: 2px solid currentColor;
	border-radius: 50%;
}

.tg-search-btn__icon::after {
	content: "";
	position: absolute;
	right: -5px;
	bottom: -3px;
	width: 6px;
	height: 2px;
	background: currentColor;
	transform: rotate(45deg);
	transform-origin: center;
}

.tg-search-panel {
	border-top: 1px solid var(--wp--preset--color--rule);
	border-bottom: 1px solid var(--wp--preset--color--rule);
	background: var(--wp--preset--color--surface);
}

.tg-search-panel__inner {
	padding-block: var(--wp--preset--spacing--50);
}

.tg-search-form__label {
	display: block;
	margin-bottom: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--eyebrow);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--wp--preset--color--ink-muted);
}

.tg-search-form__field {
	display: flex;
	gap: var(--wp--preset--spacing--20);
}

.tg-search-form__input {
	flex: 1 1 auto;
	min-width: 0;
	padding: 12px 16px;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	font-family: inherit;
	font-size: 1rem;
}

.tg-search-form__input:focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

.tg-search-form__submit {
	padding: 12px 24px;
	border: 1px solid var(--wp--preset--color--accent);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--surface);
	font-size: 1rem;
	font-weight: 600;
	cursor: pointer;
}

.tg-search-suggest {
	margin-top: var(--wp--preset--spacing--30);
}

.tg-search-suggest__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-search-suggest__item + .tg-search-suggest__item {
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-search-suggest__link {
	display: flex;
	gap: var(--wp--preset--spacing--30);
	align-items: center;
	padding: 10px 0;
	text-decoration: none;
}

.tg-search-suggest__link:hover .tg-search-suggest__title {
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tg-search-suggest__thumb {
	width: 44px;
	height: 44px;
	flex: 0 0 auto;
	object-fit: contain;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--wp--custom--radius--s);
	background: var(--wp--preset--color--paper);
}

.tg-search-suggest__text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

.tg-search-suggest__title {
	font-weight: 500;
}

.tg-search-suggest__meta,
.tg-search-suggest__empty {
	font-size: 0.875rem;
	color: var(--wp--preset--color--ink-muted);
}

/* Results page --------------------------------------------------------- */

.tg-search__summary {
	margin: 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink-muted);
}

.tg-search__heading {
	margin: var(--wp--preset--spacing--60) 0 var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--h4);
}

.tg-search__chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20);
	margin: 0 0 var(--wp--preset--spacing--40);
	padding: 0;
	list-style: none;
}

.tg-main .tg-search__chips > li + li {
	margin-top: 0;
}

.tg-search__chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 6px 14px;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 999px;
	font-size: 0.875rem;
	text-decoration: none;
}

.tg-search__chip.is-current {
	border-color: var(--wp--preset--color--ink);
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.tg-search__chip-count {
	font-variant-numeric: tabular-nums;
	opacity: 0.7;
}

.tg-search__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.tg-main .tg-search__list > li + li {
	margin-top: 0;
}

.tg-search__item {
	padding: var(--wp--preset--spacing--40) 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}

.tg-search__item-title {
	margin: 0;
	font-size: 1.0625rem;
}

.tg-search__item-excerpt {
	margin: 6px 0 0;
	color: var(--wp--preset--color--ink-muted);
}

.tg-search__empty {
	max-width: 42rem;
	padding-block: var(--wp--preset--spacing--60);
}

.tg-search__empty-title {
	margin: 0 0 var(--wp--preset--spacing--30);
	font-size: var(--wp--preset--font-size--h3);
}

.tg-search__empty-lead {
	margin: 0 0 var(--wp--preset--spacing--40);
	color: var(--wp--preset--color--ink-muted);
}

.tg-search__empty-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	margin: 0 0 var(--wp--preset--spacing--50);
	padding: 0;
	list-style: none;
}

.tg-main .tg-search__empty-links > li + li {
	margin-top: 0;
}

/* Icon only, at every width.
 *
 * The first attempt kept a visible "Search" label on desktop. Measured at 1440: the label plus
 * its gap took 98px out of `.tg-nav`, which left the navigation block 590px wide for ~700px of
 * items — and because that block is `items-justified-right`, the overflow spilled leftwards and
 * sat on top of the wordmark. The panel's own label carries the wording, so the button does not
 * need it; this keeps it a 44px square and the header exactly as wide as it was before.
 */
.tg-search-btn__label {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

.tg-search-btn {
	justify-content: center;
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	padding: 0;
}

/* The header cluster must not shrink below its items.
 *
 * Measured at 1440 after the search button joined it: `.tg-nav` was 979px wide for ~1003px of
 * content. The list is `items-justified-right`, so the shortfall spilled leftwards and the first
 * link landed on top of the wordmark — twice, once with the menu squeezed and once with the button
 * squeezed to 18px. The bar still had 112px of slack, so nothing has to be removed: both the
 * cluster and the menu inside it are told to keep their content width.
 *
 * Scoped to the desktop breakpoint because below 1280 `.tg-nav` is the slide-down panel and its
 * width is set by the panel rule. */
@media (min-width: 1280px) {
	.tg-nav {
		flex: 0 0 auto;
	}

	.tg-nav .wp-block-navigation {
		flex: 0 0 auto;
	}
}

/* The switcher shows the language's own name — no two-letter code, no flag.
 *
 * "EN" asked a visitor to decode an abbreviation; a flag would have named a country instead of a
 * language. The name is set slightly smaller than the navigation and given a hair more tracking so
 * "English" does not read as a fourth menu item. */
.tg-lang__name {
	font-size: 0.9375rem;
	line-height: 1.2;
	letter-spacing: 0.01em;
	white-space: nowrap;
}

.tg-lang__toggle .tg-lang__name--toggle {
	margin-inline-start: 2px;
}

/* Between the mobile breakpoint and a roomy desktop, the menu closes up.
 *
 * Measured at 1280px after the switcher started showing "English" instead of "EN": the bar's
 * content ran 37px past the right edge. The menu gap alone accounts for 168px across seven items,
 * so tightening it here is enough to fit without touching the CTA or the type sizes. */
@media (min-width: 1280px) and (max-width: 1439px) {
	/* Three classes: the two-class rule above lost to whatever WordPress prints for the block, and
	 * the computed gap stayed at 28px with the media query matching. */
	.tg-nav .tg-nav__menu .wp-block-navigation__container {
		gap: 16px;
	}
}
