/*
 * 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;
}

/* 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);
	}
}

/* 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;
}

/* 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);
}

/* 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 */
}

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

.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: " →";
}

/* 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);
}

.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;
}

.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;
}

.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;
}

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

/* 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 */
	-webkit-mask: var(--m-top) top / 100% var(--wave-height) no-repeat, var(--wave-solid) center / 100% calc(100% - 2 * var(--wave-height)) 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)) no-repeat, var(--m-bottom) bottom / 100% var(--wave-height) no-repeat;
}

.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));
}

.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 {
	--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;
}

/* 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;
	height: calc(100vh + 2 * var(--wave-height));
	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;
}

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;
}

/* 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);
}

/* 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 6px higher,
 * filled all the way down; the hero's own cut trims it to a band. */
:root {
	--wave-edge: 6px;
	--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;
}

/* 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. */
.ibd-mega__title::before {
	content: "";
	display: inline-block;
	width: 0.6em;
	height: 0.6em;
	margin-right: 0.5em;
	border-radius: 50%;
	background: var(--service);
	vertical-align: 0.05em;
	transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

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

.ibd-mega__item:is(:hover, :focus) .ibd-mega__title::before {
	transform: scale(1.4);
}

/* 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(6px + 45% * var(--lift));
	background: linear-gradient(to top, var(--service) 0 6px, color-mix(in srgb, var(--service) 60%, transparent) 6px, transparent);
	pointer-events: none;
}

/* 7. Blog cards: a service tag (label set in inc/services.php) and a colour edge. */
.card-post > img {
	border-bottom: 4px solid var(--accent-bar, transparent);
}

.card-post .card-body::before {
	align-self: flex-start;
	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;
}

/* Marquee: a constantly scrolling row (e.g. "About Deb & Our Team" on Home)
 * Give a Query block the class ibd-marquee-viewport and its Looper 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. Reduced-motion visitors get a
 * swipeable row.
--------------------------------------------- */
body {
	overflow-x: clip; /* full-bleed rows never cause a sideways scroll */
}

.ibd-marquee-viewport {
	margin-inline: calc(50% - 50vw); /* edge to edge */
	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 */
}

@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: none;
}

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

.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;
}

@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;
	}
}

/* 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;
}

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

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

@keyframes ibd-logo-in {
	from {
		opacity: 0;
		filter: blur(10px);
		transform: scale(1.04);
	}
}

@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-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;
	}
}

/* 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;
	opacity: 0;
	transform: translateY(24px);
	transition: opacity 0.25s ease, transform 0.3s ease-out, overlay 0.3s allow-discrete, display 0.3s allow-discrete;
}

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

@starting-style {
	.ibd-bio-dialog[open] {
		opacity: 0;
		transform: translateY(24px);
	}
}

.ibd-bio-dialog::backdrop {
	background: rgba(0, 0, 0, 0);
	transition: background 0.25s ease, overlay 0.3s allow-discrete, display 0.3s 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;
	}
}
