/**
 * IdeaPlay theme styles.
 *
 * Loaded on the front end and inside the block editor, so the editor preview
 * matches the published page.
 *
 * @package IdeaPlay
 */

:root {
	--ip-gutter: clamp(1.5rem, 5vw, 4rem);
	--ip-maxw: 1200px;
	--ip-forest: #1a3820;
	--ip-olive: #6b7a32;
	--ip-olive-dark: #5a6828;
	--ip-cream: #eae6db;
	--ip-cream-light: #e8e4d9;
	--ip-mist: #aec9c0;
	--ip-ink: #5a5649;
	--ip-line: #d0ccc0;
	--ip-muted: #9a9587;
	/* form field fill and placeholder, from the contact page design */
	--ip-sand: #f5f3ee;
	--ip-placeholder: #b0aa9e;
	--ip-radius-card: 24px;
	--ip-radius-panel: 16px;

	/* Logo ceilings.

	   `none` lets the Site Logo block's Width control size the logo, so you
	   can drag it in the editor and the image fills its box. Any length here
	   caps the image instead — which squashes it inside a box that still
	   reserves the file's own aspect ratio, leaving empty space around it.

	   If the header height still moves when you swap logo files, the cause
	   is padding baked into the image; crop the file rather than capping it
	   here. */
	--ip-logo-max-height: none;
	--ip-logo-max-height-footer: none;
}

/* Padding and borders count inside a declared width rather than adding to it.
 *
 * Without this the theme kept producing overflow bugs: form inputs at
 * `width: 100%` plus padding ran wider than their grid column, and the search
 * field's inner wrapper spilled past the 1200px column by its own padding.
 * Setting it once removes the whole category instead of patching each case.
 *
 * Safe by direction — border-box only ever makes an element the same size or
 * smaller, so it cannot introduce the overflow it prevents.
 */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* The `hidden` attribute is only `display: none` in the UA stylesheet, so any
   class setting display — the attachment list is `display: flex` — silently
   overrides it and the element shows anyway. */
[hidden] {
	display: none !important;
}

html {
	scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		transition-duration: 0.001ms !important;
	}
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* -------------------------------------------------------------------------
 * Shared section rhythm
 * ---------------------------------------------------------------------- */

.ip-topbar,
.ip-header,
.ip-footer,
.ip-section {
	padding-left: var(--ip-gutter);
	padding-right: var(--ip-gutter);
}

/* Full-bleed backgrounds, but the content inside stays on a shared centred
   column so the logo, nav, cards and footer all line up on wide screens. */
.ip-topbar__inner,
.ip-header__inner,
.ip-footer > .wp-block-group,
.ip-section--cards > .wp-block-columns,
.ip-section--search > * {
	max-width: var(--ip-maxw);
	margin-left: auto;
	margin-right: auto;
}

/* Full-bleed escape, as a class any section can opt into.
 *
 * theme.json sets useRootPaddingAwareAlignments with a root left/right
 * padding, so every section sits inset from the viewport and its own
 * background stops short of both edges. Core's constrained layout also prints
 * margin-left/right: auto on every child, so a negative margin alone is
 * discarded and max-width has to be released too.
 *
 * Only the background moves — .ip-section keeps its own inner gutter, so the
 * content stays exactly where it was. Put this on any section that paints a
 * background of its own. A cream section hides the bug by matching the page,
 * which is why it only ever surfaces the day one turns white or forest.
 *
 * .ip-hero, .ip-contact-hero, .ip-section--teaser, .ip-products-cta and the
 * product-page panels carry their own copies of these three lines, written
 * before this class existed. New sections should use the class. */
.ip-bleed {
	max-width: none !important;
	margin-left: calc(var(--wp--style--root--padding-left, 0px) * -1) !important;
	margin-right: calc(var(--wp--style--root--padding-right, 0px) * -1) !important;
}

/* The search field needs more weight than the rule above.

   WordPress emits `.wp-container-N > * { max-width: … }` for constrained
   layouts. That has the same specificity as `.ip-section--search > *`, and
   core prints it after the theme stylesheet — so it wins the tie and
   stretches the field across the whole section. The cards escape this only
   because their selector happens to carry two classes.

   Two classes here beats core's one, so the search bar ends level with the
   cards and the Contact button above it. */
.ip-section--search .ip-search {
	max-width: var(--ip-maxw);
	margin-left: auto;
	margin-right: auto;
}

/* -------------------------------------------------------------------------
 * Above the fold
 *
 * The hexagon scroll cue should be visible on load rather than hidden below
 * the fold, so the search bar and the quote are pulled tighter.
 *
 * !important is needed because these paddings are set inline in the block
 * markup (templates/front-page.html and the matching patterns), and an inline
 * style beats a class. Tune the spacing here — it is the one place that wins.
 * ---------------------------------------------------------------------- */

.ip-section--search {
	padding-top: 0.25rem !important;
	padding-bottom: 0.75rem !important;
}

.ip-section--quote {
	padding-top: 1.25rem !important;
	padding-bottom: 2rem !important;
}

/* gap between the quote line and the hexagon below it */
.ip-section--quote > * + * {
	margin-block-start: 1rem !important;
}

/* Card height follows the viewport so the quote and scroll cue clear the fold
   on a short laptop screen, while tall screens keep the design's full 420px.
   !important because min-height is inline in the block markup. */
.ip-card {
	min-height: clamp(280px, 42vh, 420px) !important;
}

/* -------------------------------------------------------------------------
 * Contact bar above the header
 * ---------------------------------------------------------------------- */

.ip-topbar {
	font-size: 0.8125rem;
}

/* Colours are set explicitly rather than inherited: the bar sits on forest
   green, and anything that resolves against the page background instead
   lands cream-on-cream. */
.ip-topbar,
.ip-topbar .ip-topbar__item,
.ip-topbar .ip-topbar__item a {
	color: var(--ip-cream-light);
}

.ip-topbar__item {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	margin-block: 0;
	background: transparent;
}

.ip-topbar__item a {
	text-decoration: none;
	transition: opacity 0.2s ease;
}

.ip-topbar__item a:hover,
.ip-topbar__item a:focus-visible {
	opacity: 0.75;
	text-decoration: underline;
}

/* Icons as pseudo-elements so the contact lines stay plain editable
   paragraphs in the Site Editor. */
.ip-topbar__item::before {
	content: "";
	display: inline-block;
	width: 14px;
	height: 14px;
	flex: 0 0 14px;
	opacity: 0.85;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
}

.ip-topbar__item--phone::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.6.57 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .57 3.6 1 1 0 0 1-.25 1z' fill='%23e8e4d9'/%3E%3C/svg%3E");
}

.ip-topbar__item--mail::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z' stroke='%23e8e4d9' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='m2.5 6.5 9.5 7 9.5-7' stroke='%23e8e4d9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* -------------------------------------------------------------------------
 * Language switcher
 * ---------------------------------------------------------------------- */

/* Built on the core Navigation block, so the dropdown, keyboard handling and
   editor behaviour are WordPress's rather than ours. It must not stretch:
   `width: auto` keeps it to its label instead of filling the header row. */
.ip-lang {
	flex: 0 0 auto;
	width: auto;
}

.ip-lang .wp-block-navigation__container {
	flex-wrap: nowrap;
}

/* The "EN" pill.

   The border goes on the list item, not the toggle button: core renders the
   dropdown caret as a sibling of that button, so bordering the button alone
   would leave the caret stranded outside the pill. */
.ip-lang .wp-block-navigation-item.wp-block-navigation-submenu {
	display: inline-flex;
	align-items: center;
	gap: 0.375rem;
	border: 1px solid var(--ip-line);
	border-radius: 6px;
	color: var(--ip-forest);
	cursor: pointer;
	line-height: 1;
	padding: 0.5rem 0.7rem;
	transition: border-color 0.2s ease, color 0.2s ease;
}

.ip-lang .wp-block-navigation-item.wp-block-navigation-submenu:hover,
.ip-lang .wp-block-navigation-item.wp-block-navigation-submenu:focus-within {
	border-color: var(--ip-olive);
	color: var(--ip-olive);
}

