/*
 * IBD 2026 — only what the Customizer, GB Global Styles and GP Elements can't do.
 *
 * Colours come from GP Global Colours (--black, --dark, --orange, --orange-dark,
 * --peach, --cream, --grey, --white). Type scale lives in GP Typography.
 * Components (buttons, cards, sections…) live in GenerateBlocks Global Styles.
 */

/* Tokens
--------------------------------------------- */
:root {
	--space-xs: clamp(0.5rem, 0.4rem + 0.4vw, 0.75rem);
	--space-s: clamp(1rem, 0.85rem + 0.6vw, 1.5rem);
	--space-m: clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem);
	--space-l: clamp(2.5rem, 2rem + 2vw, 4rem);
	--space-xl: clamp(4rem, 3rem + 4vw, 8rem);
	--gutter: clamp(16px, 4vw, 60px);
	--content-width: 1440px;
	--radius: 24px;
	--radius-pill: 50px;
	--shadow: 0 4px 4px rgb(0 0 0 / 0.25);
	/* One size for every card title: service, post, team, plain cards and FAQ
	 * questions (Global Styles use it). */
	--text-card-title: clamp(1.125rem, 1rem + 0.4vw, 1.375rem);
	/* Body text, as set in GP Typography (22px desktop, 18px phones), for
	 * things that don't inherit it: buttons, the form button, quote credits. */
	--text-body: clamp(1.125rem, 1rem + 0.45vw, 1.375rem);
	/* Display text in the body font's place: testimonial quotes and the hero
	 * intro (Poppins 500). */
	--text-quote: clamp(1.25rem, 1rem + 1vw, 1.75rem);
	--wave-height: clamp(32px, 5vw, 70px);
	--ibd-header-h: 100px;
	--wave: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 70' preserveAspectRatio='none'%3E%3Cpath d='M0 53C0 53 29 90.76 570.5 31.5C1112-27.76 1440 70 1440 70H0Z'/%3E%3C/svg%3E");
}

@media (max-width: 1024px) {
	:root {
		--ibd-header-h: 80px;
	}
}

/* Type details GP Typography has no fields for. :where() keeps them at zero
 * specificity, so any class (eyebrow, footer labels…) still wins.
 * Big Poppins headings are set a little tighter; headings balance their lines
 * and paragraphs avoid a lone last word. */
:where(h1, h2) {
	letter-spacing: -0.02em;
}

:where(h3) {
	letter-spacing: -0.01em;
}

:where(h1, h2, h3, h4, h5, h6) {
	text-wrap: balance;
}

:where(p, li, blockquote, figcaption) {
	text-wrap: pretty;
}

/* Inline code (class names on the Style Guide, code in posts): readable size
 * on a soft grey chip. */
:where(code) {
	padding: 0.1em 0.35em;
	border-radius: 4px;
	background: rgb(18 18 18 / 0.07);
	font-size: 0.85em;
	text-transform: none;
	letter-spacing: 0;
}

/* Headings in two-column layouts size to the layout, not the window. A half
 * column shrinks about twice as fast as the window, so window-based sizes
 * (GP Typography) would stay big while the column narrows and break onto
 * more lines. Measured against the whole two-column grid (cqi), so they keep
 * their line count as it narrows. Full-width headings keep GP's sizes, which
 * already track the window; below 1025px these layouts stack and do too. */
@media (min-width: 1025px) {
	:where(.split, .media-text, .section-intro) {
		container-type: inline-size;
	}

	:where(.split, .media-text, .section-intro) h1 {
		font-size: clamp(2.25rem, 4.75cqi, 4rem);
	}

	:where(.split, .media-text, .section-intro) h2 {
		font-size: clamp(1.75rem, 3.6cqi, 3rem);
	}

	:where(.split, .media-text, .section-intro) h3 {
		font-size: clamp(1.375rem, 2.75cqi, 2.25rem);
	}
}

/* Beyond the page (behind iOS Safari's floating address bar at the bottom,
 * and when scrolled past either end) the browser shows the root background,
 * which was the body's white. The footer's colour, so the footer carries on
 * down; every page also opens with the dark hero. The body stays white. */
html {
	/* --dark as the footer actually looks: its background video texture
	 * (5%, a light grey) lifts it from 45 to about 54 (measured on an iPhone). */
	background-color: color-mix(in srgb, var(--dark) 95%, rgb(220 220 220));
}

/* Safari works out that colour by blending the body's background colour over
 * the root's, so a white body made it white again. The body's white is
 * painted as an image instead (same on screen), which Safari leaves out.
 * Two element selectors, to beat GP's body { background-color }. */
html body {
	background-color: transparent;
	background-image: linear-gradient(var(--white), var(--white));
}

/* Keyboard focus and in-page jumps stop below the sticky mini header (72px,
 * 64px below 1024px) rather than under it (WCAG 2.4.11). */
html {
	scroll-padding-top: calc(var(--wp-admin--admin-bar--height, 0px) + 72px + 1rem);
}

@media (max-width: 1024px) {
	html {
		scroll-padding-top: calc(var(--wp-admin--admin-bar--height, 0px) + 64px + 1rem);
	}
}

/* The <main> landmark (inc/helpers.php) takes focus from the skip link. */
.ibd-main:focus {
	outline: none;
}

/* Keyboard focus, site-wide: the orange ring the buttons, sliders and cards
 * use, for everything that doesn't set its own (menu links, the logo, footer
 * and text links), which had the browser's thin default. :where() keeps it at
 * zero specificity, so any component's own focus style still wins. */
:where(a, button, [role="button"], input, select, textarea, summary, [tabindex]:not([tabindex="-1"])):focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 3px;
}

/* …but orange is too faint for a ring on the light section backgrounds
 * (2.8:1 on cream, 2.5:1 on grey, 1.8:1 on peach; WCAG asks 3:1), so rings
 * there are black (over 11:1). The colour only, over every component's own
 * orange ring (site.css and the Global Styles), hence !important. Service
 * panels ring their inside, over the dark photo, so they keep orange. */
:is(.section-grey, .section-cream, .section-peach) :is(:focus-visible, .card-post:focus-within):not(.service-panel) {
	outline-color: var(--black) !important;
}

/* Header sits over the hero (the hero is on every template)
--------------------------------------------- */
.ibd-header {
	position: absolute;
	inset-inline: 0;
	top: var(--wp-admin--admin-bar--height, 0px); /* below the admin bar when logged in */
	z-index: 100;
}

/* Sticky mini header (site.js adds the classes)
 * Once the page has scrolled past it, the header becomes fixed (.is-stuck) and
 * slides in from above (.is-shown) as a smaller, frosted bar that stays while
 * scrolling; at the very top it returns to normal.
 * The frosted background is a pseudo-element: blur or transform on the header
 * itself would trap the mobile menu (position: fixed) inside it.
--------------------------------------------- */
.ibd-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: rgb(18 18 18 / 0.78);
	-webkit-backdrop-filter: blur(14px) saturate(1.4);
	backdrop-filter: blur(14px) saturate(1.4);
	box-shadow: 0 8px 24px rgb(0 0 0 / 0.2);
	opacity: 0;
	transition: opacity 0.3s ease;
	pointer-events: none;
}

.ibd-header > *,
.ibd-header img {
	transition: min-height 0.3s ease, width 0.3s ease;
}

.ibd-header.is-stuck {
	--ibd-header-h: 72px;
	position: fixed;
	top: var(--wp-admin--admin-bar--height, 0px);
	transform: translateY(-100%);
	transition: transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.ibd-header.is-stuck.is-shown {
	transform: none; /* not translateY(0): any transform would trap the mobile menu */
}

.ibd-header.is-stuck::before {
	opacity: 1;
}

.ibd-header.is-stuck img {
	width: clamp(120px, 10vw, 150px);
}

@media (max-width: 1024px) {
	.ibd-header.is-stuck {
		--ibd-header-h: 64px;
	}
}

@media (max-width: 600px) {
	.ibd-header.is-stuck {
		top: 0; /* the admin bar scrolls away on small screens */
	}
}

/* Submenu chevron (e.g. Services) points up, and spins to point down while its
 * menu is open. GB Pro sets aria-expanded on whichever trigger opened the
 * overlay: the link (hover) or the chevron itself (click / keyboard). */
.ibd-header .gb-submenu-toggle-icon {
	transform: rotate(180deg);
	transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); /* slight overshoot */
}

.ibd-header :is(.gb-menu-link, .gb-submenu-toggle)[aria-expanded="true"] .gb-submenu-toggle-icon {
	transform: rotate(0deg);
}

/* Link hover fades: colour and underline change quickly on hover / focus
 * and fade back more gently (GeneratePress's 0.1s both ways makes the way
 * back look instant). Links that gain an underline keep it on all the time
 * in a transparent version of its colour, so it fades rather than popping
 * (an underline switched on or off can't animate, and currentColor doesn't
 * interpolate): Global Styles footer-type, link-arrow and card-overlay
 * (titles), the footer menus' own link styles (Site Footer element), and
 * the motion toggle's text version below. */
:is(.ibd-header .gb-menu-link, .ibd-site-footer a, .link-arrow, .card-overlay :is(h2, h3, h4), .ibd-motion-toggle--text) {
	transition: color 0.35s ease, text-decoration-color 0.35s ease, background-color 0.2s ease;
}

:is(.ibd-header .gb-menu-link, .ibd-site-footer a, .link-arrow, .ibd-motion-toggle--text):is(:hover, :focus),
.card-overlay:is(:hover, :focus) :is(h2, h3, h4) {
	transition-duration: 0.15s, 0.15s, 0.2s;
}

/* Text-link arrows (Global Style link-arrow) stay with the last word.
 * A line can break just before the Global Style's inline-block arrow, so on
 * a narrow screen it could drop onto a line of its own. site.js wraps the
 * link's last word in .ibd-arrow-tail (white-space: nowrap) and the arrow,
 * drawn exactly as the Global Style draws it, moves onto that span, so the
 * two always wrap together. Without the script the Global Style's arrow is
 * left as it was. */
.link-arrow.has-arrow-tail::after {
	content: none;
}

.ibd-arrow-tail {
	white-space: nowrap;
}

.ibd-arrow-tail::after {
	content: "";
	display: inline-block;
	width: 1em;
	height: 1em;
	margin-left: 0.35em;
	vertical-align: -0.12em;
	background-color: currentColor;
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13 6l6 6-6 6'/%3E%3C/svg%3E");
	mask-size: contain;
	mask-repeat: no-repeat;
	transition: transform 0.2s;
}

.link-arrow:is(:hover, :focus) .ibd-arrow-tail::after {
	transform: translateX(4px);
}

/* Mobile menu (GB Pro full overlay below 1024px; inc/mobile-menu.php adds the
 * Services list and the contact block, site.js the Services toggle)
 * Big Poppins links on the hero's dark, a glow of brand orange, the five-colour
 * stripe along the bottom, and the items sliding in one after another.
--------------------------------------------- */
.gb-menu-container:not(.gb-menu-container--mobile) :is(.ibd-mnav__toggle, .ibd-mnav__sub, .ibd-mnav__extras) {
	display: none;
}

.ibd-header .gb-menu-container--mobile {
	top: var(--wp-admin--admin-bar--height, 0px);
	display: flex;
	flex-direction: column;
	padding: calc(var(--ibd-header-h) + var(--space-s)) var(--gutter) calc(var(--space-m) + env(safe-area-inset-bottom));
	overflow-y: auto;
	overscroll-behavior: contain;
	background:
		var(--service-stripe) bottom / 100% 6px no-repeat,
		radial-gradient(120% 55% at 100% 100%, rgb(245 105 5 / 0.2), transparent 65%),
		var(--black);
}

/* The logo stays visible above the menu. */
.ibd-header .wrap > a:first-child {
	position: relative;
	z-index: 101; /* the menu container is 100 */
}

/* A solid black bar the height of the header, pinned to the top of the open
 * menu, so links scrolling up pass under it rather than under the logo and
 * the close button. */
.ibd-header .gb-menu-container--mobile::before {
	content: "";
	position: fixed; /* out of the menu's flow; sticky can't rise into its top padding */
	top: var(--wp-admin--admin-bar--height, 0px);
	left: 0;
	right: 0;
	z-index: 1;
	height: var(--ibd-header-h);
	background: var(--black);
	pointer-events: none;
}

@media (max-width: 600px) {
	.ibd-header.is-stuck .gb-menu-container--mobile::before {
		top: 0;
	}
}

/* The close button sits exactly where the menu button was (centred in the
 * header's height, the gutter in from the edge), so opening and closing
 * swaps one icon for the other without a jump, and it stays put while the
 * menu scrolls. GB places it at 20px / 20px inside the panel. */
.ibd-header .gb-menu-container--mobile > .gb-menu-toggle {
	position: fixed;
	top: calc(var(--wp-admin--admin-bar--height, 0px) + (var(--ibd-header-h) - 44px) / 2);
	right: var(--gutter);
}

@media (max-width: 600px) {
	.ibd-header.is-stuck .gb-menu-container--mobile > .gb-menu-toggle {
		top: calc((var(--ibd-header-h) - 44px) / 2); /* the stuck header ignores the admin bar here */
	}
}

html:has(.gb-navigation--mobile.gb-navigation--open) {
	overflow: hidden;
}

/* Hiding the page's scrollbar (above) would widen the page and shift the
 * header's menu button sideways on screens with a permanent scrollbar;
 * keeping its space avoids that. No effect on phones. */
html {
	scrollbar-gutter: stable;
}

.ibd-header .gb-navigation .gb-menu-container--mobile .gb-menu {
	flex-wrap: nowrap;
	font-family: var(--gp-font--poppins);
	font-size: clamp(1.75rem, 1.2rem + 3vw, 2.5rem);
	line-height: 1.2;
}

.gb-menu-container--mobile .gb-menu > .menu-item {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	border-bottom: 1px solid rgb(255 255 255 / 0.12);
}

.gb-menu-container--mobile .gb-menu > .menu-item > .gb-menu-link {
	flex: 1;
	justify-content: flex-start;
	padding: 0.5em 0;
	font-weight: 600;
	text-decoration: none;
}

.gb-menu-container--mobile .gb-menu > .current-menu-item > .gb-menu-link {
	color: var(--orange);
}

.gb-menu-container--mobile .gb-submenu-toggle {
	display: none; /* the desktop mega menu trigger; .ibd-mnav__toggle replaces it */
}

/* Contact: a real button, not a stretched bar. */
.gb-menu-container--mobile .gb-menu > .menu-button {
	display: block;
	margin-top: var(--space-m);
	border-bottom: 0;
}

.gb-menu-container--mobile .gb-menu > .menu-button > .gb-menu-link {
	display: inline-flex;
	width: fit-content;
	margin: 0;
	padding: 0.85em 1.75em;
	font-size: 1.125rem;
}

.gb-menu-container--mobile .gb-menu > .menu-button > .gb-menu-link::after {
	content: "→";
	margin-left: 0.5em;
}

/* Services: expand the list in place. */
.ibd-mnav__toggle {
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3rem;
	margin-right: -0.5rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--white);
	cursor: pointer;
}

.ibd-mnav__toggle:is(:hover, :focus) {
	background: rgb(255 255 255 / 0.08);
	color: var(--white);
}

.ibd-mnav__toggle::before {
	content: "";
	width: 0.7rem;
	height: 0.7rem;
	margin-top: -0.35rem;
	border-right: 2.5px solid;
	border-bottom: 2.5px solid;
	transform: rotate(45deg);
	transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.ibd-mnav__toggle[aria-expanded="true"]::before {
	margin-top: 0.35rem;
	transform: rotate(225deg);
}

.ibd-mnav__sub {
	flex-basis: 100%;
	margin: 0 0 var(--space-s);
	padding: 0;
	list-style: none;
	font-size: 1rem;
	line-height: 1.4;
}

.ibd-mnav__sub[hidden] {
	display: none;
}

.ibd-mnav__sub:not([hidden]) > li {
	animation: ibd-mnav-in 0.35s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

.ibd-mnav__sub > li:nth-child(2) { animation-delay: 30ms; }
.ibd-mnav__sub > li:nth-child(3) { animation-delay: 60ms; }
.ibd-mnav__sub > li:nth-child(4) { animation-delay: 90ms; }
.ibd-mnav__sub > li:nth-child(5) { animation-delay: 120ms; }
.ibd-mnav__sub > li:nth-child(6) { animation-delay: 150ms; }

.ibd-mnav__sub a {
	display: block;
	padding: 0.6rem 0.75rem;
	margin-inline: -0.75rem;
	border-radius: 12px;
	color: var(--white);
	text-decoration: none;
}

.ibd-mnav__service .ibd-mega__title {
	display: block;
	font-family: var(--gp-font--poppins);
	font-size: 1.125rem;
	font-weight: 600;
}

.ibd-mnav__desc {
	display: block;
	margin-top: 0.15rem;
	padding-left: calc(0.6em + 0.5em * 1.125); /* in line with the title, after its dot */
	color: rgb(255 255 255 / 0.65);
	font-size: 0.9375rem;
}

.ibd-mnav__sub .ibd-mnav__service[href]:is(:hover, :focus) {
	background-color: color-mix(in srgb, var(--service) 18%, transparent);
	color: var(--white);
}

.ibd-mnav__all {
	font-weight: 600;
}

.ibd-mnav__sub .ibd-mnav__all {
	color: var(--orange);
}

.ibd-mnav__all::after {
	content: "\00a0→"; /* a no-break space, so the arrow never wraps alone */
}

/* Contact details and social links, at the bottom. */
.ibd-mnav__extras {
	margin-top: auto;
	padding-top: var(--space-l);
	color: rgb(255 255 255 / 0.75);
}

.ibd-mnav__extras p {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	margin: 0 0 1rem;
}

.ibd-mnav__extras a {
	color: inherit;
	text-decoration: none;
}

.ibd-mnav__extras a:is(:hover, :focus) {
	color: var(--orange);
}

.ibd-mnav__social svg {
	display: block;
	width: 1.5rem;
	height: 1.5rem;
}

/* Entrance: the panel fades in and the items slide up one after another. */
.gb-navigation--open .gb-menu-container--mobile {
	animation: ibd-mnav-fade 0.3s ease both;
}

.gb-navigation--open .gb-menu-container--mobile :is(.gb-menu > .menu-item, .ibd-mnav__extras) {
	animation: ibd-mnav-in 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both;
	animation-delay: 80ms;
}

.gb-navigation--open .gb-menu-container--mobile .gb-menu > .menu-item:nth-child(2) { animation-delay: 130ms; }
.gb-navigation--open .gb-menu-container--mobile .gb-menu > .menu-item:nth-child(3) { animation-delay: 180ms; }
.gb-navigation--open .gb-menu-container--mobile .gb-menu > .menu-item:nth-child(4) { animation-delay: 230ms; }
.gb-navigation--open .gb-menu-container--mobile .gb-menu > .menu-item:nth-child(5) { animation-delay: 280ms; }
.gb-navigation--open .gb-menu-container--mobile .gb-menu > .menu-item:nth-child(6) { animation-delay: 330ms; }
.gb-navigation--open .gb-menu-container--mobile .ibd-mnav__extras { animation-delay: 380ms; }

@keyframes ibd-mnav-fade {
	from { opacity: 0; }
}

@keyframes ibd-mnav-in {
	from {
		opacity: 0;
		transform: translateY(16px);
	}
}

/* Hero — background video layer
--------------------------------------------- */
.ibd-hero {
	isolation: isolate;
}

.ibd-hero__media {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

.ibd-hero__video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Section video texture: the hero loop behind coloured sections and the site
 * footer (layer injected by inc/blocks.php; deferred like the hero). Dark
 * surfaces show it like the hero but at half strength; light ones as a tonal texture of their
 * own colour. Tune per background with --section-video-opacity/-blend; opt a
 * section out with the class "ibd-no-video".
--------------------------------------------- */
:has(> .ibd-section-media) {
	isolation: isolate;
	--section-video-opacity: 0.05; /* half the hero's: quieter in the page body */
	--section-video-blend: normal;
}

/* The loop is a light, faceted image (it reads dark on the hero only because
 * it's at 10% over black), so on light colours it's multiplied in: its
 * darker facets shade the section's own colour. */
:is(.section-grey, .section-peach, .section-cream):has(> .ibd-section-media) {
	--section-video-opacity: 0.125;
	--section-video-blend: multiply;
}

.ibd-section-media {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
	opacity: var(--section-video-opacity);
	mix-blend-mode: var(--section-video-blend);
}

/* The footer is the page's last thing, against the root background (its
 * colour as it looks, html above): the texture stopped a fraction of a pixel
 * short of its bottom edge, leaving a hairline of plain --dark there. 1px
 * past the edge closes it; the footer's mask clips the overhang. */
.ibd-site-footer > .ibd-section-media {
	bottom: -1px;
}

.ibd-section__video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* When the page content opens with a dark section, the hero flows straight
 * into it (no wave, compact height) — e.g. the homepage showreel. */
body:has(.entry-content > .section-dark:first-child) .ibd-hero {
	min-height: 0;
	padding-bottom: var(--space-m);
}

body:has(.entry-content > .section-dark:first-child) .ibd-hero {
	-webkit-mask: none;
	mask: none;
}

/* …and its background video carries on down behind that section as one layer:
 * the hero's video layer reaches down by the section's height (site.js sets
 * --ibd-hero-flow) and takes over the section's bottom swoop, and the section
 * itself is see-through. */
body:has(.entry-content > .section-dark:first-child) .ibd-hero {
	overflow: visible;
}

body:has(.entry-content > .section-dark:first-child) .ibd-hero__media,
body:has(.entry-content > .section-dark:first-child) .ibd-hero::after {
	bottom: calc(-1 * var(--ibd-hero-flow, 0px));
	-webkit-mask: var(--wave-solid) top / 100% calc(100% - var(--wave-height) + 1px) no-repeat, var(--wave-cut-bottom) bottom / 100% var(--wave-height) no-repeat;
	mask: var(--wave-solid) top / 100% calc(100% - var(--wave-height) + 1px) no-repeat, var(--wave-cut-bottom) bottom / 100% var(--wave-height) no-repeat;
}

/* The hero's dark colour, reaching down under its video layer. */
body:has(.entry-content > .section-dark:first-child) .ibd-hero::after {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	z-index: -2;
	background: var(--black);
	pointer-events: none;
}

.entry-content > .section-dark:first-child {
	background-color: transparent;
}

.entry-content > .section-dark:first-child {
	padding-top: 0;
}

/* Showreel: transparent-background video, edge to edge, with no bottom
 * padding so the section's bottom swoop cuts through the video. */
.section.ibd-showreel {
	padding-left: 0;
	padding-right: 0;
	padding-bottom: 0;
}

/* …including over the swoop sections' bottom padding (.section.has-wave-bottom,
 * later in this file), which would leave a band of plain background between
 * the video and the swoop. */
.section.ibd-showreel:is(.has-wave-bottom, :has(+ .has-wave-top)) {
	padding-bottom: 0;
}

.ibd-showreel .wrap {
	max-width: none;
}

.ibd-showreel video {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
}

/* Title-only hero: let the title use the full width. */
/* Hero intro: set like the testimonial quotes. */
.ibd-hero__inner .lead {
	font-family: var(--gp-font--poppins);
	font-size: var(--text-quote);
	font-weight: 500;
	line-height: 1.4;
}

.ibd-hero__inner > :only-child {
	grid-column: 1 / -1;
}

/* Blog posts: a centred header. The title fills the width rather than
 * balancing into two even lines (pretty still avoids a lone last word), up to
 * a bit short of full on wider screens; the underline follows the title. */
.single-post .ibd-hero__inner {
	text-align: center;
}

.single-post .ibd-hero__inner h1 {
	text-wrap: pretty;
}

@media (min-width: 768px) {
	.single-post .ibd-hero__inner h1 {
		max-width: 80%;
	}
}

/* Byline under the title (inc/dynamic-tags.php): the author's team
 * headshot(s) on their own line, then "credit · date". */
.ibd-hero__byline {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--space-xs);
	margin: var(--space-s) 0 0;
	font-size: var(--text-body);
	line-height: 1.4;
}

.ibd-hero__meta {
	opacity: 0.85;
}

.ibd-hero__avatars {
	display: flex;
}

/* The post's tags, filled like the blog card tags; each links to its filter. */
.ibd-hero__tags {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.4em;
}

.ibd-hero__tag {
	display: inline-flex;
	align-items: center;
	min-height: 24px; /* WCAG 2.5.8 target size */
	padding: 0.35em 0.75em;
	border-radius: var(--radius-pill);
	background: var(--service);
	color: var(--service-ink);
	font-family: var(--gp-font--poppins);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: 1;
	text-decoration: none;
	text-transform: uppercase;
	transition: filter 0.2s ease;
}

.ibd-hero__tag:is(:hover, :focus) {
	color: var(--service-ink);
	filter: brightness(1.12);
}

.ibd-hero__tag:focus-visible {
	outline: 3px solid var(--white);
	outline-offset: 2px;
}

.ibd-hero__avatar {
	width: 3.5em;
	height: 3.5em;
	border: 2px solid var(--white);
	border-radius: 50%;
	object-fit: cover;
}

.ibd-hero__avatar + .ibd-hero__avatar {
	margin-left: -0.75em;
}

/* Single posts and job postings use GP's contained layout (Layout element
 * "Layout – Single post", 820px) — give the article breathing room since
 * global content padding is 0. */
:is(.single-post, .single-job-posting) .inside-article {
	padding: var(--space-l) var(--gutter) var(--space-xl);
}

/* Contact page: the column beside the form. A heading like the form's, the
 * contact details as lines with a small orange icon each (icons: Lucide,
 * ISC licence), and the photo at its own shape, with room between them. */
.contact-aside {
	row-gap: var(--space-m);
}

.contact-lines {
	display: grid;
	gap: var(--space-s);
	margin-bottom: var(--space-xs);
}

.contact-line {
	position: relative;
	display: flex;
	align-items: center;
	min-height: 2.25rem;
	padding-left: 3rem;
}

.contact-line > p {
	margin: 0;
}

/* The icon: white on an orange circle, centred on the detail's lines. */
.contact-line::before,
.contact-line::after {
	content: "";
	position: absolute;
	top: calc(50% - 1.125rem);
	left: 0;
	width: 2.25rem;
	height: 2.25rem;
}

.contact-line::before {
	border-radius: 50%;
	background: var(--orange);
}

.contact-line::after {
	background: var(--white);
	-webkit-mask: var(--contact-icon) center / 1.1rem no-repeat;
	mask: var(--contact-icon) center / 1.1rem no-repeat;
}

.contact-line--email {
	--contact-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Cpath d='m3 7 9 6 9-6'/%3E%3C/svg%3E");
}

.contact-line--phone {
	--contact-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");
}

.contact-line--address {
	--contact-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0z'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3C/svg%3E");
}

.contact-aside > img {
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

/* Job postings (inc/jobs.php): the Job details panel at the top (label and
 * value pairs, then the Apply button) and the Apply button again at the end. */
.ibd-job__details {
	display: grid;
	gap: var(--space-m);
	margin: 0 0 var(--space-l);
	padding: var(--space-m);
	border-radius: var(--radius);
	background: var(--cream);
}

.ibd-job__details dl {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--space-s) var(--space-m);
	margin: 0;
}

.ibd-job__detail dt {
	font-family: var(--gp-font--poppins);
	font-size: 0.8125rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--dark);
}

.ibd-job__detail dd {
	margin: 0.15em 0 0;
	font-weight: 600;
}

.ibd-job__details .ibd-job__apply,
.ibd-job__cta .ibd-job__apply {
	justify-self: start;
}

.ibd-job__cta {
	display: grid;
	gap: var(--space-s);
	justify-items: start;
	margin: var(--space-l) 0 0;
	padding-top: var(--space-m);
	border-top: 1px solid rgb(18 18 18 / 0.12);
}

.ibd-job__cta-title {
	margin: 0;
	font-family: var(--gp-font--poppins);
	font-size: var(--text-card-title);
	font-weight: 600;
}

/* Featured image at the top of a blog post (inc/helpers.php), rounded like
 * the site's other images. */
.ibd-post-image {
	margin: 0 0 var(--space-m);
}

.ibd-post-image img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--radius);
	box-shadow: 0 2px 16px rgb(18 18 18 / 0.08);
}