/* globe, ahead of the label */
.ip-lang .wp-block-navigation-item.wp-block-navigation-submenu::before {
	content: "";
	display: inline-block;
	width: 15px;
	height: 15px;
	flex: 0 0 15px;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Ccircle cx='12' cy='12' r='9' stroke='%231a3820' stroke-width='1.8'/%3E%3Cpath d='M3 12h18M12 3a15 15 0 0 1 0 18a15 15 0 0 1 0-18z' stroke='%231a3820' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* The toggle is just text — the pill is the list item above. Its ::after
   stretches across the whole pill so the globe, the label and the caret are
   all one click target, instead of only the two letters being clickable. */
.ip-lang .wp-block-navigation-submenu__toggle {
	display: inline-flex;
	align-items: center;
	align-self: center;
	background: transparent;
	border: 0;
	color: inherit;
	cursor: pointer;
	font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	line-height: 1;
	padding: 0;
}

.ip-lang .wp-block-navigation-submenu__toggle::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

/* Centre the caret. Left to itself the SVG is inline, so it sits on the text
   baseline and hangs low next to the label; line-height:0 plus a flex box
   removes the descender gap and pins it to the middle in both states. */
.ip-lang .wp-block-navigation__submenu-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	align-self: center;
	margin: 0;
	padding: 0;
	line-height: 0;
	transform-origin: center center;
	transition: transform 0.2s ease;
}

.ip-lang .wp-block-navigation__submenu-icon svg {
	display: block;
	width: 10px;
	height: 10px;
	margin: 0;
}

/* flip the caret while the dropdown is open */
.ip-lang .wp-block-navigation-submenu:has( .wp-block-navigation-submenu__toggle[aria-expanded="true"] ) .wp-block-navigation__submenu-icon {
	transform: rotate(180deg);
}

/* the dropdown card */
.ip-lang .wp-block-navigation-item.wp-block-navigation-submenu {
	position: relative;
}

.ip-lang .wp-block-navigation__submenu-container {
	/* above the toggle's click overlay, so the options stay clickable */
	z-index: 40;
	top: calc(100% + 0.55rem);
	right: 0;
	left: auto;
	min-width: 9rem;
	padding: 0.35rem;
	background: #fff;
	border: 0;
	border-radius: 10px;
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.12);
}

.ip-lang .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	border-radius: 6px;
	color: var(--ip-forest);
	font-weight: 400;
	padding: 0.5rem 0.7rem;
	text-decoration: none;
}

.ip-lang .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
.ip-lang .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible {
	background: var(--ip-cream);
	color: var(--ip-olive);
}

/* -------------------------------------------------------------------------
 * Header
 * ---------------------------------------------------------------------- */

.ip-header {
	position: relative;
	z-index: 20;
}

/* The header row is set to nowrap in the block markup. Allowing it to wrap
   means a large logo pushes the nav onto a second line instead of crushing
   it — it still sits on one line whenever everything fits.

   The logo takes the left and an auto margin pushes everything else right,
   rather than relying on space-between across exactly two children. If the
   editor ever re-serialises the header and flattens the nesting, the row
   still reads correctly instead of scattering items across the full width. */
.ip-header__inner {
	flex-wrap: wrap;
	justify-content: flex-start;
	gap: 1.5rem;
}

.ip-header__inner > .wp-block-site-logo,
.ip-header__inner > .ip-logo {
	margin-right: auto;
}

/* Size the logo with the Site Logo block's own width control (select the
   logo in the editor, then set Width). Deliberately no width or max-height
   here: either one overrides that control, which makes dragging the width
   grow the empty space around the logo instead of the logo itself.

   To re-impose a ceiling — say the header row must never exceed 48px —
   set --ip-logo-max-height below rather than adding a rule here. */
.ip-logo img {
	display: block;
	height: auto;
	max-width: 100%;
	max-height: var(--ip-logo-max-height);
	object-fit: contain;
}

.ip-default-logo__link {
	display: block;
	line-height: 0;
	text-decoration: none;
}

.ip-logo--footer img {
	max-height: var(--ip-logo-max-height-footer);
	opacity: 0.75;
}

.ip-nav .wp-block-navigation-item__content {
	text-decoration: none;
	transition: color 0.2s ease;
}

.ip-nav .wp-block-navigation-item__content:hover,
.ip-nav .wp-block-navigation-item__content:focus {
	color: var(--ip-olive);
}

/* Match the design's md breakpoint for the mobile menu (default core is 600px). */
@media (max-width: 781px) {
	.ip-header .ip-nav .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}

	.ip-header .ip-nav .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}

	.ip-header .ip-nav .wp-block-navigation__responsive-container.is-menu-open {
		display: flex;
		padding: 2rem var(--ip-gutter);
	}
}

.wp-block-navigation__responsive-container-open svg,
.wp-block-navigation__responsive-container-close svg {
	fill: currentColor;
}

/* -------------------------------------------------------------------------
 * Hexagon "Contact" button
 * ---------------------------------------------------------------------- */

.ip-hex-button .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	white-space: nowrap;
}

.ip-hex-button .wp-block-button__link::after {
	content: "";
	display: inline-block;
	width: 20px;
	height: 20px;
	flex: 0 0 20px;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpolygon points='12,1 22,6.5 22,17.5 12,23 2,17.5 2,6.5' fill='none' stroke='%23ffffff' stroke-width='1.5'/%3E%3Cpath d='M8 12h8M13 9l3 3-3 3' stroke='%23ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* -------------------------------------------------------------------------
 * Search field
 * ---------------------------------------------------------------------- */

.ip-search .wp-block-search__inside-wrapper {
	background: #fff;
	border: 0;
	border-radius: var(--ip-radius-panel);
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.05);
	padding: 1rem 1.5rem;
}

.ip-search .wp-block-search__input {
	background: transparent;
	border: 0;
	border-radius: 0;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--body);
	font-size: 1.125rem;
	padding: 0;
	width: 100%;
}

.ip-search .wp-block-search__input:focus {
	outline: none;
}

.ip-search .wp-block-search__input::placeholder {
	color: var(--ip-muted);
	opacity: 1;
}

.ip-search .wp-block-search__inside-wrapper:focus-within {
	box-shadow: 0 0 0 2px rgba(107, 122, 50, 0.35), 0 8px 24px rgba(26, 56, 32, 0.06);
}

/* -------------------------------------------------------------------------
 * Category cards
 * ---------------------------------------------------------------------- */

.ip-cards {
	gap: 1rem;
}

.ip-card {
	/* Keeps the card readable while its photo loads, or if it fails to load. */
	background-color: #2f3d26;
	overflow: hidden;
	isolation: isolate;
	border-radius: var(--ip-radius-card);
	transition: box-shadow 0.3s ease;
}

.ip-card .wp-block-cover__image-background {
	transition: transform 0.7s ease;
}

.ip-card:hover .wp-block-cover__image-background,
.ip-card:focus-within .wp-block-cover__image-background {
	transform: scale(1.04);
}

.ip-card:hover,
.ip-card:focus-within {
	box-shadow: inset 0 0 0 3px rgba(255, 255, 255, 0.35);
}

/* Decorative ampersand watermark from the design. */
.ip-card::after {
	content: "&";
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	font-size: clamp(160px, 22vw, 260px);
	line-height: 1;
	color: rgba(0, 0, 0, 0.4);
	pointer-events: none;
	user-select: none;
	z-index: 1;
}

.ip-card > .wp-block-cover__inner-container {
	position: relative;
	z-index: 2;
	width: 100%;
}

/* The whole card is the click target, not just the two words.
   The label's link keeps its normal place in the flow — so it stays the
   accessible link text and screen readers announce it properly — while its
   ::after is stretched over the card to catch the click. */
.ip-card__label a {
	color: inherit;
	text-decoration: none;
}

.ip-card__label a::after {
	content: "";
	position: absolute;
	/* Oversized on purpose. The nearest positioned ancestor is the cover
	   block's inner container, not the card, so `inset: 0` would only cover
	   the label. The card already clips its overflow, so overshooting and
	   letting it crop gives exactly the card's area whatever sits between. */
	inset: -100vh -100vw;
	z-index: 3;
}

/* Keyboard focus only — the card already signals hover with the image zoom
   and its inset ring, so an underline there just adds noise. */
.ip-card__label a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.ip-card:focus-within {
	outline: 2px solid rgba(255, 255, 255, 0.8);
	outline-offset: -4px;
}