/* Share links on posts (inc/helpers.php ibd_share_links()), above the
 * featured image and after the article: an eyebrow label and pills like the
 * blog filters (outlined, tinted on hover, ripple), all in brand orange. */
.ibd-share {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-xs) var(--space-s);
	margin: 0 0 var(--space-m);
}

.entry-content + .ibd-share {
	margin: var(--space-l) 0 0;
	padding-top: var(--space-m);
	border-top: 1px solid rgb(18 18 18 / 0.12);
}

.ibd-share {
	--service: var(--orange);
}

.ibd-share__label.eyebrow {
	margin: 0;
}

.ibd-share__list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-xs);
	margin: 0;
	padding: 0;
	list-style: none;
}

.ibd-share__list li {
	margin: 0;
}

.ibd-share .ibd-share__link { /* .ibd-share: beats GP's button styles on Copy link */
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.55em 1.1em;
	border: 2px solid var(--service);
	border-radius: var(--radius-pill);
	background: var(--white);
	color: var(--black);
	font-family: var(--gp-font--poppins);
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.2;
	text-decoration: none;
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.ibd-share__link svg {
	width: 1em;
	height: 1em;
	flex: none;
}

.ibd-share .ibd-share__link:is(:hover, :focus) {
	background: color-mix(in srgb, var(--service) 12%, var(--white));
	color: var(--black);
}

.ibd-share__link:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 2px;
}

.ibd-share__status {
	font-size: 0.875rem;
}

/* Images, image grids and embeds in posts get the same space below as a
 * paragraph; a caption (p.meta) sits close under its image. */
.single-post .entry-content > :is(img, a:has(> img), .grid-5, .wp-block-embed) {
	margin-bottom: 1.5em;
}

.single-post .entry-content > :has(+ p.meta) {
	margin-bottom: 0.5em;
}

/* Performance: sections after the first aren't rendered until they're near the
 * screen, so their images (including CSS background images such as the
 * service cards) don't compete with the first paint. The browser remembers
 * each section's real height once rendered, so scrolling stays steady.
--------------------------------------------- */
.entry-content > .section:not(:first-child) {
	content-visibility: auto;
	contain-intrinsic-size: auto 900px;
}

/* Keyboard users (site.js adds .is-keyboard on the first Tab) get every section
 * rendered: a section's real height arriving as focus moves into it would
 * shift the focused element out of view (WCAG 2.4.11). So does an in-page link
 * (the AJAX nav plugin adds .is-anchor-scroll), so it lands where it aims. */
:is(.is-keyboard, .is-anchor-scroll) .entry-content > .section {
	content-visibility: visible;
}

/* Waves (swoops)
 * Add .has-wave-top / .has-wave-bottom to any full-bleed section. The section
 * cuts its own edge into the swoop with a mask, and its neighbour slides one
 * wave-height underneath, so whatever the neighbour is (white, a colour, a
 * background video) shows through the cut. No colours to match.
--------------------------------------------- */
:root {
	/* What a section keeps at a top swoop: everything below the curve (the
	 * brand wave turned 180°). */
	--wave-cut-top: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 70' preserveAspectRatio='none'%3E%3Cpath d='M1440 17C1440 17 1411 -20.76 869.5 38.5C328 97.76 0 0 0 0V70H1440Z'/%3E%3C/svg%3E");
	/* …and at a bottom swoop: everything above the curve. */
	--wave-cut-bottom: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 70' preserveAspectRatio='none'%3E%3Cpath d='M0 53C0 53 29 90.76 570.5 31.5C1112 -27.76 1440 70 1440 70V0H0Z'/%3E%3C/svg%3E");
	/* The opposite of --wave-cut-top (everything above that curve). */
	--wave-above-top: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 70' preserveAspectRatio='none'%3E%3Cpath d='M1440 17C1440 17 1411 -20.76 869.5 38.5C328 97.76 0 0 0 0H1440Z'/%3E%3C/svg%3E");
	--wave-solid: linear-gradient(#000 0 0);
}

.has-wave-top,
.has-wave-bottom,
.section.ibd-site-footer {
	--m-top: var(--wave-solid);
	--m-bottom: var(--wave-solid);
	position: relative;
	z-index: 1; /* above the neighbour that slides underneath */
	/* The solid middle overlaps each wave piece by 1px: butted edge to edge, a
	 * fractional wave height (it scales with the screen) left a hairline seam
	 * at each join on iPad Safari. */
	-webkit-mask: var(--m-top) top / 100% var(--wave-height) no-repeat, var(--wave-solid) center / 100% calc(100% - 2 * var(--wave-height) + 2px) no-repeat, var(--m-bottom) bottom / 100% var(--wave-height) no-repeat;
	mask: var(--m-top) top / 100% var(--wave-height) no-repeat, var(--wave-solid) center / 100% calc(100% - 2 * var(--wave-height) + 2px) no-repeat, var(--m-bottom) bottom / 100% var(--wave-height) no-repeat;
}

/* .section.has-wave-* so the padding outranks the .section Global Style,
 * which loads after this file. */
.section.has-wave-top {
	--m-top: var(--wave-cut-top);
	margin-top: calc(-1 * var(--wave-height));
	padding-top: calc(var(--space-xl) + var(--wave-height));
}

.section.has-wave-bottom {
	--m-bottom: var(--wave-cut-bottom);
	padding-bottom: calc(var(--space-xl) + var(--wave-height));
}

/* The neighbour slides under the swoop; it gets that height back as padding. */
.section:has(+ .has-wave-top) {
	padding-bottom: calc(var(--space-xl) + var(--wave-height));
}

.has-wave-bottom + .section {
	margin-top: calc(-1 * var(--wave-height));
	padding-top: calc(var(--space-xl) + var(--wave-height));
}

/* The hero's swoop: page content starting with a coloured section slides up
 * under it (white content just shows the white page through the cut). */
.entry-content > :is(.section-grey, .section-peach, .section-cream):first-child {
	margin-top: calc(-1 * var(--wave-height));
	padding-top: calc(var(--space-xl) + var(--wave-height));
}

/* The site footer always has a top swoop, cut the same way. Whatever comes
 * before it (the contact form section, or the page's last section) slides
 * underneath. */
.section.ibd-site-footer {
	--m-top: var(--wave-cut-top);
	margin-top: calc(-1 * var(--wave-height));
	padding-top: calc(var(--space-l) + var(--wave-height));
}

.ibd-footer-form,
.entry-content > .section:last-child {
	padding-bottom: calc(var(--space-xl) + var(--wave-height));
}

/* The form or footer below brings its own swoop; a second one cut into the
 * same band would leave a sliver of white page between the two curves. */
.entry-content > .has-wave-bottom:last-child,
.has-wave-bottom:has(+ .has-wave-top) {
	--m-bottom: var(--wave-solid);
}

#page:not(:has(.entry-content > .section:last-child)) {
	padding-bottom: var(--wave-height); /* posts, archives, 404… */
}