.ip-card__label {
	text-align: center;
	width: 100%;
	font-family: var(--wp--preset--font-family--display);
	/* The design calls for the heaviest display weight; Comfortaa ships up to
	   700, so 900 lets the browser synthesise the extra weight as in Figma. */
	font-weight: 900;
	text-transform: uppercase;
	line-height: 1.02;
	letter-spacing: -0.01em;
	margin-block: 0;
	text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* The label scales with the card, not with the viewport.

   theme.json sizes it with WordPress fluid typography, which interpolates on
   viewport width. Between roughly 800px and 1100px that goes wrong: the
   viewport is wide enough to push the label near its 3.75rem maximum while
   the three columns are still side by side, leaving each card only ~230px —
   so "CONNECT" and "EXPLORE" dropped onto a third line under the deliberate
   SHARE/CONNECT break.

   cqi is 1% of the card's content box, which is exactly the space the label
   has: the 1.75rem side padding sits on .ip-card itself. "CONNECT" is the
   widest label and measures 5.426em in Comfortaa at this weight — measured,
   not estimated, by inlining the bundled woff2 and reading the rendered
   width. That puts the hard ceiling at 18.4cqi; 17cqi leaves headroom,
   because weight 900 is synthesised from a 700 face and browsers embolden by
   different amounts.

   !important is required, not laziness: `has-card-font-size` is a WordPress
   preset class and core prints those with !important of their own.

   A browser without container query units drops the whole clamp() and falls
   back to the theme.json size, which is the current behaviour. */
.ip-card {
	container-type: inline-size;

	/* The cards are near-square in the design: 389px wide by 420px tall at the
	   1200px layout. min-height alone keeps the 420px while the width shrinks
	   with the column, so on a narrow or portrait screen they stretched into
	   tall rectangles. An aspect ratio holds the proportion at every width.

	   Both declarations need !important, and for the same reason: the cover
	   block writes `min-height:420px;aspect-ratio:unset` into the element's
	   inline style attribute. Without !important the aspect ratio here loses
	   to that `unset`, min-height wins, and the card collapses to the height
	   of its own label. An important author rule does beat a normal inline
	   style — that is the only thing that gets past it.

	   The 320px floor under 781px still applies to stacked cards. */
	aspect-ratio: 389 / 420 !important;
	min-height: 0 !important;
}

.ip-card__label {
	font-size: clamp(1.25rem, 17cqi, 3.75rem) !important;
}

/* -------------------------------------------------------------------------
 * Quote and hexagon scroll cue
 * ---------------------------------------------------------------------- */

.ip-quote {
	margin: 0 auto;
	max-width: 46rem;
}

.ip-scroll {
	display: flex;
	justify-content: center;
}

.ip-scroll__btn {
	display: inline-flex;
	line-height: 0;
	border-radius: 8px;
	transition: opacity 0.2s ease, transform 0.2s ease;
}

.ip-scroll__btn:hover,
.ip-scroll__btn:focus-visible {
	opacity: 0.8;
	transform: translateY(2px);
}

.ip-scroll__btn:focus-visible {
	outline: 2px solid var(--ip-olive);
	outline-offset: 4px;
}

/* -------------------------------------------------------------------------
 * Dark teaser
 * ---------------------------------------------------------------------- */

/* Full-bleed band.

   `main` carries the theme's root padding, so a section nested inside it has
   its background stop short of the viewport edges — the top bar escapes this
   only because it sits at root level. Negative margins matching that padding
   pull it back out, which is what WordPress's own .alignfull rule does.

   The !important is not decoration: core sets

       :where(body .is-layout-constrained) > :where(:not(.alignfull))
           { margin-left: auto !important; margin-right: auto !important; }

   on every child of a constrained layout, so plain negative margins are
   discarded. max-width has to be released too, or the section stays capped
   at the width of main's content box. The section keeps its own inner
   gutter, so only the background reaches the edges — the text stays put. */
.ip-section--teaser {
	text-align: center;
	max-width: none !important;
	margin-left: calc(var(--wp--style--root--padding-left, 0px) * -1) !important;
	margin-right: calc(var(--wp--style--root--padding-right, 0px) * -1) !important;
}

.ip-section--teaser:focus {
	outline: none;
}

.ip-teaser__title {
	margin-block: 0;
	font-weight: 900;
}

.ip-teaser__intro {
	margin-left: auto;
	margin-right: auto;
	max-width: 36rem;
	line-height: 1.65;
}

.ip-teaser__actions .wp-block-button.is-style-outline .wp-block-button__link:hover,
.ip-teaser__actions .wp-block-button.is-style-outline .wp-block-button__link:focus {
	background-color: rgba(255, 255, 255, 0.1) !important;
}

.ip-btn-catalog .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 0.55rem;
}

.ip-btn-catalog .wp-block-button__link::before {
	content: "";
	display: inline-block;
	width: 18px;
	height: 18px;
	flex: 0 0 18px;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M12 3v12m0 0-4.5-4.5M12 15l4.5-4.5M4 18v1.5A1.5 1.5 0 0 0 5.5 21h13a1.5 1.5 0 0 0 1.5-1.5V18' stroke='%231a3820' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-btn-catalog .wp-block-button__link:hover,
.ip-btn-catalog .wp-block-button__link:focus {
	background-color: #fff !important;
	color: var(--ip-forest) !important;
}

/* -------------------------------------------------------------------------
 * Feature cards
 * ---------------------------------------------------------------------- */

.ip-section--features .wp-block-column {
	display: flex;
}

.ip-feature {
	height: 100%;
	flex: 1;
}

.ip-feature::before {
	content: "";
	display: block;
	width: 12px;
	height: 12px;
	border-radius: 50%;
	margin-bottom: 1rem;
	background: var(--ip-olive);
}

.ip-feature--olive::before {
	background: #6b7a32;
}

.ip-feature--teal::before {
	background: #4d7575;
}

.ip-feature--blue::before {
	background: #7aaec9;
}

.ip-feature__title {
	margin-block: 0;
}

.ip-feature__body {
	margin-block: 0;
	line-height: 1.65;
}

/* -------------------------------------------------------------------------
 * Footer
 * ---------------------------------------------------------------------- */

.ip-footer__copy {
	margin-block: 0;
}

.ip-nav--footer .wp-block-navigation__responsive-container-open,
.ip-nav--footer .wp-block-navigation__responsive-container-close {
	display: none !important;
}

.ip-nav--footer .wp-block-navigation-item__content {
	text-decoration: none;
}

.ip-nav--footer .wp-block-navigation-item__content:hover {
	color: var(--ip-forest);
}

/* -------------------------------------------------------------------------
 * Blog / archive cards
 * ---------------------------------------------------------------------- */

.ip-post-card .wp-block-post-title a {
	text-decoration: none;
}

.ip-post-card .wp-block-post-title a:hover {
	color: var(--ip-olive);
}

/* -------------------------------------------------------------------------
 * Small screens
 * ---------------------------------------------------------------------- */

@media (max-width: 781px) {
	.ip-cards {
		gap: 1rem;
	}

	.ip-card {
		min-height: 320px !important;
	}

	.ip-card::after {
		font-size: clamp(140px, 40vw, 220px);
	}

	.ip-hex-button .wp-block-button__link {
		font-size: 0.8125rem;
		padding-left: 1rem;
		padding-right: 1rem;
	}

	.ip-footer > .wp-block-group {
		justify-content: center;
		text-align: center;
	}

	.ip-topbar__inner {
		justify-content: center;
	}

	.ip-topbar__item + .ip-topbar__item {
		margin-left: 1rem;
	}
}

@media (max-width: 480px) {
	.ip-topbar {
		font-size: 0.75rem;
	}

	.ip-topbar__inner {
		gap: 0.35rem 1rem;
	}
}

/* -------------------------------------------------------------------------
 * Contact page
 *
 * Built from the Figma Make ContactPage design: a full-bleed forest hero with
 * decorative logo cubes, then a 40/60 grid pairing a "what happens next"
 * panel with the form card.
 * ---------------------------------------------------------------------- */

/* ---- hero ---- */

.ip-contact-hero,
.ip-hero {
	position: relative;
	overflow: hidden;
	/* full-bleed, same escape from main's root padding as the teaser band */
	max-width: none !important;
	margin-left: calc(var(--wp--style--root--padding-left, 0px) * -1) !important;
	margin-right: calc(var(--wp--style--root--padding-right, 0px) * -1) !important;
}

/* Decorative cube cluster, the logo mark itself. Drawn as a background so it
   stays out of the block markup entirely — nothing for the editor to break,
   and no stray element in the content flow.

   It hangs off the inner column rather than the full-bleed section, so its
   right edge finishes level with the header's Contact button and the cards on
   the landing page, instead of bleeding past the viewport edge. */
.ip-contact-hero__inner::after,
.ip-hero__inner::after {
	content: "";
	position: absolute;
	z-index: -1;
	top: 50%;
	right: 0;
	width: min(26rem, 42%);
	aspect-ratio: 1;
	transform: translateY(-50%);
	opacity: 0.14;
	pointer-events: none;
	background-repeat: no-repeat;
	background-position: center right;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 480 480'%3E%3Cg fill='%236b7a32'%3E%3Cpath d='M314.35,399.44c-.53,4.11-3.45,4.94-7.24,4.85l-9.06-.23-60.9-.92-9.66.06c-2.69-.58-5.45-1.24-7.63-2.91l-5.19-3.95-7.61-13.06-20.83-35.98-8.14-14.21-4.05-7.44c-1.01-1.85-1.23-4.04-.9-6.08.28-1.77,1.65-3.2,3.57-3.2l34.61.02,21.34.04,6.43-.03,6.57.24h7.91c5.69,0,10.08.6,14.93,4.04,2.42,1.24,4.56,2.79,5.9,5.15l3.66,6.39,4.12,7.2,14.26,25.06,16.22,29.38c.98,1.78,1.97,3.31,1.68,5.56Z'/%3E%3Cpath d='M325.88,389.58c-1.53,2.62-5.2,5.83-8.03,5.36-2.3-.39-4.06-1.93-5.18-3.93l-3.64-6.49-21.68-39.22-11.96-21.9c-3.28-6.01-2.61-11.3-.92-17.71l4.18-7.17,27.75-47.28,8.2-13.9c1.14-1.93,3.14-3.38,5.37-3.67.59-.08,1.85.13,2.46.28,2.11.54,3.36,2.46,4.31,4.25l2.26,4.27,12.92,23.5,3,5.7,8.42,15.08,10.92,20.03c2.42,3.36,3.46,7.62,2.12,11.62-.75,2.24-1.83,4.26-3.05,6.37l-30.67,53.22-6.79,11.6Z'/%3E%3Cpath d='M177.18,314.53c-1.54-.02-3.26-1.14-4.04-2.11-1.46-1.84-2.06-4.58-1.18-6.76,1.26-3.12,3.01-5.85,4.74-8.69l4.01-6.6c.58-.96,1.92-1.08,2.97-1.36l22.84-6.2c2.07-.56,3.88-2.02,5.67-3.2,3.23-2.14,5.79-5.32,6.87-9.2l11.4-40.86c.23-.81.4-1.68,1.15-2.06l21.36.19,31.42.26,23.75.08c1.97,0,3.76.57,4.85,2.12.92,1.31,1.84,3.79.82,5.51l-40.33,68.26c-1.69,2.86-3.58,5.3-6.54,7.01-2.9,1.81-6.06,3.09-9.41,3.98h-19.95s-35.49-.07-35.49-.07l-24.91-.29Z'/%3E%3Cpath d='M269.75,217.14l-4.6,2.67c-1.71.99-3.89.65-5.54-.37-1.27-.78-2.29-2.1-2.29-3.76v-52.64s-.2-12.85-.2-12.85v-15.66c0-3.2.97-6.05,2.57-8.72,1.22-2.03,2.36-3.89,3.99-5.68l43.73-25.57,21.53-12.77,8.69-4.32c2.02-.18,3.75.29,5.02,1.83l.16,17.44.25,22.81.24,21.81.26,12.5-.07,8.64c-.03,3.74-.77,7.28-2.84,10.4l-3.99,4.95-49.41,28.99-17.51,10.3Z'/%3E%3Cpath d='M432.15,211.36c-.08,1.65-1.06,3.47-2.15,4.53-1.5,1.47-3.61,1.68-5.66,1.48l-35.88-20.96-34.22-20.19c-3.36-1.98-5.5-5.46-6.65-8.95-1.2-3.67-1.54-7.21-1.6-11.07l-.49-31.17-.25-33.34.29-10.81c.06-2.23,1.82-3.41,3.79-3.99,1.5-.44,3.1-1.23,4.68-.32l37.18,21.56,25.19,14.62,7.02,4.53c3.8,2.45,6.82,5.68,8.25,10.12l.49,27.94v10.86s.25,21.29.25,21.29l.21,14.08-.46,9.76Z'/%3E%3Cpath d='M342.52,264.02l-17.73-31.27c-2.78-3.09-6.43-5-10.59-5.49l-9.57-.54-25.97-.19-11.35-.05c-.73,0-1.59.03-2.18-.36-.22-2.23.94-4.08,2.9-5.23l53.72-31.58,4.84-2.87,7.54-4.47c4.59-2.72,9.4-4.23,14.75-4.02l3.24.34,60.03,34.25,13.75,7.91c2.37,1.36,2.97,4.85,1.91,7.11-.87,1.84-2.36,2.79-4.06,3.75l-50.1,28.31-16.21,9.22-3.41,1.9c-3.55,1.97-7.51.72-9.43-2.87l-2.06-3.85Z'/%3E%3Cpath d='M152.15,204.18c-8.05.12-15.74-2.59-20.86-8.89l-29.16-29.35-20.95-21.02c-1.11-1.12-1.75-2.65-2.2-4.08-.79-2.53.12-5.06,2.17-6.65,1.59-1.23,3.34-1.84,5.37-2.38l71.56-19.22c8.38-1.19,16.77,1.01,21.52,8.09l30.27,30.15,22.08,21.57c2.4,2.91,3.01,7.91.61,9.78-1.07.84-2.5,1.26-3.93,1.64l-76.49,20.36Z'/%3E%3Cpath d='M108.4,298.96l-7.09-7.39-12.99-13.19-26.72-26.97-5.09-5.3c-4.82-5.03-8.69-9.24-8.42-16.89.12-3.44,1.27-6.55,2.13-9.79l2.13-8,10.3-39.77,3.59-14.2,1.44-5.53,1.37-4.89c.36-1.27,1.42-2.53,2.61-3.1,2.67-1.28,5.52-.25,7.47,1.8l3.66,3.85,37.53,37.5,10.2,9.99c2.06,2.02,4.19,3.8,5.82,6.2l2.67,6.2c1.22,2.83,1.49,5.91.95,8.97l-2.1,7.74-1.86,6.82-18.76,67.32c-1.42.87-3.11.84-4.62.89-2.04.07-2.94-.91-4.22-2.25Z'/%3E%3Cpath d='M126.57,301.51c-1.84-.48-3.57-1.24-4.52-2.86-.72-1.21-.85-3-.44-4.54l20.24-75.35c1.18-2.17,1.61-4.49,3.14-6.36,1.77-2.16,4.12-3.71,6.34-5.4,2.18-1.02,4.29-1.9,6.62-2.51l12.2-3.18,39.79-10.57,22.91-6.11c1.84-.49,7.85,1.34,6.72,5.3-7.78,27.03-15.19,54-22.33,81.24-3.36,5.72-7.49,8.91-13.94,10.66l-45.08,12.18-16.7,4.46c-4.94,1.32-9.68,2.31-14.94,3.05Z'/%3E%3C/g%3E%3C/svg%3E");
}

/* The hero copy sits on the same 1200px centred column as the header, so the
   eyebrow, headline, lead and contact details all begin exactly where the logo
   above them does.

   This needs the inner wrapper rather than styling the hero's children
   directly: WordPress's constrained layout gives every direct child
   `margin-inline: auto`, so a child narrowed to a readable measure gets
   centred instead of left-aligned — which is what pushed the headline right
   while the full-width details row stayed at the far left. The wrapper takes
   the centring, and its children are plain flow content anchored left. */
.ip-contact-hero__inner,
.ip-hero__inner {
	position: relative;
	z-index: 1;
	max-width: var(--ip-maxw);
	margin-left: auto;
	margin-right: auto;
}

.ip-eyebrow {
	margin-block: 0 1rem;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
}

/* Readable measures, anchored to the left of the column rather than centred. */
.ip-contact-hero__title,
.ip-hero__title {
	margin-block: 0 1rem;
	max-width: 46rem;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(2.25rem, 5vw, 4rem);
	font-weight: 700;
	line-height: 1.1;
}

.ip-contact-hero__lead,
.ip-hero__lead {
	margin-block: 0;
	max-width: 36rem;
	line-height: 1.65;
}

.ip-contact-hero__tagline {
	margin-block: 1.5rem 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.125rem;
	font-weight: 700;
}

.ip-contact-hero__tagline-alt {
	color: var(--ip-olive);
}

/* phone / email pairs, each with a soft olive disc */
.ip-contact-chip {
	display: grid;
	grid-template-areas: "icon label" "icon value";
	grid-template-columns: auto 1fr;
	align-items: center;
	column-gap: 0.85rem;
	margin-block: 0;
}

.ip-contact-chip::before {
	content: "";
	grid-area: icon;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 50%;
	background-color: rgba(107, 122, 50, 0.25);
	background-repeat: no-repeat;
	background-position: center;
	background-size: 1.1rem;
}

.ip-contact-chip--phone::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2a1 1 0 0 1 1-.24 11.4 11.4 0 0 0 3.6.57 1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1 11.4 11.4 0 0 0 .57 3.6 1 1 0 0 1-.25 1z' fill='%23e8e4d9'/%3E%3C/svg%3E");
}