/* Two plain (white) sections in a row share one gap instead of doubling it. */
.section:not(.section-dark, .section-peach, .section-grey, .section-cream, .has-wave-bottom) + .section:not(.section-dark, .section-peach, .section-grey, .section-cream, .has-wave-top) {
	padding-top: 0;
}

/* Gravity Forms (Orbital theme)
 * Colours/sizes come from the gform_default_styles filter (inc/helpers.php);
 * this only adds what GF has no setting for. The ID-level selector matches
 * the specificity of GF's per-form variables.
--------------------------------------------- */
.gform-theme--orbital[id^="gform_wrapper_"] {
	--gf-ctrl-btn-radius: var(--radius-pill);
	--gf-ctrl-btn-shadow: var(--shadow);
	--gf-ctrl-label-font-weight-primary: 600;
	--gf-ctrl-label-font-size-req: 0.875rem; /* the small size, as fine print */
	--gf-ctrl-size-lg: 52px; /* roomier fields, like the old site */
	--gf-font-family-base: inherit;
	--gf-ctrl-font-size: 1rem; /* 16px: readable, and phones don't zoom in on focus */
	--gf-form-gap-y: var(--space-s);
	/* The submit button matches .btn (the form uses GF's large size). */
	--gf-ctrl-btn-font-size-lg: var(--text-body); /* = .btn */
	--gf-ctrl-btn-size-lg: 2.9em; /* .btn height: 1.2 line + 2 x 0.85em */
	--gf-ctrl-btn-font-weight: 600;
	--gf-ctrl-btn-padding-x-lg: 2em;
}

/* The message box: same corners as the other fields (GF gives it 8px), and a
 * little shorter than GF's "medium" 12rem (.gfield textarea.medium, hence the
 * extra classes here). */
.gform-theme--orbital[id^="gform_wrapper_"] .gform_fields .gfield textarea {
	border-radius: var(--gf-ctrl-radius);
	block-size: 9rem;
	min-block-size: 9rem;
}

/* Contact page form (form 2): a message box twice as tall on desktop. */
@media (min-width: 1025px) {
	.gform-theme--orbital#gform_wrapper_2 .gform_fields .gfield textarea {
		block-size: 18rem;
		min-block-size: 18rem;
	}
}

/* Footer contact form: heading on the left, the form beside it on wide screens
 * (.split stacks them at 1024px and below). */
@media (min-width: 1025px) {
	.ibd-footer-form .split {
		grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
		align-items: start;
	}
}

/* Page transition: brand wave wipe
 * A panel that looks like the hero (dark, with the subtle background video at
 * 10%) sweeps over the page while Swup swaps it underneath (html.is-animating),
 * then carries on off screen (html.is-rendering). --wipe-direction sets which way. Its swooped ends are a
 * clip-path outline, so the video runs right into the waves. It covers the header
 * too, so the whole screen is revealed together. site.js paints the hero video's
 * current frame into the panel while it moves.
 * Reduced-motion users get no animation (Swup A11y plugin).
--------------------------------------------- */
.ibd-wipe {
	--wipe-direction: 1; /* 1 = bottom to top, -1 = top to bottom */
	--wipe-offset: calc(var(--wipe-direction) * (100% - var(--wave-height))); /* fully off screen */
	--wipe-duration: 0.45s;
	--wipe-ease: cubic-bezier(0.7, 0, 0.3, 1);
	position: fixed;
	top: calc(-1 * var(--wave-height));
	left: 0;
	right: 0;
	/* Taller than the screen by --wipe-overhang, to reach under iOS 26 Safari's
	 * floating address bar (see html.is-changing .ibd-wipe below). The offsets
	 * are % of the panel's own height, so it still starts and ends off screen. */
	--wipe-overhang: calc(env(safe-area-inset-bottom, 0px) + 8rem);
	height: calc(100lvh + 2 * var(--wave-height) + var(--wipe-overhang));
	scroll-margin-top: var(--wave-height); /* the wave height in px, for site.js (top changes during a visit) */
	z-index: 1000; /* over the header (100), under the admin bar */
	overflow: hidden;
	background: var(--black);
	visibility: hidden;
	pointer-events: none;
	transform: translateY(var(--wipe-offset));
	transition: transform var(--wipe-duration) var(--wipe-ease);
	/* Swooped ends: one clip-path outline drawn by site.js at the exact panel
	 * size (a single shape, so there are no seams between pieces). */
}

.ibd-wipe__media {
	position: absolute;
	inset: 0;
	/* Fully opaque: the canvas paints the hero's background and the (tinted) video
	 * at the hero's 10% itself (site.js). */
	/* Counter-move exactly opposite the panel (same %, duration and easing),
	 * so the video stays fixed on screen while the swooped field slides
	 * across it — like background-attachment: fixed. */
	transform: translateY(calc(-1 * var(--wipe-offset)));
	transition: transform var(--wipe-duration) var(--wipe-ease);
}

/* Canvas painted by site.js with the hero video's current frame. */
.ibd-wipe__media canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

html.is-changing .ibd-wipe {
	visibility: visible;
}

/* During a visit the panel is part of the page, at the current scroll
 * position (--wipe-top, set by site.js, which moves it with the page when the
 * new page scrolls to the top), not fixed to the screen: iOS 26 Safari draws
 * the page under its floating address bar but cuts fixed layers off at the
 * bar's top edge, so a fixed panel left the bottom of the old page showing.
 * Fixed while idle, so the hidden panel never lengthens the page. */
html.is-changing .ibd-wipe {
	position: absolute;
	top: calc(var(--wipe-top, 0px) - var(--wave-height));
}

html.is-animating :is(.ibd-wipe, .ibd-wipe__media) {
	transform: translateY(0);
}

html.is-rendering:not(.is-animating) .ibd-wipe {
	transform: translateY(calc(-1 * var(--wipe-offset)));
}

html.is-rendering:not(.is-animating) .ibd-wipe__media {
	transform: translateY(var(--wipe-offset));
}

/* Reset to the bottom instantly once the visit is over. */
html:not(.is-changing) :is(.ibd-wipe, .ibd-wipe__media) {
	transition: none;
}

/* Card tilt (.card-overlay / .card-post / .card-plain in GB Global Styles)
 * site.js sets these as the pointer approaches a card: --lift (0 far away, 1
 * on the card) drives the shadow (and the service cards' colour bar);
 * --tilt-x/-y the lean. Registered so the cards can transition them
 * smoothly, and so they default to flat.
--------------------------------------------- */
@property --lift {
	syntax: "<number>";
	inherits: true;
	initial-value: 0;
}

@property --tilt-x {
	syntax: "<angle>";
	inherits: true;
	initial-value: 0deg;
}

@property --tilt-y {
	syntax: "<angle>";
	inherits: true;
	initial-value: 0deg;
}

/* The 3D transform only while a card tilts or settles back (site.js
 * .is-tilting). A 3D transform, even a flat one, makes the browser draw the
 * card as its own layer and resample it at its fractional position, which
 * softens it on standard (1x) screens; at rest a card is drawn normally. */
:is(a.card-overlay, .card-service, article.card-post, article.card-team, div.card-plain, img.img-rounded):not(.is-tilting) {
	transform: none;
}

/* …and that layer lands on whole screen pixels, while a card at rest is drawn
 * at its exact (often fractional) spot, so its text jumped a pixel as a tilt
 * began and ended. site.js nudges every card onto whole pixels (--snap-x/-y),
 * so it draws the same either way. `translate` sits outside the tilt
 * transform, so it applies at rest and while tilting alike. A tilting card
 * inside a swoop section also turns the section's mask into a layer, so the
 * swoop sections are nudged onto whole pixels too (--section-snap). Not
 * inherited, so nothing inside picks up its parent's nudge. */