.ip-contact-chip--mail::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z' stroke='%23e8e4d9' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='m2.5 6.5 9.5 7 9.5-7' stroke='%23e8e4d9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-contact-chip__label {
	grid-area: label;
	color: var(--ip-mist);
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.ip-contact-chip a {
	grid-area: value;
	color: inherit;
	font-weight: 500;
	text-decoration: none;
}

.ip-contact-chip a:hover,
.ip-contact-chip a:focus-visible {
	text-decoration: underline;
}

/* ---- "what happens next" panel ---- */

.ip-contact-grid {
	align-items: stretch;
}

.ip-nextsteps {
	height: 100%;
}

.ip-nextsteps__title {
	margin-block: 0 0.5rem;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
}

.ip-nextsteps__intro {
	margin-block: 0 1.5rem;
	line-height: 1.65;
}

.ip-step {
	display: grid;
	grid-template-areas: "n title" "n desc";
	grid-template-columns: 2rem 1fr;
	margin-block: 0 1.25rem;
}

.ip-step:last-child {
	margin-block-end: 0;
}

.ip-step__n {
	grid-area: n;
	color: var(--ip-olive);
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	font-size: 0.875rem;
}

.ip-step__t {
	grid-area: title;
	font-weight: 600;
	font-size: 0.875rem;
}

.ip-step__d {
	grid-area: desc;
	color: var(--ip-mist);
	font-size: 0.75rem;
	line-height: 1.6;
	margin-top: 0.15rem;
}

/* ---- form card ---- */

.ip-form {
	background: #fff;
	border-radius: var(--ip-radius-panel);
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.05);
	padding: clamp(1.5rem, 4vw, 2rem);
}

.ip-form__title {
	margin-block: 0 1.25rem;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.5rem;
	font-weight: 700;
}

.ip-form__row {
	display: grid;
	gap: 1.25rem;
	margin-bottom: 1.25rem;
}

@media (min-width: 620px) {
	.ip-form__row--split {
		grid-template-columns: 1fr 1fr;
	}
}

.ip-form__field {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

.ip-form__label {
	color: var(--ip-forest);
	font-size: 0.875rem;
	font-weight: 600;
}

.ip-form__label .ip-form__req {
	color: var(--ip-olive);
}

.ip-form__label-note {
	color: var(--ip-muted);
	font-weight: 400;
}

.ip-form__input,
.ip-form__textarea {
	background: var(--ip-sand);
	border: 1px solid transparent;
	border-radius: 12px;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--body, inherit);
	font-size: 0.9375rem;
	padding: 0.8rem 1rem;
	width: 100%;
}

.ip-form__textarea {
	min-height: 9rem;
	resize: vertical;
}

.ip-form__input:focus,
.ip-form__textarea:focus {
	background: #fff;
	border-color: var(--ip-olive);
	outline: none;
}

.ip-form__input::placeholder,
.ip-form__textarea::placeholder {
	color: var(--ip-placeholder);
	opacity: 1;
}

/* ---- drag & drop attachments ---- */

.ip-drop {
	position: relative;
	border: 2px dashed var(--ip-line);
	border-radius: 12px;
	cursor: pointer;
	padding: 1.5rem;
	text-align: center;
	transition: border-color 0.2s ease, background-color 0.2s ease;
}

.ip-drop:hover,
.ip-drop:focus-within {
	border-color: rgba(107, 122, 50, 0.5);
}

.ip-drop.is-dragover {
	border-color: var(--ip-olive);
	background-color: rgba(107, 122, 50, 0.06);
}

.ip-drop__icon {
	display: block;
	width: 28px;
	height: 28px;
	margin: 0 auto 0.5rem;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12' stroke='%239a9587' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-drop__text {
	margin: 0;
	color: var(--ip-ink);
	font-size: 0.875rem;
}

.ip-drop__browse {
	color: var(--ip-olive);
	font-weight: 600;
}

/* The input covers the whole zone so clicking anywhere opens the picker, and
   the browser's own drop handling still applies. */
.ip-drop input[type="file"] {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	opacity: 0;
	cursor: pointer;
}

.ip-drop__list {
	display: flex;
	flex-direction: column;
	gap: 0.375rem;
	list-style: none;
	margin: 0.75rem 0 0;
	padding: 0;
}

.ip-drop__list li {
	align-items: center;
	background: var(--ip-sand);
	border-radius: 10px;
	display: flex;
	gap: 0.75rem;
	justify-content: space-between;
	padding: 0.5rem 0.75rem;
}

.ip-drop__name {
	color: var(--ip-forest);
	font-size: 0.75rem;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ip-drop__size {
	color: var(--ip-muted);
	flex: 0 0 auto;
	font-size: 0.75rem;
}

.ip-form .ip-form__hint {
	color: var(--ip-muted);
	font-size: 0.8125rem;
	margin: 0.5rem 0 0;
	margin-block: 0.5rem 0;
}

.ip-form__hint:empty {
	display: none;
}

.ip-form__hint.is-error {
	color: #7a2d2d;
	font-weight: 600;
}

.ip-form__consent {
	align-items: flex-start;
	display: flex;
	gap: 0.6rem;
	font-size: 0.875rem;
	color: var(--ip-ink);
	margin-bottom: 1.5rem;
}

.ip-form__consent input {
	accent-color: var(--ip-olive);
	margin-top: 0.2rem;
	flex: 0 0 auto;
	width: 1rem;
	height: 1rem;
}

/* Anti-spam honeypot — hidden from people, visible to naive bots. */
.ip-form__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.ip-form__submit {
	align-items: center;
	background: var(--ip-olive);
	border: 0;
	border-radius: 12px;
	color: #fff;
	cursor: pointer;
	display: flex;
	font-family: var(--wp--preset--font-family--display, inherit);
	font-size: 1rem;
	font-weight: 700;
	gap: 0.6rem;
	justify-content: center;
	padding: 0.9rem 2rem;
	transition: background 0.2s ease;
	width: 100%;
}

.ip-form__submit::after {
	content: "";
	width: 18px;
	height: 18px;
	flex: 0 0 18px;
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-form__submit:hover,
.ip-form__submit:focus-visible {
	background: var(--ip-olive-dark);
}

/* ---- notices and the sent confirmation ---- */

.ip-notice {
	border-radius: 12px;
	margin: 0 0 1.25rem;
	padding: 1rem 1.25rem;
}

.ip-notice--ok {
	background: #e3ecdd;
	color: #2c4a24;
}

.ip-notice--error {
	background: #f5e2e2;
	color: #7a2d2d;
}

.ip-sent {
	align-items: center;
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
	padding: clamp(2.5rem, 8vw, 5rem) 1.5rem;
	text-align: center;
}

.ip-sent__mark {
	align-items: center;
	background: rgba(107, 122, 50, 0.15);
	border-radius: 50%;
	display: flex;
	height: 5rem;
	justify-content: center;
	width: 5rem;
	background-repeat: no-repeat;
	background-position: center;
	background-size: 2.5rem;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40' fill='none'%3E%3Cpath d='M10 20l8 8 12-16' stroke='%236b7a32' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-sent__title {
	margin: 0;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.875rem;
	font-weight: 700;
}

.ip-sent__body {
	margin: 0;
	max-width: 24rem;
	color: var(--ip-ink);
}

.ip-sent__back {
	color: var(--ip-olive);
	font-weight: 600;
	text-decoration: underline;
	text-underline-offset: 4px;
}

.ip-sent__back:hover,
.ip-sent__back:focus-visible {
	color: var(--ip-forest);
}

/* On the confirmation screen the aside is no longer relevant, so the grid
   collapses to the confirmation alone. */
.ip-contact-sent .ip-contact-aside {
	display: none;
}

.ip-contact-sent .ip-contact-main {
	flex-basis: 100% !important;
}

@media (max-width: 781px) {
	.ip-contact-hero__inner::after,
	.ip-hero__inner::after {
		width: 18rem;
		opacity: 0.09;
	}

	.ip-contact-hero__details {
		gap: 1.25rem;
	}
}

/* -------------------------------------------------------------------------
 * About page
 *
 * Built from the Figma AboutPage design, with two deliberate departures from
 * it: the forest band moved from the pillars down the page up to the hero, so
 * the page opens the same way Products and Contact do — full-bleed forest with
 * the logo cubes, carried by .ip-hero / .ip-hero__inner — and the three
 * pillars are the landing page's .ip-feature cards rather than a second dark
 * band, so "Community-first" reads the same here as it does on the front page.
 * ---------------------------------------------------------------------- */

/* ---- lead photo ---- */

.ip-about-figure .wp-block-image {
	margin-block: 0;
}

/* Ratio taken from the design rather than a fixed height, so the crop holds at
   every width. No inline style on the img, so no !important needed here. */
.ip-about-figure img {
	display: block;
	width: 100%;
	aspect-ratio: 8 / 3;
	object-fit: cover;
	border-radius: var(--ip-radius-card);
}

/* ---- story, and the listen / shape / realise list beside it ---- */

/* The heading is sized against its own column, not the viewport.

   theme.json's fluid presets scale on the viewport, which is wrong inside a
   column — see the note on .ip-card__label. xx-large also tops out at 1.5rem,
   well under the design's 2.25rem. A container query gives the design's range
   from a column measure instead, and needs no preset class to override. */
.ip-about-story__text {
	container-type: inline-size;
}

.ip-about-story__title {
	margin-block: 0 1.25rem;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.5rem, 6.4cqi, 2.25rem);
	font-weight: 700;
	line-height: 1.25;
}

.ip-about-story__body {
	margin-block: 0;
	line-height: 1.75;
}

.ip-about-story__body + .ip-about-story__body {
	margin-block-start: 1rem;
}

/* Each step is its own grid so the dot sits in a column of its own and the
   label and body stack beside it — three grid items from two blocks plus the
   ::before, which is why the dot spans both rows. */
.ip-process__item {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: 1rem;
	padding-block: 1.5rem;
}

.ip-process__item + .ip-process__item {
	border-top: 1px solid var(--ip-line);
}

.ip-process__item:first-child {
	padding-top: 0;
}

.ip-process__item:last-child {
	padding-bottom: 0;
}

.ip-process__item::before {
	content: "";
	grid-column: 1;
	grid-row: 1 / span 2;
	width: 12px;
	height: 12px;
	margin-top: 0.35rem;
	border-radius: 50%;
	background: var(--ip-olive);
}

/* Same three accents the feature cards and the design's process list use. */
.ip-process__item--olive::before {
	background: #6b7a32;
}

.ip-process__item--teal::before {
	background: #4d7575;
}

.ip-process__item--blue::before {
	background: #7aaec9;
}

.ip-process__label {
	grid-column: 2;
	margin-block: 0 0.35rem;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.ip-process__body {
	grid-column: 2;
	margin-block: 0;
	line-height: 1.65;
}

/* ---- pillars ---- */

.ip-about-pillars__title {
	margin-block: 0;
	line-height: 1.2;
}

/* ---- closing call to action ---- */

.ip-about-cta__title {
	margin-block: 0;
	line-height: 1.15;
}

.ip-about-cta__intro {
	line-height: 1.7;
}

/* The design's two CTA buttons are the same size, one filled and one outlined.
   Size, radius, family and weight all come from theme.json's button element —
   only the border has to be settled here.

   The filled button gets a transparent 2px border so it matches the outlined
   one's box, and core's `is-style-outline` padding is put back to theme.json's
   own. Core prints `.wp-block-button.is-style-outline>.wp-block-button__link`
   with `calc(.667em + 2px)` to make room for its border; it is three classes
   and lands after the theme stylesheet, so the selector below needs four to
   win the tie. */
.ip-about-cta__actions .wp-block-button__link {
	border: 2px solid transparent;
}

.ip-about-cta__actions .wp-block-button.is-style-outline > .wp-block-button__link {
	padding: 0.75rem 2rem;
}

/* Outline button on cream: fills forest on hover, the inverse of the olive
   button beside it. */
.ip-btn-ghost .wp-block-button__link:hover,
.ip-btn-ghost .wp-block-button__link:focus {
	background-color: var(--ip-forest) !important;
	color: var(--ip-cream-light) !important;
}

@media (max-width: 781px) {
	/* Portrait screens get a taller crop — 8/3 leaves a letterbox strip. */
	.ip-about-figure img {
		aspect-ratio: 3 / 2;
	}

	/* The columns have stacked, so the process list needs its own top rule
	   to separate it from the story above. */
	.ip-process {
		padding-top: 2rem;
		border-top: 1px solid var(--ip-line);
	}
}

/* -------------------------------------------------------------------------
 * Editor-only tweaks
 * ---------------------------------------------------------------------- */

.editor-styles-wrapper .ip-card::after {
	z-index: 1;
}

/* -------------------------------------------------------------------------
 * Products
 *
 * The category colour reaches each card through --ip-cat, published per term
 * by ideaplay_product_cat_colors_css(). Adding a category in wp-admin and
 * picking its colour is enough — nothing here needs editing.
 * ---------------------------------------------------------------------- */

.ip-hero,
.ip-products-cta,
.ip-products-body {
	--ip-cat: var(--ip-olive);
}

/* ---- filter pills ---- */

.ip-filter {
	position: sticky;
	top: 0;
	z-index: 10;
	background: rgba(234, 230, 219, 0.95);
	backdrop-filter: blur(6px);
	border-bottom: 1px solid var(--ip-line);
	padding-left: var(--ip-gutter);
	padding-right: var(--ip-gutter);
}

.ip-filter__inner {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	max-width: var(--ip-maxw);
	margin-inline: auto;
	overflow-x: auto;
	padding-block: 0.75rem;
	scrollbar-width: none;
}

.ip-filter__inner::-webkit-scrollbar {
	display: none;
}

.ip-pill {
	--ip-cat: var(--ip-forest);
	flex: 0 0 auto;
	border: 1.5px solid #c8c4b8;
	border-radius: 999px;
	color: var(--ip-ink);
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.875rem;
	font-weight: 600;
	padding: 0.5rem 1.25rem;
	text-decoration: none;
	transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.ip-pill:hover,
.ip-pill:focus-visible {
	border-color: var(--ip-cat);
	color: var(--ip-cat);
}

.ip-pill.is-active {
	background: var(--ip-cat);
	border-color: var(--ip-cat);
	color: #fff;
}

/* The active tag pill doubles as its own clear button: tags are open-ended, so
   the filter bar lists only categories and shows the current tag as one pill
   that links back to the unfiltered archive. */

.ip-pill--tag {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
}

.ip-pill--tag:hover,
.ip-pill--tag:focus-visible {
	background: var(--ip-olive);
	border-color: var(--ip-olive);
	color: #fff;
}

.ip-pill__clear {
	font-size: 1em;
	line-height: 1;
	opacity: 0.7;
}

.ip-pill--tag:hover .ip-pill__clear,
.ip-pill--tag:focus-visible .ip-pill__clear {
	opacity: 1;
}

.ip-filter__count {
	flex: 0 0 auto;
	margin-left: auto;
	padding-left: 1rem;
	color: var(--ip-muted);
	font-size: 0.875rem;
}

/* ---- product grid ---- */

.ip-products {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 1.5rem;
}

.ip-product {
	position: relative;
	display: flex;
	flex-direction: column;
	background: #fff;
	border-radius: var(--ip-radius-card);
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.05);
	overflow: hidden;
}

.ip-product__media {
	display: block;
	height: 220px;
	overflow: hidden;
}

.ip-product__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.5s ease;
}

.ip-product:hover .ip-product__img,
.ip-product:focus-within .ip-product__img {
	transform: scale(1.06);
}

.ip-product__img--empty {
	background: var(--ip-sand);
}

.ip-product__cat,
.ip-product__tag {
	position: absolute;
	top: 0.75rem;
	border-radius: 999px;
	font-size: 0.75rem;
	padding: 0.25rem 0.75rem;
	text-decoration: none;
	transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

.ip-product__cat {
	left: 0.75rem;
	background: var(--ip-cat);
	color: #fff;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
}

.ip-product__tag {
	right: 0.75rem;
	background: rgba(255, 255, 255, 0.85);
	color: var(--ip-forest);
	font-weight: 500;
}

/* Both badges are links to their term archive; the tag one was a plain span
   until it needed to filter the grid, so it gets the same affordance. */

.ip-product__cat:hover,
.ip-product__cat:focus-visible {
	box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8);
}

.ip-product__tag:hover,
.ip-product__tag:focus-visible {
	background: #fff;
	color: var(--ip-cat);
	box-shadow: 0 1px 6px rgba(26, 56, 32, 0.18);
}

.ip-product__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: 0.5rem;
	padding: 1.25rem;
}

.ip-product__title {
	margin: 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.125rem;
	font-weight: 700;
	line-height: 1.35;
}

.ip-product__title a {
	color: var(--ip-forest);
	text-decoration: none;
}

.ip-product__title a:hover,
.ip-product__title a:focus-visible {
	color: var(--ip-olive);
}

.ip-product__desc {
	flex: 1;
	margin: 0;
	color: var(--ip-ink);
	font-size: 0.875rem;
	line-height: 1.65;
}

.ip-product__foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	border-top: 1px solid #ede9df;
	margin-top: 0.25rem;
	padding-top: 0.75rem;
}

.ip-product__more {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	color: var(--ip-olive);
	font-size: 0.875rem;
	font-weight: 600;
	text-decoration: none;
}