@property --snap-x {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --snap-y {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

@property --section-snap {
	syntax: "<length>";
	inherits: false;
	initial-value: 0px;
}

/* Each card also stays its own layer at all times (will-change), so a tilt
 * starting or stopping doesn't switch how it's drawn: that switch still
 * jumped the text a pixel inside swoop sections. On whole pixels, the
 * layer is as sharp as the page. */
:is(a.card-overlay, .card-service, article.card-post, article.card-team, div.card-plain, img.img-rounded) {
	translate: var(--snap-x) var(--snap-y);
	will-change: transform;
}

:is(.has-wave-top, .has-wave-bottom) {
	translate: 0 var(--section-snap);
}

/* Tilting cards keep one steady shadow: the white cards' resting shadow,
 * which no longer deepens with --lift on hover. Overrides the --lift
 * shadows in the Global Styles (element + class wins). */
:is(a.card-overlay, .card-service, article.card-post, article.card-team, div.card-plain, img.img-rounded) {
	box-shadow: 0 2px 16px rgb(18 18 18 / 0.08);
}

/* A portrait photo in a split or media-text block (add the class
 * "img-tall-mobile"): once the columns stack, the image is otherwise only
 * 340px tall at full width and loses the top and bottom of the photo (Deb at
 * the podium lost the top of her head). It gets a 4:5 shape there instead. */
@media (max-width: 1024px) {
	:is(.split, .media-text) > img.img-tall-mobile {
		height: auto;
		min-height: 0;
		aspect-ratio: 4 / 5;
		contain: none;
	}
}

/* A graphic (transparent PNG, e.g. "The IBD Approach") in a media-text block:
 * shown whole at its own shape, centred against the text, instead of being
 * cropped to fill the column like a photo. Add the class "img-graphic". */
.media-text > img.img-graphic {
	align-self: center;
	justify-self: center;
	max-width: min(100%, 400px);
	height: auto;
	min-height: 0;
	object-fit: contain;
	contain: none;
}

/* Side by side, the graphic's column is the graphic's width and it sits on
 * the content's left edge (centred in a 5fr column it left wide empty space
 * to its left and a large gutter before the text). */
@media (min-width: 1025px) {
	.media-text:has(> img.img-graphic:first-child) {
		grid-template-columns: minmax(0, 400px) minmax(0, 1fr);
	}

	.media-text > img.img-graphic:first-child {
		justify-self: start;
	}
}

/* Plain cards with a link (.link-arrow, e.g. "Paid Media & Digital Ads →"):
 * the whole card is the link's target, as the blog cards are. The link's
 * ::before stretches over the card (its ::after is the arrow), so it stays one
 * link for keyboards and screen readers, hovering anywhere shows the link's
 * hover, and keyboard focus rings the whole card. */
.card-plain:has(> .link-arrow) {
	position: relative;
}

.card-plain > .link-arrow::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: var(--radius);
}

.card-plain:has(> .link-arrow:focus-visible) {
	outline: 3px solid var(--orange);
	outline-offset: 3px;
}

.card-plain > .link-arrow:focus-visible {
	outline: none;
}

/* FAQ sections: the heading centred over the centred column of questions. */
.container-narrow:has(> .accordion-faq) > h2 {
	text-align: center;
}

/* Photo cards that turn plain below desktop (Careers benefits 5): give the
 * section the class plain-below-desktop. On tablets and phones its heading
 * lines up left and its card-service cards drop their photos and take
 * card-plain's look, one per row. The section's background is left alone. */
@media (max-width: 1024px) {
	.plain-below-desktop .stack {
		text-align: left;
		margin-left: 0;
	}

	.plain-below-desktop .grid-3 > .card-service {
		flex-basis: 100%;
		padding: var(--space-m);
	}

	.plain-below-desktop .grid-3 > .card-service > img {
		display: none;
	}

	.plain-below-desktop .grid-3 > .card-service > * {
		margin: 0;
	}

	.plain-below-desktop .grid-3 > .card-service > :is(h3, h4)::after {
		content: "";
		display: block;
		width: 2.5rem;
		height: 3px;
		margin-top: 0.6em;
		background-color: var(--service);
	}
}

/* Wide photos (Careers benefits 6): give a grid of card-service cards the
 * class cards-16x9 for 16:9 photos instead of square ones. */
.cards-16x9 > .card-service > img {
	aspect-ratio: 16 / 9;
}

/* Tier cards (plans and pricing, e.g. WordPress Maintenance): the eyebrow
 * carries the accent line, so the title drops its own. */
.card-plain.card-tier > :is(h3, h4)::after {
	content: none;
}

/* Solid colour cards (About, Core Values 4): the card in its --service
 * colour with its --service-ink text, set on the card like the solid panels;
 * the title's accent line takes the text colour. */
.card-plain.card-solid {
	background-color: var(--service);
	color: var(--service-ink);
}

.card-plain.card-solid > :is(h3, h4)::after {
	background-color: currentColor;
}

/* A grid-2 that goes four across on desktop (WordPress Maintenance,
 * "What every plan includes"). */
@media (min-width: 1025px) {
	.grid-2.grid-4-desktop {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

/* Rows of plain or photo cards: a short last row is centred rather than left
 * hanging. Same columns and gaps as the grid-3 Global Style, as a wrapping
 * flex row. */
.grid-3:has(> :is(.card-plain, .card-service)) {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
}

.grid-3:has(> :is(.card-plain, .card-service)) > * {
	flex: 0 0 calc((100% - 2 * var(--space-m)) / 3);
	min-width: 0;
}

@media (max-width: 1024px) {
	.grid-3:has(> :is(.card-plain, .card-service)) > * {
		flex-basis: calc((100% - var(--space-m)) / 2);
	}
}

@media (max-width: 767px) {
	.grid-3:has(> :is(.card-plain, .card-service)) > * {
		flex-basis: 100%;
	}
}

/* Team and pet cards (About): exactly the columns and card sizes of their
 * grid (as many 240px+ cards as fit: repeat(auto-fill, minmax(240px, 1fr))
 * with a --space-m gap), but a short last row is centred. Grid can't centre
 * a part row, so the loop wraps instead; each container query is the width
 * at which the grid gains a column (--space-m written out, as container
 * queries can't read custom properties). The scrolling team row on Home
 * (.ibd-marquee) is left alone. */
[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	container-type: inline-size;
}

[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
	flex: 0 0 100%;
	min-width: 0;
}

@container (min-width: calc(2 * 240px + 1 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 1 * var(--space-m)) / 2);
	}
}

@container (min-width: calc(3 * 240px + 2 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 2 * var(--space-m)) / 3);
	}
}

@container (min-width: calc(4 * 240px + 3 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 3 * var(--space-m)) / 4);
	}
}

@container (min-width: calc(5 * 240px + 4 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 4 * var(--space-m)) / 5);
	}
}

@container (min-width: calc(6 * 240px + 5 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"]:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 5 * var(--space-m)) / 6);
	}
}

/* .team-max-4 on the looper: at most four across (the Office Pets). */
@container (min-width: calc(5 * 240px + 4 * clamp(1.5rem, 1.2rem + 1.2vw, 2.5rem))) {
	[class*="gb-looper-"].team-max-4:has(> .card-team):not(.ibd-marquee) > * {
		flex-basis: calc((100% - 3 * var(--space-m)) / 4);
	}
}

/* Service colours (inc/services.php sets --service per page, link and post card)
 * Brand orange everywhere else.
--------------------------------------------- */
:root {
	--service: var(--orange);
	--service-ink: var(--white);
	--service-text: var(--orange-dark); /* small text on light backgrounds (4.5:1) */
	--service-stripe: linear-gradient(90deg, var(--svc-strategy) 0 20%, var(--svc-video) 20% 40%, var(--svc-social) 40% 60%, var(--svc-ads) 60% 80%, var(--svc-web) 80%);
}

/* 1. Hero: a service-coloured edge along the swoop: the wave 8px higher
 * (the site's accent weight), filled all the way down; the hero's own cut
 * trims it to a band. The footer's five-colour stripe (8.) shares it. */
:root {
	--wave-edge: 8px;
	--wave-edge-mask: var(--wave) top / 100% var(--wave-height) no-repeat, linear-gradient(#000 0 0) bottom / 100% calc(var(--wave-edge) + 2px) no-repeat;
}

.has-service .ibd-hero::before {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: -1px;
	z-index: 1;
	height: calc(var(--wave-height) + var(--wave-edge));
	background: var(--service);
	-webkit-mask: var(--wave-edge-mask);
	mask: var(--wave-edge-mask);
	pointer-events: none;
}

/* 2. …and the video's highlights pick up the colour: a colour layer multiplied
 * over the footage (dark stays dark, light turns to the colour). site.js does
 * the same in the page-transition wipe, so keep the two in step. */
.has-service .ibd-hero__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background: color-mix(in srgb, var(--service) 80%, var(--white));
	mix-blend-mode: multiply;
	pointer-events: none;
}

/* 2b. Peach sections (video texture multiplied in) take a light pastel of the
 * service colour (a quarter colour, the rest white): on a service's own
 * pages, or where a section is given a service class itself ("service-web"
 * etc., as on the Services page). */
.has-service .section-peach,
.section-peach:is(.service-video, .service-social, .service-web, .service-ads, .service-strategy) {
	background-color: color-mix(in srgb, var(--service) 25%, var(--white));
}

/* 3. Buttons hover to the service colour where one applies. */
.btn:not(.btn-light):is(:hover, :focus-visible) {
	background-color: var(--btn-hover, var(--dark));
	color: var(--btn-hover-ink, var(--white));
}

/* 5. Mega menu: a colour dot per service, and a tint of it on hover.
 * The dot (0.6em) grows 1.4× on hover. It's one radial gradient whose
 * radius animates (--dot-size, registered so it can), drawn in a 0.92em box
 * (room for the grown 0.84em dot and its springy overshoot) whose negative
 * margins keep the text exactly where a 0.6em dot put it. Not transform: scale(), which
 * Safari briefly applied to the whole title; not a box-shadow ring, which
 * left a faint seam between the dot's edge and the ring's. */
@property --dot-size {
	syntax: "<number>";
	inherits: false;
	initial-value: 0.652;
}

.ibd-mega__title::before {
	--dot-size: 0.652; /* × 0.92em = 0.6em */
	content: "";
	display: inline-block;
	width: 0.92em;
	height: 0.92em;
	margin: -0.16em 0.34em -0.16em -0.16em;
	background: radial-gradient(circle closest-side, var(--service) calc(var(--dot-size) * 100% - 1px), transparent calc(var(--dot-size) * 100%));
	vertical-align: 0.05em;
	transition: --dot-size 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* The tint comes in quickly and fades back gently, like the links' hover
 * colours (GeneratePress's 0.1s both ways reads as a snap). */
.ibd-mega__item {
	transition: background-color 0.35s ease, color 0.35s ease;
}

.ibd-mega__item[href]:is(:hover, :focus) {
	background-color: color-mix(in srgb, var(--service) 16%, var(--white));
	transition-duration: 0.15s;
}

/* In the desktop menu the tint is a layer behind the item's content that
 * fades its opacity, rather than the item's own background fading: Safari
 * repainting an item whose background and dot were both animating drew the
 * whole item about a third larger for a frame or two. Same colour and
 * timing. (The phone menu's items have their own tint, below.) */
.gb-overlay .ibd-mega__item {
	position: relative;
	isolation: isolate;
	transition: none;
}

.gb-overlay .ibd-mega__item[href]:is(:hover, :focus) {
	background-color: transparent;
}

.gb-overlay .ibd-mega__item::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	background-color: color-mix(in srgb, var(--service) 16%, var(--white));
	opacity: 0;
	transition: opacity 0.35s ease;
	pointer-events: none;
}

.gb-overlay .ibd-mega__item[href]:is(:hover, :focus)::after {
	opacity: 1;
	transition-duration: 0.15s;
}

.ibd-mega__item:is(:hover, :focus) .ibd-mega__title::before {
	--dot-size: 0.913; /* × 0.92em = 0.84em */
}

/* 6. Service cards: a colour bar along the bottom that rises as the pointer
 * approaches (driven by the same --lift as the tilt). */
a.card-overlay::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: -1;
	height: calc(8px + 45% * var(--lift));
	background: linear-gradient(to top, var(--service) 0 8px, color-mix(in srgb, var(--service) 60%, transparent) 8px, transparent);
	pointer-events: none;
}

/* 7. Blog cards: their service / topic tags (inc/services.php ibd_post_tags():
 * all of them, the filtered one first) and a colour edge in the first one's colour. */
.card-post > img {
	border-bottom: 8px solid var(--accent-bar, transparent);
}

.card-tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4em;
	margin: 0;
	padding: 0;
	list-style: none;
}

.card-tags li {
	margin: 0;
	padding: 0.35em 0.75em;
	border-radius: var(--radius-pill);
	background: var(--service);
	color: var(--service-ink);
	font-family: var(--gp-font--poppins);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	line-height: 1;
	text-transform: uppercase;
}

/* 8. A five-colour stripe just under the site footer's top swoop: everything
 * above the curve shifted down by --wave-edge (plus a solid band at the top);
 * the footer's own cut trims it to a band along the curve. */
.section.ibd-site-footer::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	z-index: 0;
	height: calc(var(--wave-height) + var(--wave-edge));
	background: var(--service-stripe);
	-webkit-mask: var(--wave-solid) top / 100% var(--wave-edge) no-repeat, var(--wave-above-top) 0 var(--wave-edge) / 100% var(--wave-height) no-repeat;
	mask: var(--wave-solid) top / 100% var(--wave-edge) no-repeat, var(--wave-above-top) 0 var(--wave-edge) / 100% var(--wave-height) no-repeat;
	pointer-events: none;
}

/* 9. A wavy line in the service colour along a section's top swoop, in place
 * of a coloured background (Services page: has-wave-top has-wave-line
 * service-…). Drawn as the footer's stripe is: everything above the curve
 * shifted down by --wave-edge, which the section's own cut trims to a band. */