.ip-product__more::after {
	content: "";
	width: 14px;
	height: 14px;
	background: no-repeat center / contain
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8h10M9 4l4 4-4 4' stroke='%236b7a32' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-product__more:hover,
.ip-product__more:focus-visible {
	color: var(--ip-forest);
}

.ip-product__dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--ip-cat);
}

.ip-products__empty {
	color: var(--ip-muted);
	padding-block: 5rem;
	text-align: center;
}

/* ---- pagination ---- */

.ip-pagination {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	justify-content: center;
	margin-top: 3rem;
}

.ip-pagination .page-numbers {
	border: 1px solid var(--ip-line);
	border-radius: 8px;
	color: var(--ip-forest);
	padding: 0.5rem 0.85rem;
	text-decoration: none;
}

.ip-pagination .page-numbers:hover {
	border-color: var(--ip-olive);
	color: var(--ip-olive);
}

.ip-pagination .page-numbers.current {
	background: var(--ip-forest);
	border-color: var(--ip-forest);
	color: #fff;
}

/* ---- bottom call to action ---- */

.ip-products-cta {
	text-align: center;
	max-width: none !important;
	margin-left: calc(var(--wp--style--root--padding-left, 0px) * -1) !important;
	margin-right: calc(var(--wp--style--root--padding-right, 0px) * -1) !important;
}

.ip-products-cta__title {
	margin-block: 0 1rem;
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.75rem, 3.5vw, 2.5rem);
	font-weight: 700;
	line-height: 1.2;
}

.ip-products-cta__intro {
	margin-inline: auto;
	max-width: 30rem;
	line-height: 1.7;
}

.ip-btn-arrow .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	border-radius: 12px;
}

.ip-btn-arrow .wp-block-button__link::after {
	content: "";
	width: 16px;
	height: 16px;
	flex: 0 0 16px;
	background: no-repeat center / contain
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8h10M9 4l4 4-4 4' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

@media (max-width: 900px) {
	.ip-products {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 600px) {
	.ip-products {
		grid-template-columns: 1fr;
	}
}

/* -------------------------------------------------------------------------
 * Product gallery
 * ---------------------------------------------------------------------- */

.ip-gallery__main {
	border-radius: 20px;
	overflow: hidden;
	background: var(--ip-sand);
}

.ip-gallery__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

.ip-gallery__thumbs {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	list-style: none;
	margin: 0.75rem 0 0;
	padding: 0;
}

.ip-gallery__thumb {
	display: block;
	width: 5.5rem;
	padding: 0;
	background: none;
	border: 2px solid transparent;
	border-radius: 12px;
	cursor: pointer;
	overflow: hidden;
	transition: border-color 0.2s ease, opacity 0.2s ease;
	opacity: 0.75;
}

.ip-gallery__thumb img {
	display: block;
	width: 100%;
	height: 4rem;
	object-fit: cover;
}

.ip-gallery__thumb:hover,
.ip-gallery__thumb:focus-visible {
	opacity: 1;
}

.ip-gallery__thumb.is-current {
	border-color: var(--ip-olive);
	opacity: 1;
}

/* -------------------------------------------------------------------------
 * The product page
 *
 * Accent colour comes from --ip-cat, which the product's category sets on
 * <body>, so every rule below picks up the right green, teal or blue without
 * naming one.
 * ---------------------------------------------------------------------- */

/* Full-bleed backgrounds, the same escape the hero, teaser and bottom CTA use.

   theme.json sets useRootPaddingAwareAlignments with a root left/right
   padding, so every section sits inset from the viewport by that gutter and
   its background stops short of the edges. Core's constrained layout also
   prints margin-left/right: auto on every child, so a plain negative margin
   is discarded and max-width has to be released too.

   Only the background moves — .ip-section keeps its own inner gutter, so the
   content stays exactly where it was. Without this the white behind Related
   products stopped short of both sides; the cream sections hid the same bug
   by matching the page background. */
.ip-product-top,
.ip-product-tabs-section,
.ip-product-related {
	--ip-panel-bg: #fff;
	max-width: none !important;
	margin-left: calc(var(--wp--style--root--padding-left, 0px) * -1) !important;
	margin-right: calc(var(--wp--style--root--padding-right, 0px) * -1) !important;
}

/* ---- breadcrumb ---- */

.ip-crumbs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem;
	margin-bottom: 1.5rem;
	color: var(--ip-muted);
	font-size: 0.875rem;
}

.ip-crumbs a {
	color: var(--ip-muted);
	text-decoration: none;
	transition: color 0.2s ease;
}

.ip-crumbs a:hover,
.ip-crumbs a:focus-visible {
	color: var(--ip-forest);
}

.ip-crumbs__current {
	color: var(--ip-forest);
	font-weight: 500;
}

/* ---- two-column showcase ---- */

.ip-showcase {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 3rem;
	align-items: start;
}

.ip-showcase__media {
	position: relative;
}

/* The badge sits over the gallery's first image. The gallery wrapper is not
   positioned, so this anchors to .ip-showcase__media instead. */
.ip-showcase__badge {
	position: absolute;
	top: 1rem;
	left: 1rem;
	z-index: 2;
	background: var(--ip-cat, var(--ip-olive));
	border-radius: 999px;
	color: #fff;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.75rem;
	font-weight: 700;
	padding: 0.35rem 0.9rem;
	text-decoration: none;
	transition: box-shadow 0.2s ease;
}

.ip-showcase__badge:hover,
.ip-showcase__badge:focus-visible {
	box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8);
}

.ip-showcase__info {
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
}

/* ---- category and tag chips ---- */

.ip-showcase__terms {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.ip-term {
	border-radius: 999px;
	font-size: 0.75rem;
	padding: 0.3rem 0.8rem;
	text-decoration: none;
	transition: background-color 0.2s ease, color 0.2s ease;
}

/* A tint of the category colour rather than the colour itself — at full
   strength three of these in a row fight the title for attention.

   The flat fallback comes first: a browser without color-mix() drops that
   declaration and keeps this one, so the chip still has a background. */
.ip-term--cat {
	background: #ede9df;
	background: color-mix(in srgb, var(--ip-cat, var(--ip-olive)) 14%, #fff);
	color: var(--ip-cat, var(--ip-olive));
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
}

.ip-term--cat:hover,
.ip-term--cat:focus-visible {
	background: var(--ip-line);
	background: color-mix(in srgb, var(--ip-cat, var(--ip-olive)) 24%, #fff);
}

.ip-term--tag {
	background: #ede9df;
	color: var(--ip-ink);
	font-weight: 500;
}

.ip-term--tag:hover,
.ip-term--tag:focus-visible {
	background: var(--ip-line);
	color: var(--ip-forest);
}

/* ---- title and tagline ---- */

.ip-showcase__title {
	margin: 0;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(1.75rem, 4vw, 2.75rem);
	font-weight: 700;
	line-height: 1.15;
}

.ip-showcase__tagline {
	margin: 0;
	border-left: 4px solid var(--ip-cat, var(--ip-olive));
	padding-left: 1rem;
	color: var(--ip-ink);
	font-size: 1.125rem;
	line-height: 1.6;
}

/* ---- the spec grid beside the photos ---- */

.ip-quickspecs {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0.75rem 1.5rem;
	margin: 0;
	padding: 0.5rem 0;
}

.ip-quickspecs__item {
	min-width: 0;
}

.ip-quickspecs__label {
	margin: 0 0 0.15rem;
	color: var(--ip-muted);
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

.ip-quickspecs__value {
	margin: 0;
	color: var(--ip-forest);
	font-size: 0.9375rem;
	font-weight: 600;
}

/* ---- buttons ---- */

.ip-showcase__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	border-top: 1px solid var(--ip-line);
	padding-top: 1.25rem;
}

.ip-btn {
	display: inline-flex;
	flex: 1 1 12rem;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	border-radius: 12px;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.875rem;
	font-weight: 700;
	padding: 0.9rem 1.25rem;
	text-align: center;
	text-decoration: none;
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.ip-btn--primary {
	background: var(--ip-olive);
	color: #fff;
}

.ip-btn--primary::after {
	content: "";
	width: 16px;
	height: 16px;
	flex: 0 0 16px;
	background: no-repeat center / contain
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 8h10M9 4l4 4-4 4' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-btn--primary:hover,
.ip-btn--primary:focus-visible {
	background: var(--ip-olive-dark);
	color: #fff;
}

.ip-btn--ghost {
	border: 2px solid var(--ip-line);
	color: var(--ip-forest);
	font-weight: 600;
}

.ip-btn--ghost::before {
	content: "\2190";
	font-size: 1rem;
	line-height: 1;
}

.ip-btn--ghost:hover,
.ip-btn--ghost:focus-visible {
	border-color: var(--ip-olive);
	color: var(--ip-olive);
}

/* ---- certification badges ---- */

.ip-certs {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.ip-certs__item {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	background: rgba(77, 117, 117, 0.1);
	border-radius: 999px;
	color: #4d7575;
	font-size: 0.75rem;
	padding: 0.3rem 0.8rem;
}

/* The tick is a background image rather than an <svg> per item: the markup
   stays a plain list, which is what a screen reader wants to hear. */
.ip-certs__item::before,
.ip-ticks__item--cert::before {
	content: "";
	width: 12px;
	height: 12px;
	flex: 0 0 12px;
	background: no-repeat center / contain
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none'%3E%3Ccircle cx='6' cy='6' r='5' stroke='%234d7575' stroke-width='1.5'/%3E%3Cpath d='M3.5 6l2 2 3-3' stroke='%234d7575' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ---- tabs ---- */

.ip-tabs__bar {
	border-top: 1px solid var(--ip-line);
	border-bottom: 1px solid var(--ip-line);
	margin-bottom: 2.5rem;
}

.ip-tabs__list {
	display: flex;
	gap: 0;
	overflow-x: auto;
	scrollbar-width: none;
}

.ip-tabs__list::-webkit-scrollbar {
	display: none;
}

.ip-tabs__tab {
	flex: 0 0 auto;
	background: none;
	border: 0;
	border-bottom: 2px solid transparent;
	color: var(--ip-muted);
	cursor: pointer;
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.875rem;
	font-weight: 600;
	padding: 1rem 1.5rem;
	transition: color 0.2s ease, border-color 0.2s ease;
	white-space: nowrap;
}

.ip-tabs__tab:hover {
	color: var(--ip-forest);
}

.ip-tabs__tab.is-active {
	border-bottom-color: var(--ip-cat, var(--ip-olive));
	color: var(--ip-cat, var(--ip-olive));
}

/* Every panel is visible until the script says otherwise, so the page still
   reads end to end with JavaScript off. */
.ip-tabs__panel + .ip-tabs__panel {
	margin-top: 3rem;
}

.ip-tabs.is-enhanced .ip-tabs__panel {
	display: none;
	margin-top: 0;
}

.ip-tabs.is-enhanced .ip-tabs__panel.is-active {
	display: block;
}

.ip-panel__title {
	margin: 0 0 1.25rem;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.5rem;
	font-weight: 700;
}

/* ---- overview ---- */

.ip-overview {
	display: grid;
	grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
	gap: 2.5rem;
	align-items: start;
}

.ip-overview__text {
	color: var(--ip-ink);
	line-height: 1.75;
}

.ip-overview__text > :first-child {
	margin-top: 0;
}

.ip-overview__text > :last-child {
	margin-bottom: 0;
}

/* ---- white cards ----

   Named ip-infocard, not ip-card: .ip-card is the landing page's category
   card, and one of its rules paints a huge decorative "&" through ::after.
   Reusing the name dropped that ampersand across the product page. */

.ip-infocard {
	background: var(--ip-panel-bg, #fff);
	border-radius: var(--ip-radius-panel);
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.05);
	padding: 1.5rem;
}

.ip-infocard__title {
	margin: 0 0 1rem;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.0625rem;
	font-weight: 700;
}

.ip-ticks,
.ip-dots {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.ip-ticks__item,
.ip-dots__item {
	display: flex;
	align-items: flex-start;
	gap: 0.65rem;
	color: var(--ip-ink);
	font-size: 0.875rem;
	line-height: 1.5;
}

/* Colour and image are set separately rather than as one shorthand: a browser
   without color-mix() would otherwise drop the tick along with the tint. */
.ip-ticks__item::before {
	content: "";
	width: 16px;
	height: 16px;
	flex: 0 0 16px;
	margin-top: 0.1rem;
	border-radius: 50%;
	background-color: #ede9df;
	background-color: color-mix(in srgb, var(--ip-cat, var(--ip-olive)) 16%, #fff);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none'%3E%3Cpath d='M2 5l2.5 2.5L8 2.5' stroke='%235a5649' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
	background-position: center;
	background-repeat: no-repeat;
	background-size: 10px 10px;
}

.ip-ticks__item--cert::before {
	margin-top: 0.15rem;
	border-radius: 0;
	background-color: transparent;
	background-size: contain;
	width: 14px;
	height: 14px;
	flex-basis: 14px;
}

.ip-dots__item::before {
	content: "";
	width: 8px;
	height: 8px;
	flex: 0 0 8px;
	margin-top: 0.45rem;
	border-radius: 50%;
	background: var(--ip-cat, var(--ip-olive));
}

/* ---- specifications table ---- */

.ip-spectable {
	max-width: 44rem;
	margin: 0;
	background: var(--ip-panel-bg, #fff);
	border-radius: var(--ip-radius-panel);
	box-shadow: 0 1px 2px rgba(26, 56, 32, 0.06), 0 8px 24px rgba(26, 56, 32, 0.05);
	overflow: hidden;
}

.ip-spectable__row {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0 1rem;
	padding: 0.9rem 1.5rem;
}

/* Zebra striping by position, so adding a spec never means touching CSS. */
.ip-spectable__row:nth-child(even) {
	background: #f8f6f1;
}

.ip-spectable__label {
	flex: 0 0 11rem;
	color: var(--ip-muted);
	font-size: 0.875rem;
}

.ip-spectable__value {
	flex: 1 1 12rem;
	margin: 0;
	color: var(--ip-forest);
	font-size: 0.875rem;
	font-weight: 600;
}


/* ---- downloads ---- */

.ip-downloads {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1rem;
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: 56rem;
}

.ip-downloads__item {
	display: flex;
}

.ip-download {
	display: flex;
	flex: 1;
	align-items: center;
	gap: 0.9rem;
	background: var(--ip-panel-bg, #fff);
	border: 1px solid var(--ip-line);
	border-radius: var(--ip-radius-panel);
	padding: 1.1rem 1.25rem;
	text-decoration: none;
	transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

/* The arrow is a pseudo-element so the link's text stays a clean pair of
   spans — a screen reader reads the label and the file details, nothing else. */
.ip-download::before {
	content: "";
	width: 22px;
	height: 22px;
	flex: 0 0 22px;
	background: no-repeat center / contain
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M12 3v12M7.5 11l4.5 4.5 4.5-4.5M4.5 19.5h15' stroke='%235a5649' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.ip-download:hover,
.ip-download:focus-visible {
	border-color: var(--ip-cat, var(--ip-olive));
	box-shadow: 0 6px 18px rgba(26, 56, 32, 0.08);
	transform: translateY(-1px);
}

.ip-download__label {
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 0.9375rem;
	font-weight: 700;
	line-height: 1.3;
	min-width: 0;
}

@media (max-width: 900px) {
	.ip-downloads {
		grid-template-columns: 1fr;
	}
}

/* ---- materials and certifications ---- */

.ip-matcerts {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1.5rem;
	max-width: 48rem;
}

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

.ip-related__title {
	margin: 0 0 2rem;
	color: var(--ip-forest);
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.5rem;
	font-weight: 700;
}

/* The cards are the same component as the products grid, so they need the
   grid's own accent fallback rather than the page's product colour. */
.ip-related .ip-products {
	--ip-cat: var(--ip-olive);
}

/* ---- narrower screens ---- */

@media (max-width: 900px) {
	.ip-showcase {
		grid-template-columns: 1fr;
		gap: 2rem;
	}

	.ip-overview {
		grid-template-columns: 1fr;
		gap: 1.5rem;
	}

	.ip-matcerts {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 600px) {
	.ip-quickspecs {
		gap: 0.75rem 1rem;
	}

	.ip-tabs__tab {
		padding: 0.9rem 1rem;
	}

	.ip-spectable__row {
		padding: 0.8rem 1.15rem;
	}

	.ip-spectable__label {
		flex-basis: 100%;
	}
}

/* -------------------------------------------------------------------------
 * Search results
 * ---------------------------------------------------------------------- */

.ip-search-hero__count {
	margin-bottom: 1.5rem;
}

/* Results that are not products — pages, mostly. They keep their place in the
   relevance order rather than being split into a second list, so they share
   the grid and only lose the photo band and the badges. */
.ip-product--plain {
	justify-content: center;
	background: var(--ip-sand);
	box-shadow: none;
	border: 1px solid var(--ip-line);
}

.ip-product--plain .ip-product__body {
	padding: 1.5rem;
}

.ip-search-body .ip-products__empty {
	margin: 0;
	color: var(--ip-ink);
	font-size: 1.0625rem;
}

/* Two classes, not one: core prints `.wp-container-N > *` after the theme
   stylesheet and a single class would lose the tie. Same reason as
   `.ip-section--search .ip-search` above. */
.ip-hero__inner .ip-search--hero {
	max-width: 34rem;
}