.has-wave-top.has-wave-line::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	top: 0;
	z-index: 0;
	height: calc(var(--wave-height) + var(--wave-edge));
	background: var(--service);
	-webkit-mask: var(--wave-solid) top / 100% var(--wave-edge) no-repeat, var(--wave-above-top) 0 var(--wave-edge) / 100% var(--wave-height) no-repeat;
	mask: var(--wave-solid) top / 100% var(--wave-edge) no-repeat, var(--wave-above-top) 0 var(--wave-edge) / 100% var(--wave-height) no-repeat;
	pointer-events: none;
}

/* Marquee: a constantly scrolling row (e.g. "About Deb & Our Team" on Home)
 * Give a Query block (or any element) the class ibd-marquee-viewport and its
 * Looper (or inner element) the class ibd-marquee. site.js duplicates the
 * items for a seamless loop and moves the row at a steady ~72px/s, like the
 * old site, easing to a stop on hover / keyboard focus, and can be dragged /
 * flung. Add ibd-marquee--step to the track to have it step forward one card
 * at a time instead (Careers benefits). Reduced-motion visitors get a
 * swipeable row.
--------------------------------------------- */
body {
	overflow-x: clip; /* full-bleed rows never cause a sideways scroll */
}

.ibd-marquee-viewport {
	/* Edge to edge of the visible page: 100vw includes a permanent scrollbar
	 * (site.js --scrollbar), which put the row 7.5px past each side, so the
	 * first card could never sit fully in view. */
	margin-inline: calc(50% - (100vw - var(--scrollbar, 0px)) / 2);
	margin-block: calc(-1 * var(--space-s)) calc(-1 * var(--space-m));
	padding-block: var(--space-s) var(--space-m); /* room for card shadows and tilt */
	overflow: hidden;
	cursor: grab;
	touch-action: pan-y; /* sideways swipes drag the row; vertical ones scroll the page */
}

.ibd-marquee-viewport.is-dragging,
.ibd-marquee-viewport.is-dragging * {
	cursor: grabbing !important;
	user-select: none;
}

.ibd-marquee img {
	-webkit-user-drag: none;
}

.ibd-marquee {
	display: flex;
	width: max-content;
	will-change: transform;
}

.ibd-marquee > * {
	flex: 0 0 clamp(220px, 22vw, 340px);
	margin-right: 20px; /* a margin, not a gap, so the two halves are equal */
}

/* Photo strip (Careers): the same height, each photo at its own width. */
.ibd-marquee--photos > img {
	flex: none;
	width: auto;
	height: clamp(220px, 24vw, 340px);
	object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
	.ibd-marquee-viewport {
		overflow-x: auto;
	}
}

/* Motion toggle (inc/blocks.php ibd_motion_toggle(), site.js): one pause for
 * all the site's motion, on the hero, the showreel, the marquee and in the
 * footer. Pause icon while playing, play icon while paused. Reduced-motion
 * visitors have no motion to pause, so no toggle.
--------------------------------------------- */
.ibd-motion-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5em;
	padding: 0;
	border: 0;
	font: inherit;
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.ibd-motion-toggle svg {
	width: 1.25rem;
	height: 1.25rem;
	flex: none;
}

.ibd-motion-toggle__play,
.motion-paused .ibd-motion-toggle__pause {
	display: none;
}

.motion-paused .ibd-motion-toggle__play {
	display: block;
}

.ibd-motion-toggle:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 2px;
}

/* Round, over video. */
.ibd-motion-toggle--overlay {
	position: absolute;
	right: 1rem;
	bottom: 1rem;
	z-index: 2;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: 50%;
	background: rgb(18 18 18 / 0.55);
	color: var(--white);
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
}

.ibd-motion-toggle--overlay:is(:hover, :focus) {
	background: rgb(18 18 18 / 0.85);
	color: var(--white);
}

/* In the bottom corner of the hero / showreel, above the swoop. */
.ibd-motion-toggle--corner {
	right: var(--gutter);
	bottom: calc(var(--wave-height) + var(--space-s));
	background: rgb(255 255 255 / 0.1);
}

.ibd-motion-toggle--corner:is(:hover, :focus) {
	background: rgb(255 255 255 / 0.2);
}

/* …and out of sight until it has keyboard focus (it stays in the tab order).
 * Always shown while paused, so it's clear how to resume. Mouse and touch
 * visitors pause with the footer's "Pause animations" link. */
.ibd-motion-toggle--corner {
	opacity: 0;
	pointer-events: none; /* no surprise pauses from clicks on the hidden button */
	transition: opacity 0.3s ease, background-color 0.2s ease;
}

.ibd-motion-toggle--corner:focus-visible,
.motion-paused .ibd-motion-toggle--corner {
	opacity: 1;
	pointer-events: auto;
}

/* Text, in the footer's fine print: styled like the fine print's links
 * ("Privacy Policy", .footer-type a). Two classes, to beat GP's
 * button:not(.menu-toggle) size and weight. */
.footer-fineprint .ibd-motion-toggle--text {
	gap: 0.4em;
	font-size: inherit;
	font-weight: 400;
	line-height: inherit;
	background: none;
	color: var(--white);
	text-decoration: underline;
	text-decoration-color: color-mix(in srgb, var(--orange) 0%, transparent);
	text-underline-offset: 0.2em;
}

.footer-fineprint .ibd-motion-toggle--text:is(:hover, :focus) {
	background: none;
	color: var(--orange);
	text-decoration-color: var(--orange);
}

.ibd-motion-toggle--text svg {
	width: 0.9em;
	height: 0.9em;
}

/* The copyright line sits on the row's centre line with the icons and the
 * toggle (.footer-type p's bottom margin was lifting it). */
.footer-type .footer-fineprint p {
	margin-bottom: 0;
}

/* The footer's bottom bar (Site Footer element, .ibd-footer-bottom): the
 * social icons in the true centre on wider screens (three columns, so the
 * longer copyright line on the left doesn't push them off centre), and
 * everything centred and stacked on phones, the copyright and the privacy
 * links on lines of their own. Two classes, to beat the cluster Global
 * Style's display: flex. */
.footer-fineprint.ibd-footer-bottom {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: var(--space-s);
}

.footer-fineprint.ibd-footer-bottom > :last-child {
	justify-self: end;
}

@media (max-width: 767px) {
	.footer-fineprint.ibd-footer-bottom {
		grid-template-columns: minmax(0, 1fr);
		justify-items: center;
		text-align: center;
	}

	.footer-fineprint.ibd-footer-bottom > :last-child {
		justify-self: center;
	}

	.footer-fineprint.ibd-footer-bottom :is(.ibd-footer-copy, .ibd-footer-legal) {
		display: block;
	}

	.footer-fineprint.ibd-footer-bottom .ibd-footer-sep {
		display: none;
	}

	.footer-fineprint.ibd-footer-bottom .ibd-footer-legal {
		margin-top: 0.35em;
	}
}

@media (prefers-reduced-motion: reduce) {
	.ibd-motion-toggle {
		display: none !important;
	}
}

/* Button and card ripple (added by assets/js/site.js on click)
--------------------------------------------- */
.has-ripple {
	position: relative;
	overflow: hidden;
	isolation: isolate;
}

.ibd-ripple {
	position: absolute;
	z-index: -1;
	border-radius: 50%;
	background: currentColor;
	opacity: 0.3;
	transform: scale(0);
	pointer-events: none;
	animation: ibd-ripple 0.6s ease-out forwards;
}

/* On cards: the card's service colour, over the photo and text. */
.ibd-ripple--card {
	z-index: 3;
	background: var(--service, var(--orange));
	opacity: 0.35;
	animation-duration: 0.7s;
}

@keyframes ibd-ripple {
	to {
		transform: scale(1);
		opacity: 0;
	}
}

/* Accordion headings (inc/blocks.php): each question's <h3> is only there for
 * screen readers, so it takes no space and passes nothing on (the base h3
 * letter-spacing and balanced wrapping would otherwise reach the question).
 * Below it, the GB and Global Style rules that select a toggle as a direct
 * child of its item, repeated for the toggle inside the heading.
--------------------------------------------- */
.gb-accordion__item > .ibd-accordion-heading {
	display: block;
	margin: 0;
	padding: 0;
	font: inherit;
	letter-spacing: inherit;
	text-transform: inherit;
	text-wrap: inherit;
	color: inherit;
}

/* GB accordion-style.css */
.gb-accordion__item:not(.gb-accordion__item-open) > .ibd-accordion-heading > .gb-accordion__toggle .gb-accordion__toggle-icon-close,
.gb-accordion__item.gb-accordion__item-open > .ibd-accordion-heading > .gb-accordion__toggle .gb-accordion__toggle-icon-open {
	display: none;
}

/* Global Style accordion-faq */
.accordion-faq .gb-accordion__item:is(:not(.gb-accordion__item-open), .is-filling):has(> .ibd-accordion-heading > .gb-accordion__toggle:is(:hover, :focus-visible)) {
	background-color: color-mix(in srgb, var(--service) 6%, var(--white));
}

.accordion-faq .gb-accordion__item.gb-accordion__item-open > .ibd-accordion-heading > .gb-accordion__toggle .gb-accordion__toggle-icon-open {
	display: flex;
	transform: rotate(180deg);
}

/* Global Style accordion-services */
.accordion-services .gb-accordion__item-open > .ibd-accordion-heading > .gb-accordion__toggle > .gb-text {
	color: var(--orange);
}

.accordion-services .gb-accordion__item-open > .ibd-accordion-heading > .gb-accordion__toggle > .gb-text::before {
	left: calc(100% - 6px);
	right: 0;
	transition: right 0.375s ease-out, left 0.375s ease-in 0.375s;
}

/* FAQ ripple (opening a question): a full-strength fill in the open tint
 * that stays until the box's own tint takes over (site.js "FAQ questions
 * ripple"). */
.accordion-faq .gb-accordion__item > .ibd-ripple--fill {
	background: color-mix(in srgb, var(--service) 16%, var(--white));
	opacity: 1;
	animation-name: ibd-ripple-fill;
	animation-duration: 0.4s;
}

@keyframes ibd-ripple-fill {
	to {
		transform: scale(1);
	}
}

/* Logo wall (site.js "Logo wall"): four slots, one swapping every few seconds
with a blur dissolve.
--------------------------------------------- */
.logo-wall.is-rotating {
	grid-template-columns: repeat(4, minmax(0, 1fr));
}

.logo-wall__slot {
	display: grid;
	place-items: center;
	width: 100%;
	height: 88px;
}

.logo-wall__slot > * {
	grid-area: 1 / 1;
	translate: var(--snap-x) var(--snap-y); /* whole pixels (site.js) */
}

.logo-wall__slot > .is-entering {
	animation: ibd-logo-wall-in 0.8s ease both;
}

.logo-wall__slot > .is-leaving {
	animation: ibd-logo-out 0.8s ease both;
	pointer-events: none;
}

/* The blur is gone by 75%, while the fade and scale run to the end: even a
 * near-zero blur draws through the filter, a touch softer, so the logo (or
 * quote, or card) visibly sharpened the moment the animation ended. */
@keyframes ibd-logo-in {
	from {
		opacity: 0;
		filter: blur(10px);
		transform: scale(1.04);
	}

	75% {
		filter: none;
	}
}

/* The logo wall's own, without the zoom: a logo drawn larger while it
 * animates (the browser renders the whole animation at its largest size)
 * sharpened slightly as it settled; detailed logos showed it. */
@keyframes ibd-logo-wall-in {
	from {
		opacity: 0;
		filter: blur(10px);
	}

	75% {
		filter: none;
	}
}

@keyframes ibd-logo-out {
	to {
		opacity: 0;
		filter: blur(10px);
		transform: scale(0.97);
	}
}

@media (prefers-reduced-motion: reduce) {
	@keyframes ibd-logo-in {
		from {
			opacity: 0;
		}
	}

	@keyframes ibd-logo-wall-in {
		from {
			opacity: 0;
		}
	}

	@keyframes ibd-logo-out {
		to {
			opacity: 0;
		}
	}
}

@media (max-width: 767px) {
	.logo-wall.is-rotating {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.logo-wall__slot {
		height: 64px;
	}
}

/* Card wall (site.js "Card wall"): cards in a card-wall container, four at a
time, one swapping every few seconds with the logo wall's blur dissolve.
Without JS they're all in a grid.
--------------------------------------------- */
.card-wall {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: var(--space-m);
}

.card-wall__slot {
	display: grid;
}

.card-wall__slot > * {
	grid-area: 1 / 1;
	translate: var(--snap-x) var(--snap-y); /* whole pixels (site.js) */
}

.card-wall__slot > :not(.is-shown, .is-leaving) {
	visibility: hidden;
}

.card-wall__slot > .is-entering {
	animation: ibd-logo-wall-in 0.8s ease both;
}

.card-wall__slot > .is-leaving {
	animation: ibd-logo-out 0.8s ease both;
	pointer-events: none;
}

@media (max-width: 1024px) {
	.card-wall {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 767px) {
	.card-wall {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* Testimonial slider (site.js "Testimonial slider"): testimonial quotes (or
other blocks) in a testimonial-slider container, one at a time with the logo wall's blur
dissolve, and dots to pick one. Without JS they're listed.
--------------------------------------------- */
.testimonial-slider {
	display: grid;
	row-gap: var(--space-l);
}

.testimonial-slider.is-sliding > * {
	grid-area: 1 / 1;
	align-self: center;
}

.testimonial-slider.is-sliding > :not(.is-active, .is-leaving) {
	visibility: hidden;
}

.testimonial-slider > .is-entering {
	animation: ibd-logo-in 0.8s ease both;
}

.testimonial-slider > .is-leaving {
	animation: ibd-logo-out 0.8s ease both;
	pointer-events: none;
}

/* The slider, its dots and the arrows either side (site.js). */
.testimonial-carousel {
	position: relative;
	max-width: calc(900px + 2 * (3rem + var(--space-m)));
	margin-inline: auto;
	padding-inline: calc(3rem + var(--space-m));
}

.testimonial-slider__arrow {
	position: absolute;
	top: calc(50% - (var(--space-m) + 24px) / 2); /* the quote's middle, above the dots row */
	display: grid;
	place-items: center;
	width: 3rem;
	height: 3.5rem;
	padding: 0;
	border: 0;
	background: none;
	color: var(--peach); /* like the inactive pips; orange like the active one on hover */
	cursor: pointer;
	transform: translateY(-50%);
	transition: color 0.2s ease;
}

.testimonial-slider__arrow--prev {
	left: 0;
}

.testimonial-slider__arrow--next {
	right: 0;
}

/* A plain chevron drawn 1:1 (28 × 44px) with an 8px round-capped stroke: the
 * same weight and ends as the active pip. Mirrored for "previous". */
.testimonial-slider__arrow::after {
	content: "";
	width: 28px;
	height: 44px;
	background-color: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 44' fill='none' stroke='black' stroke-width='8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 6l14 16-14 16'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 44' fill='none' stroke='black' stroke-width='8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 6l14 16-14 16'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}

.testimonial-slider__arrow--prev::after {
	transform: scaleX(-1);
}

/* No GP button fill; orange on hover and keyboard focus only (a clicked arrow
 * keeps focus, so plain :focus would leave it orange). */
.testimonial-slider__arrow:is(:hover, :focus, :active) {
	background: none;
	color: var(--peach);
}

.testimonial-slider__arrow:is(:hover, :focus-visible) {
	color: var(--orange);
}

.testimonial-slider__arrow:focus-visible {
	outline: 2px solid var(--orange);
	outline-offset: 2px;
	border-radius: 6px;
}

/* Phones: no room either side, so the arrows sit at the ends of the dots row. */
@media (max-width: 767px) {
	.testimonial-carousel {
		padding-inline: 0;
	}

	.testimonial-slider__arrow {
		top: auto;
		bottom: calc((24px - 3.5rem) / 2);
		transform: none;
	}
}

.testimonial-slider__dots {
	display: flex;
	justify-content: center;
	align-items: center;
	gap: 2px;
	margin-top: var(--space-m);
}

/* Peach pips; the current one stretches into a brand-orange pill. Each sits
in a 24px target (WCAG 2.5.8). */
.testimonial-slider__dot {
	display: grid;
	place-items: center;
	min-width: 24px;
	height: 24px;
	padding: 0 4px;
	border: 0;
	border-radius: var(--radius-pill);
	background: none;
	cursor: pointer;
}

.testimonial-slider__dot::before {
	content: "";
	width: 8px;
	height: 8px;
	border-radius: var(--radius-pill);
	background-color: var(--peach);
	transition: width 0.3s ease, background-color 0.2s ease;
}

/* No GP button fill on hover / focus. */
.testimonial-slider__dot:is(:hover, :focus, :active) {
	background: none;
}

.testimonial-slider__dot:hover::before {
	background-color: var(--orange);
}

.testimonial-slider__dot[aria-current="true"]::before {
	width: 28px;
	background-color: var(--orange);
}

.testimonial-slider__dot:focus-visible {
	outline: 2px solid var(--orange);
	outline-offset: 0;
}

/* Value slider (About "Our core values"): the values in the testimonial
 * slider, one at a time like the quotes: a large heading, then the
 * description, centred. */
.testimonial-carousel:has(> .value-slider) {
	max-width: calc(760px + 2 * (3rem + var(--space-m)));
}

.value-slider > .value {
	display: flex;
	flex-direction: column;
	align-items: center;
	row-gap: var(--space-s);
	text-align: center;
}

.value-slider > .value > * {
	margin-bottom: 0;
}

.value-slider > .value :is(h3, h4) {
	font-size: clamp(1.75rem, 1.25rem + 1.6vw, 2.5rem);
	line-height: 1.2;
}

.value-slider > .value p {
	font-size: var(--text-quote);
	line-height: 1.5;
}

/* Core Services (Home): expanding panels (site.js "Core Services panels").
--------------------------------------------- */

/* One panel is open at a time: it widens and reveals more of its photo (each
 * photo keeps the open panel's width, so nothing zooms), and its title and
 * description come in with the logo wall's focus (blur) dissolve. Closed
 * panels show their title sideways. The 8px colour bar never changes. Phones
 * get a plain stack. */
.service-panels {
	display: flex;
	gap: var(--space-xs);
	height: clamp(27.5rem, 38vw, 35rem); /* room for the longest sideways title, growing with the text size */
	container-type: inline-size;
}

/* The open panel's content width: flex shares out what's left after the gaps
 * and every panel's side padding, 3.2 parts to the open one and 1 to each
 * closed one. --panels is the row's panel count (site.js; 5 by default). */
.service-panels {
	--panels: 5;
}

.service-panel {
	--panel-open-content: calc((100cqw - (var(--panels) - 1) * var(--space-xs) - 2 * var(--panels) * var(--space-s)) * 3.2 / (var(--panels) - 1 + 3.2));
}

.service-panel {
	position: relative;
	isolation: isolate;
	display: flex;
	flex: 1 1 0;
	flex-direction: column;
	justify-content: flex-end;
	align-items: flex-start;
	gap: 0.4em;
	min-width: 0;
	padding: var(--space-s) var(--space-s) calc(var(--space-s) + 8px);
	border-radius: var(--radius); /* the focus ring's shape */
	/* Clipped as one picture (not overflow: hidden, which clips the base,
	 * photo, shade and bar one by one, so the shade only partly covered the
	 * edge pixels and left a fringe of bright photo colour). */
	clip-path: inset(0 round var(--radius));
	background-color: var(--black);
	color: var(--white);
	text-decoration: none;
}

.service-panel:is(:hover, :focus, :active) {
	color: var(--white);
}

.service-panel:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: -3px; /* inside the clip */
}

.service-panel > img {
	position: absolute;
	inset: 0 auto 0 50%;
	z-index: -2;
	width: calc(var(--panel-open-content) + 2 * var(--space-s)); /* the open panel's width */
	max-width: none;
	height: 100%;
	object-fit: cover;
	transform: translateX(-50%);
}

/* A dark fade for the text, and the service colour along the bottom. */
.service-panel::before,
.service-panel::after {
	content: "";
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: -1;
	pointer-events: none;
}

/* Closed panels (--panel-shade 1) get an even 50% shade from top to bottom
 * (measured on the current photos: every sideways title 3.8:1 or better),
 * behind sideways titles that run two-thirds of the way up. As a panel
 * opens (0) it fades to just the bottom, behind the title and description
 * (about the bottom third at the default text size), leaving the top clear.
 * The stops are in rem, so the shade grows with the text; they stay put and
 * only their darkness changes, so it cross-fades rather than sliding. */
@property --panel-shade {
	syntax: "<number>";
	inherits: true;
	initial-value: 1;
}

.service-panel::before {
	top: 0;
	background: linear-gradient(to top, rgb(18 18 18 / calc(0.88 - 0.38 * var(--panel-shade))) 0%, rgb(18 18 18 / calc(0.6 - 0.1 * var(--panel-shade))) 8.75rem, rgb(18 18 18 / calc(0.5 * var(--panel-shade))) 11.875rem, rgb(18 18 18 / calc(0.5 * var(--panel-shade))) 100%);
}

.service-panel {
	--panel-shade: 1;
	transition: flex-grow 0.55s cubic-bezier(0.2, 0.7, 0.2, 1), --panel-shade 0.55s ease;
}

.service-panel.is-open {
	--panel-shade: 0;
}

/* Above everything: while the title fades, its blur makes it a layer of its
 * own, which would otherwise lift its shade band over the bar. */
.service-panel::after {
	z-index: 1;
	height: 8px;
	background-color: var(--service);
}

/* The title, twice: the heading (read across, shown in the open panel) and a
 * sideways copy site.js adds for the closed panels (.service-panel__side,
 * hidden from assistive tech). They cross-fade with the logo wall's focus
 * (blur) dissolve, as does the description (the mega menu's blurb).
 * Transitions, so a quick change of mind reverses smoothly. */
.service-panel > h3,
.service-panel__desc,
.service-panel__side {
	transition: opacity 0.5s ease, filter 0.5s ease, transform 0.5s ease;
}

/* Both wrap at the open panel's width, so they're revealed as it widens
 * rather than re-wrapping. */
.service-panel > :is(h3, .service-panel__desc) {
	width: var(--panel-open-content);
	max-width: none;
	margin: 0;
	color: inherit;
}

.service-panel > h3 {
	position: relative;
	font-size: var(--text-card-title);
	line-height: 1.2;
}

/* A band of shade that fades in from 6rem above the title, is 60% dark from
 * just above it and runs to the bottom, so the text stays on shade however
 * tall it gets (bigger text settings, longer blurbs like About's values).
 * 60% keeps white text at 4.5:1 or better even over a white photo. It fades
 * in and out with the title. */
.service-panel > h3::before {
	content: "";
	position: absolute;
	z-index: -1;
	top: -6rem;
	bottom: -100vh; /* past the panel's bottom edge, which clips it */
	left: calc(-1 * var(--space-s));
	width: calc(var(--panel-open-content) + 2 * var(--space-s));
	background: linear-gradient(to bottom, rgb(18 18 18 / 0), rgb(18 18 18 / 0.6) 5rem);
	pointer-events: none;
}

.service-panel__desc {
	line-height: 1.45;
}

.service-panel:not(.is-open) > :is(h3, .service-panel__desc) {
	opacity: 0;
	filter: blur(10px);
	transform: scale(1.04);
	transform-origin: left bottom;
}

.service-panel__side {
	position: absolute;
	text-shadow: 0 1px 10px rgb(18 18 18 / 0.5);
	left: var(--space-s);
	bottom: calc(var(--space-s) + 8px);
	font-family: var(--gp-font--poppins);
	font-size: var(--text-card-title);
	font-weight: 600;
	line-height: 1.2;
	white-space: nowrap;
	writing-mode: vertical-rl;
	rotate: 180deg;
}

.service-panel.is-open > .service-panel__side {
	opacity: 0;
	filter: blur(10px);
}

/* The open panel (site.js). */
.service-panel.is-open {
	flex-grow: 3.2;
}

/* Solid colour panels (.service-panels--solid, no photos): each panel is its
 * service colour with that colour's ink for the text (dark on orange and
 * yellow, white on blue, red and magenta; all 4.5:1 or better), with no
 * photo shades and no colour bar. */
.service-panels--solid > .service-panel {
	background-color: var(--service);
	color: var(--service-ink);
}

.service-panels--solid > .service-panel:is(:hover, :focus, :active) {
	color: var(--service-ink);
}

.service-panels--solid > .service-panel::before,
.service-panels--solid > .service-panel::after,
.service-panels--solid > .service-panel > h3::before {
	content: none;
}

.service-panels--solid .service-panel__side {
	text-shadow: none;
}

/* Six or more panels (About's values, with longer blurbs) leave the open one
 * narrow on tablets, so the row is taller there. */
@media (min-width: 768px) and (max-width: 1024px) {
	.service-panels:has(> :nth-child(6)) {
		height: 34rem;
	}
}

/* Solid panels have no photo to reveal, so the row is only as tall as its
 * content: the longest blurb (the closed panels' hidden text still takes its
 * height) or, at least, room for the longest sideways title. */
@media (min-width: 768px) {
	.service-panels.service-panels--solid {
		height: auto;
		min-height: 24rem;
	}

	.service-panels--solid > .service-panel {
		padding-top: var(--space-l); /* room above the longest blurb */
	}
}

/* Whole pixels: the same shares, but each panel's width, the gaps and the
 * row's height rounded to whole pixels, so (with the row's site.js nudge,
 * --snap-x/-y) every panel edge lands on a screen pixel instead of blurring
 * into a pale line. The panels animate between those widths. Browsers without
 * CSS round() keep the flex shares above. */
.service-panels {
	translate: var(--snap-x) var(--snap-y);
}

@supports (width: round(1.5px, 1px)) {
	@media (min-width: 768px) {
		.service-panels {
			gap: round(var(--space-xs), 1px);
			height: round(clamp(27.5rem, 38vw, 35rem), 1px);
		}

		.service-panel {
			--panel-row: round(down, 100cqw, 1px);
			--panel-gap: round(var(--space-xs), 1px);
			--panel-closed: round(down, (var(--panel-row) - (var(--panels) - 1) * var(--panel-gap)) / (var(--panels) - 1 + 3.2), 1px);
			--panel-open: calc(var(--panel-row) - (var(--panels) - 1) * var(--panel-gap) - (var(--panels) - 1) * var(--panel-closed));
			--panel-open-content: calc(var(--panel-open) - 2 * var(--space-s));
			flex: 0 0 var(--panel-closed);
			transition: flex-basis 0.55s cubic-bezier(0.2, 0.7, 0.2, 1), --panel-shade 0.55s ease;
		}

		.service-panel.is-open {
			flex-grow: 0;
			flex-basis: var(--panel-open);
		}
	}
}

@media (max-width: 767px) {
	.service-panels {
		flex-direction: column;
		height: auto;
	}

	.service-panel {
		flex: 0 0 auto; /* as tall as its text (the values' blurbs run to several lines) */
		min-height: 9.375rem;
	}

	.service-panel > img {
		inset: 0;
		width: 100%;
		transform: none;
	}

	/* Every panel is the same on phones: no open one, and only the title's
	 * 60% band for shade (the panel's own fade stacked on it took the text
	 * area to about 95%). 60% is the least that keeps white text at 4.5:1
	 * over a white photo. The band spans the panel (100cqw, the row's
	 * width) rather than stopping at the title's end. */
	.service-panels > .service-panel {
		--panel-shade: 0;
	}

	.service-panels:not(.service-panels--solid) > .service-panel::before {
		content: none;
	}

	.service-panel > h3::before {
		width: 100cqw;
	}

	.service-panels .service-panel > :is(h3, .service-panel__desc) {
		width: auto;
		opacity: 1;
		filter: none;
		transform: none;
		white-space: normal;
	}

	.service-panel__side {
		display: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.service-panel {
		transition: none;
	}

	.service-panels .service-panel > * {
		filter: none !important;
		transform: none !important;
	}

	.service-panels .service-panel > img {
		transform: translateX(-50%) !important;
	}
}

/* The same while the site's motion is paused (html.motion-paused, site.js). */
.motion-paused .service-panel {
	transition: none;
}

.motion-paused .service-panels .service-panel > * {
	filter: none !important;
	transform: none !important;
}

.motion-paused .service-panels .service-panel > img {
	transform: translateX(-50%) !important;
}

@media (max-width: 767px) {
	.motion-paused .service-panels .service-panel > img {
		transform: none !important;
	}
}

@media (prefers-reduced-motion: reduce) and (max-width: 767px) {
	.service-panels .service-panel > img {
		transform: none !important;
	}
}

/* Blog filters (inc/services.php ibd_blog_filters()): topic pills above the
blog grid, outlined in their service colour; the current one is filled, and a
click ripples in that colour (site.js "Ripple").
--------------------------------------------- */
.ibd-filters ul {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: var(--space-xs);
	margin: 0 0 var(--space-l);
	padding: 0;
	list-style: none;
}

.ibd-filter {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.55em 1.1em;
	border: 2px solid var(--service);
	border-radius: var(--radius-pill);
	background: var(--white);
	color: var(--black);
	font-family: var(--gp-font--poppins);
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.2;
	text-decoration: none;
	transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.ibd-filter--all {
	--service: var(--black);
}

:is(.ibd-filter, .ibd-share__link) > .ibd-ripple {
	background: var(--service);
	opacity: 0.35;
}

.ibd-filter:is(:hover, :focus) {
	border-color: var(--service);
	background: color-mix(in srgb, var(--service) 12%, var(--white));
	color: var(--black);
}

.ibd-filter--all:is(:hover, :focus) {
	background: var(--grey);
}

.ibd-filter[aria-current="page"] {
	border-color: var(--service);
	background: var(--service);
	color: var(--service-ink);
}

.ibd-filter--all[aria-current="page"] {
	color: var(--white);
}

.ibd-filter:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 2px;
}

/* The posts cross-fade as a filter switches (site.js), like the logo wall and
with its keyframes (plain fade for reduced motion): copies of the old cards,
placed over the new ones, blur out as the new cards blur in, once the new
cards' images have loaded. */
body > .ibd-filter-ghost { /* beats the card's own position: relative */
	position: absolute;
	z-index: 2;
	margin: 0;
	pointer-events: none;
}

/* New cards wait hidden under the copies until their images have loaded. */
.is-filter-wait {
	opacity: 0;
}

.is-filter-out {
	animation: ibd-logo-out 0.8s ease both;
}

.is-filter-in {
	animation: ibd-logo-in 0.8s ease both;
}

/* Small utilities
--------------------------------------------- */
/* 404: the two ways forward side by side (content-404.php). */
.ibd-404-actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-s);
}

.ibd-visually-hidden:not(:focus):not(:active) {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		scroll-behavior: auto !important; /* override GB/GP smooth scroll */
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
	}
}

/* Team bio popup (inc/helpers.php adds the button + template, site.js the
   <dialog>): photo beside name, pronouns, role and bio, as on the old site.
--------------------------------------------- */
.card-team:has(.ibd-bio-open) {
	cursor: pointer;
}

.ibd-bio-open {
	position: absolute;
	inset: 0;
	z-index: 1;
	padding: 0;
	border: 0;
	border-radius: inherit;
	background: none;
	cursor: pointer;
}

.ibd-bio-open:hover,
.ibd-bio-open:focus {
	background: none;
}

.ibd-bio-open:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: -3px;
}

.ibd-bio-dialog {
	width: min(100% - 2rem, 960px);
	max-height: min(100% - 2rem, 760px);
	padding: 0;
	border: 0;
	border-radius: var(--radius);
	background: var(--white);
	color: var(--black);
	box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
	overflow: auto;
	overscroll-behavior: contain;
	/* The logo wall's blur dissolve (ibd-logo-in / -out): it comes in from a
	 * slightly larger blur and leaves into a slightly smaller one. */
	opacity: 0;
	filter: blur(10px);
	transform: scale(0.97);
	transition: opacity 0.6s ease, filter 0.6s ease, transform 0.6s ease, overlay 0.6s allow-discrete, display 0.6s allow-discrete;
}

.ibd-bio-dialog[open] {
	opacity: 1;
	filter: none;
	transform: none;
}

@starting-style {
	.ibd-bio-dialog[open] {
		opacity: 0;
		filter: blur(10px);
		transform: scale(1.04);
	}
}

.ibd-bio-dialog::backdrop {
	background: rgba(0, 0, 0, 0);
	transition: background 0.4s ease, overlay 0.6s allow-discrete, display 0.6s allow-discrete;
}

.ibd-bio-dialog[open]::backdrop {
	background: rgba(0, 0, 0, 0.6);
}

@starting-style {
	.ibd-bio-dialog[open]::backdrop {
		background: rgba(0, 0, 0, 0);
	}
}

html:has(.ibd-bio-dialog[open]) {
	overflow: hidden;
}

.ibd-bio {
	display: grid;
	grid-template-columns: 1fr 2fr;
	gap: var(--space-m);
	align-items: start;
	padding: var(--space-m);
}

.ibd-bio__photo {
	position: sticky;
	top: 0;
	width: 100%;
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: var(--radius);
}

.ibd-bio__name {
	margin: 0 3rem 0 0;
	font-size: clamp(1.75rem, 1.4rem + 1vw, 2.25rem);
}

.ibd-bio__pronouns {
	margin: 0.25rem 0 0;
	font-weight: 600;
}

.ibd-bio__role {
	margin: 0.25rem 0 var(--space-s);
}

.ibd-bio__body > :last-child {
	margin-bottom: 0;
}

.ibd-bio-close {
	position: absolute;
	top: 1rem;
	right: 1rem;
	z-index: 1;
	display: grid;
	place-items: center;
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--black);
	color: var(--white);
	font-size: 1.75rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.ibd-bio-close:hover,
.ibd-bio-close:focus-visible {
	background: var(--orange);
	color: var(--white);
}

@media (max-width: 767px) {
	.ibd-bio {
		grid-template-columns: 1fr;
		padding: var(--space-s);
	}

	.ibd-bio__photo {
		position: static;
		max-width: 240px;
	}
}

