/* -----------------------------------------------------------------------
   components.css — buttons, cards, sliders, forms, marquee.
   ----------------------------------------------------------------------- */

/* --------------------------------------------------------------- button */

/*
 * The design's button is a square white block with a gradient L-bracket
 * offset outside the top-left and bottom-right corners (the design and
 * "Vector 1", both absolutely positioned outside the frame). The brackets are
 * decorative, so they are drawn as pseudo-element backgrounds.
 */
.btn {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	/*
	 * The design draws the button's 1px stroke INSIDE its 187x44 frame — padding
	 * 24/12 plus a 20px line comes to exactly 44 there. CSS adds the border
	 * outside the padding box, so the padding is reduced by the border width
	 * to land on the same 44x(text+48) the design specifies.
	 *
	 * The line is pinned to 20px rather than inherited as 140%: 14 x 1.4 is
	 * 19.6, which the design's own layout rounds up to the 20 its 44px frame is
	 * built on. Leaving it fluid made every button in the theme 43.59 tall —
	 * rounding to 44 in a test while never actually being 44.
	 */
	padding: 11px 23px;
	background-color: var(--white);
	color: var(--c-ink-dark);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 500;
	line-height: 20px;
	text-align: center;
	border: 1px solid rgba(0, 0, 0, 0.01);
	/*
	 * Anchors get this from the UA sheet, but .btn is also worn by <button> and
	 * — on the project card — by a <span> that only repeats the card's own link
	 * for the pointer. Those two would otherwise show a text caret over
	 * something that plainly reads as a button.
	 */
	cursor: pointer;
	transition: background-color var(--transition), color var(--transition);
}

.btn::before,
.btn::after {
	content: "";
	position: absolute;
	width: 24px;
	height: 24px;
	pointer-events: none;
	background-repeat: no-repeat;
	background-size: contain;
	transition: transform var(--transition);
}

.btn::before {
	top: -4px;
	left: -4px;
	background-image: url("../icons/vector-2-1.svg");
}

.btn::after {
	right: -4px;
	bottom: -4px;
	background-image: url("../icons/vector-1-1.svg");
}

.btn:hover {
	background-color: var(--c-accent);
	color: var(--white);
}

.btn:hover::before {
	transform: translate(-2px, -2px);
}

.btn:hover::after {
	transform: translate(2px, 2px);
}

/* On light surfaces the white brackets are invisible, so drop them. */
.btn--on-light::before,
.btn--on-light::after {
	display: none;
}

/* The design: transparent with a 1px white rule and white text. */
.btn--outline {
	background-color: transparent;
	color: var(--white);
	border-color: var(--white);
}

.btn--outline:hover {
	background-color: var(--white);
	color: var(--c-ink-dark);
}

/*
 * the design: the red button keeps its brackets, but they are
 * drawn in the primary red rather than white — on the light contact card the
 * white pair would be invisible, which is why this used to be given
 * `btn--on-light` and lose them altogether.
 */
.btn--primary {
	background-color: var(--c-accent);
	color: var(--white);
}

.btn--primary::before {
	background-image: url("../icons/vector-2-primary.svg");
}

.btn--primary::after {
	background-image: url("../icons/vector-1-primary.svg");
}

/*
 * Red to WHITE on hover, with dark text.
 *
 * It used to darken to --c-ink-dark, which on the dark bands this button
 * mostly sits on (property and project cards, the support band, the lightbox)
 * left it almost the colour of the page behind it — the hovered card read as
 * the disabled one. Going the other way keeps the contrast climbing as the
 * pointer lands, which is what a hover is for.
 */
.btn--primary:hover {
	background-color: var(--white);
	color: var(--c-ink-dark);
}

/*
 * Except on the white nav panels, where white on white is the same mistake
 * pointing the other way. There the button darkens, which is what reads
 * against that ground.
 */
.btn--on-panel:hover {
	background-color: var(--c-ink-dark);
	color: var(--white);
}

/* ---------------------------------------------------------- slider nav */

/*
 * Circular previous/next controls. The inactive control sits at 20% white,
 * the active one is solid white with a dark arrow.
 */
.slider-nav {
	display: flex;
	align-items: center;
	gap: 8px;
}

/*
 * the design: 44x44, radius 36 (a circle at this size). Both
 * controls are solid white; the one that cannot move drops to 10% opacity —
 * so first slide dims prev, last slide dims next, and anywhere in between both
 * are white. Swiper's own disabled class drives it, so no JS is needed.
 */
.slider-nav__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: 50%;
	background-color: var(--white);
	color: var(--c-ink-dark);
	transition: opacity var(--transition);
}

.slider-nav__btn svg {
	width: 20px;
	height: 20px;
}

/* A restrained hover, rather than the colour flip this used to do. */
.slider-nav__btn:hover:not(.swiper-button-disabled):not(:disabled) {
	opacity: 0.85;
}

.slider-nav__btn.swiper-button-disabled,
.slider-nav__btn:disabled {
	opacity: 0.1;
	cursor: default;
}

/* Progress rails under a slider: one per slide, active is red. */
.slider-rails {
	display: flex;
	align-items: center;
	gap: 4px;
}

.slider-rails__item {
	flex: 1 1 0;
	height: 2px;
	max-width: 130px;
	background-color: rgba(255, 255, 255, 0.25);
	transition: background-color var(--transition);
}

.slider-rails__item.is-active {
	background-color: var(--c-accent);
}

/* ------------------------------------------------------------- counter */

/* The "1/3" step counter: current is full white, total is dimmed. */
.counter {
	font-family: var(--font-heading);
	line-height: var(--lh-tight);
	text-transform: uppercase;
}

.counter__current {
	color: var(--white);
}

/*
 * The design: the total sits at 20% opacity in both the step and location counters.
 *
 * line-height is restated rather than inherited. The counter row sets it once
 * on the parent, where 1.1 has already computed to a LENGTH against the H4
 * size — inheriting that left the smaller total in a 26.4px line box against
 * the design's 18, which set the height of the whole row.
 */
.counter__total {
	color: var(--white);
	line-height: var(--lh-tight);
	opacity: 0.2;
}

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

.card {
	position: relative;
	display: flex;
	flex-direction: column;
	background-color: var(--c-bg-alt);
}

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

/*
 * The contact form sits on the light panel: underlined fields,
 * no boxes, placeholder-as-label with a real <label> kept for screen readers.
 */
/* the design: fields stacked with an 8px gap. */
.bbqld-form form {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.form-field {
	position: relative;
	display: block;
	margin: 0;
}

.form-field__label {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/*
 * the design: each field is 8px of space, one 14px line, 6px of space
 * and a 1px rule at 10% BLACK — not the 12/12 padding over a 20% ink rule this
 * used to carry.
 *
 * The line is pinned to 20px for the same reason the button's is: 14 x 1.4 is
 * 19.6, but the design's own layout rounds that to the 20 its 34px field is built
 * on. Inherited as 1.4 every field came out 34.6 and the six-field stack drifted
 * 4px past the design.
 */
.form-field__control,
.bbqld-form input[type="text"],
.bbqld-form input[type="email"],
.bbqld-form input[type="tel"],
.bbqld-form input[type="number"],
.bbqld-form textarea {
	width: 100%;
	/*
	 * 8 above the line and 6 below comes to 34 in the design because the 1px rule is
	 * drawn INSIDE that 34, exactly as the button's stroke is. CSS adds the
	 * border outside the padding box, so the lower padding is reduced by the
	 * border width to land on the same 34 — otherwise every field is 35 and the
	 * six-field stack pushes the card 6px past the design.
	 */
	/*
	 * 2px of it horizontal. The design runs the type flush to the start of the
	 * rule, and at a literal 0 the browser gives a field no side gutter at all
	 * — so the left bearing of the first glyph was being clipped by the control's
	 * own edge, worst on a textarea and on letters that lean into their bearing.
	 * 2 clears it while staying within rounding of the design's alignment, and
	 * it is on the shared rule so every field in a form still lines up with the
	 * others rather than the message box stepping in on its own.
	 */
	padding: 8px 8px 5px;
	background: transparent;
	/*
	 * Block, not the UA's inline-block: as an inline element the textarea sat on
	 * a line box and its descender space made the field 6.4px taller than the
	 * control inside it.
	 */
	display: block;
	color: var(--c-ink-dark);
	font-family: var(--font-body);
	font-size: var(--fs-small);
	font-weight: 300;
	line-height: 20px;
	border: 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.1);
	border-radius: 0;
	transition: border-color var(--transition);
}

/*
 * the design: the same field with 32px below the line instead of 6, so
 * it reads as a message box while still being one line tall at rest. The
 * height is set explicitly because CF7 emits a rows attribute that would
 * otherwise size the control to ten lines.
 */
.bbqld-form textarea {
	height: 60px;
	min-height: 60px;
	/* 31 + the 1px rule = the 32 the design leaves under the line. */
	padding-bottom: 31px;
	resize: vertical;
}

/* The submit button carries the design's 24px gap above it. */
.bbqld-form input[type="submit"],
.bbqld-form .wpcf7-submit {
	align-self: flex-start;
	margin-top: 16px;
	cursor: pointer;
}

/* The design: black at 50%, not the ink tint this approximated it with. */
.bbqld-form input::placeholder,
.bbqld-form textarea::placeholder {
	color: rgba(0, 0, 0, 0.5);
	opacity: 1;
}

.bbqld-form input:focus,
.bbqld-form textarea:focus {
	border-bottom-color: var(--c-accent);
	outline: none;
}

/*
 * The focus ring follows the ground rather than the brand. Red on a field
 * reads as a validation failure — the same colour .wpcf7-not-valid-tip uses —
 * so a correctly filled field looked rejected the moment it was focused. The
 * default is the dark ink for the homepage's white contact card; the
 * consultation panel flips it to white, and the submit picks up whichever is
 * set because it is an input too.
 */
.bbqld-form {
	--form-focus: var(--c-ink-dark);
}

/*
 * Buttons too, not just inputs: Contact Form 7 renders the submit as a
 * <button>, so an input-only rule left it falling through to the global red
 * ring in base.css — the one control on the form that still flashed red. The
 * 2px offset puts the ring on the panel behind the white button, where it
 * shows, rather than on the button itself.
 */
.bbqld-form :is(input, textarea, select, button):focus-visible {
	outline: 1px solid var(--form-focus);
	outline-offset: 2px;
}

/* Contact Form 7 chrome, restyled to the design. */
.bbqld-form .wpcf7-form-control-wrap {
	display: block;
}

.bbqld-form .wpcf7-not-valid-tip {
	display: block;
	margin-top: 6px;
	color: var(--c-accent);
	font-size: 12px;
	line-height: 1.4;
}

.bbqld-form .wpcf7-response-output {
	margin: 16px 0 0;
	padding: 12px 16px;
	color: var(--c-ink-dark);
	font-size: 13px;
	line-height: 1.4;
	border: 1px solid rgba(25, 24, 27, 0.2);
}

/*
 * CF7 ships the spinner as an inline-block that is merely `visibility: hidden`
 * until a submission is in flight — harmless in normal flow. But this form is a
 * flex column, and flex BLOCKIFIES its children: the spinner became a full
 * 24px flex item, and with the form's 8px gap it held 32px of empty card open
 * under the submit at all times. That was the single largest reason the contact
 * band measured 755 against the 705 its design draws.
 *
 * Absolute positioning takes it out of the flex flow while leaving it at its
 * static position, so it still appears by the button during a submission
 * rather than being hidden outright.
 */
.bbqld-form .wpcf7-spinner {
	position: absolute;
	margin-left: 8px;
}

.bbqld-form form.invalid .wpcf7-response-output,
.bbqld-form form.unaccepted .wpcf7-response-output {
	border-color: var(--c-accent);
}

.bbqld-form form.sent .wpcf7-response-output {
	border-color: #2e7d32;
}

/* ----------------------------------------------------------- marquee */

/*
 * The partner logo strip is two rows scrolling in opposite directions
 *. Each logo occupies a
 * 193x80 cell, cells are 24px apart, and the row sits at 40% opacity.
 *
 * THE ASSETS ARE WHOLE CELLS, not bare logos. The design composites each logo as a
 * white fill masked by the artwork's alpha, positioned inside its cell — so
 * the bundled asset is that finished 193x80 cell, sliced from the design's own
 * render. Sizing it with `contain` therefore cannot distort anything, which is
 * what the previous build did: it forced per-logo mask sizes taken from the
 * design onto source files with quite different aspect ratios (SONTO was a
 * square 353x353 squeezed into 159x66 — a 141% skew).
 *
 * The mobile frame is the same component at exactly 68.75%
 * (990x55 from 1440x80), so one multiplier drives the cell, the gap and the
 * row height.
 */
.marquee {
	--marquee-scale: 1;
	--marquee-duration: 28s;
	display: flex;
	overflow: hidden;
	width: 100%;
}

.marquee__track {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	gap: calc(24px * var(--marquee-scale));
	/* The trailing gap so the seam spaces like every other pair. */
	padding-right: calc(24px * var(--marquee-scale));
	animation: bbqld-marquee var(--marquee-duration) linear infinite;
}

.marquee--reverse .marquee__track {
	animation-direction: reverse;
}

.marquee:hover .marquee__track {
	animation-play-state: paused;
}

/* The design: a 193x80 cell at 40% opacity. */
.marquee__item {
	display: flex;
	flex: 0 0 calc(193px * var(--marquee-scale));
	align-items: center;
	justify-content: center;
	width: calc(193px * var(--marquee-scale));
	height: calc(80px * var(--marquee-scale));
	opacity: 0.4;
	transition: opacity var(--transition);
}

.marquee__item:hover {
	opacity: 1;
}

/*
 * The artwork is already a white silhouette filling its cell, so it is drawn
 * through a white box via its own alpha and scaled with `contain` — no
 * per-logo size is needed, and none can skew it. A logo the client adds later
 * is fitted the same way.
 */
.marquee__logo {
	display: block;
	width: 100%;
	height: 100%;
	background-color: var(--white);
	-webkit-mask-image: var(--logo);
	mask-image: var(--logo);
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: var(--logo-size, contain);
	mask-size: var(--logo-size, contain);
}

@keyframes bbqld-marquee {
	from {
		transform: translateX(0);
	}

	to {
		transform: translateX(-100%);
	}
}

/* the mobile design: the whole strip at 68.75%. */
@media (max-width: 1024px) {
	.marquee {
		--marquee-scale: 0.6875;
	}
}

@media (prefers-reduced-motion: reduce) {
	.marquee__track {
		animation: none;
	}

	.marquee {
		overflow-x: auto;
	}
}

/* ------------------------------------------------------------ video modal --
 * A native <dialog> in the top layer. The panel borrows the design language
 * already established elsewhere: the button's bracket corners, the theme's
 * ground colour, and the 44px round control used by the slider arrows.
 * -------------------------------------------------------------------------- */

.video-modal {
	/*
	 * The vertical room the panel must leave for its own chrome.
	 *
	 * The close control sits 60 ABOVE the panel, and because the panel is
	 * centred, whatever is reserved above has to exist below as well — so the
	 * allowance is 60 twice over, plus 16 of breathing room at each end.
	 */
	--video-chrome: 152px;

	max-width: none;
	max-height: none;
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
	background: transparent;
	border: 0;
	overflow: hidden;
}

.video-modal::backdrop {
	background-color: rgba(25, 24, 27, 0.88);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
}

/* The dialog fills the viewport; this centres the panel inside it. */
.video-modal::before {
	content: "";
	display: block;
	height: 100%;
}

/*
 * The panel is sized by WIDTH and takes its height from the stage's 16/9, so
 * the viewport's height has to bound the width as well — otherwise the panel
 * stays 1120x630 on a short window, the dialog's overflow: hidden crops it, and
 * the close control is the first thing to go: at 1440x700 it sat at top: -25,
 * off the screen entirely, and by 1440x620 the picture was cut at both ends.
 *
 * The third term is that bound, expressed the same way round as the other two:
 * the widest the panel may be for its 9/16 height to fit the room left after
 * the chrome. dvh rather than vh so a phone's collapsing address bar counts,
 * with a vh line first for anything that does not know dvh.
 */
.video-modal__panel {
	position: absolute;
	top: 50%;
	left: 50%;
	width: min(1120px,
			calc(100vw - var(--gutter) * 2),
			calc((100vh - var(--video-chrome)) * 16 / 9));
	width: min(1120px,
			calc(100vw - var(--gutter) * 2),
			calc((100dvh - var(--video-chrome)) * 16 / 9));
	transform: translate(-50%, -50%);
	background-color: var(--black);
}

/* The same bracket motif the buttons carry, at the panel's two far corners. */
.video-modal__panel::before,
.video-modal__panel::after {
	content: "";
	position: absolute;
	width: 24px;
	height: 24px;
	background-repeat: no-repeat;
	background-size: contain;
	pointer-events: none;
}

.video-modal__panel::before {
	top: -8px;
	left: -8px;
	background-image: url("../icons/vector-2-1.svg");
}

.video-modal__panel::after {
	right: -8px;
	bottom: -8px;
	background-image: url("../icons/vector-1-1.svg");
}

.video-modal__stage {
	position: relative;
	aspect-ratio: 16 / 9;
	width: 100%;
	overflow: hidden;
}

.video-modal__stage iframe,
.video-modal__stage video {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/*
 * z-index, because the control precedes the stage in the DOM and both are
 * positioned with z-index auto — so the video painted straight over the top of
 * it the moment the control moved inside the panel on a small screen.
 */
.video-modal__close {
	position: absolute;
	z-index: 2;
	top: -60px;
	right: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	background-color: var(--white);
	color: var(--c-ink-dark);
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	transition: background-color var(--transition), transform var(--transition);
}

.video-modal__close svg {
	width: 14px;
	height: 14px;
}

/* The icon ships with a baked white fill; the button needs it to follow. */
.video-modal__close svg path {
	fill: currentColor;
}

.video-modal__close:hover {
	background-color: var(--c-accent);
	color: var(--white);
	transform: scale(1.06);
}

.video-modal[open] .video-modal__panel {
	animation: bbqld-video-in 260ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes bbqld-video-in {
	from {
		opacity: 0;
		transform: translate(-50%, calc(-50% + 12px)) scale(0.98);
	}

	to {
		opacity: 1;
		transform: translate(-50%, -50%) scale(1);
	}
}

/*
 * Below the breakpoint the close control has nowhere to sit above the panel on
 * a short screen, so it moves inside the top-right corner of the stage.
 */
@media (max-width: 768px),
(max-height: 600px) {

	/*
	 * With the control inside the stage there is nothing to reserve above it,
	 * so the height budget only has to keep the panel off the two edges.
	 */
	.video-modal {
		--video-chrome: 48px;
	}

	/*
	 * Inside the corner it is sitting ON the video, where the white disc
	 * vanishes the moment a frame is bright — so it flips to the theme's dark
	 * ground with a white glyph, which reads against any footage.
	 */
	.video-modal__close {
		top: 8px;
		right: 8px;
		width: 40px;
		height: 40px;
		background-color: rgba(25, 24, 27, 0.72);
		color: var(--white);
		backdrop-filter: blur(4px);
		-webkit-backdrop-filter: blur(4px);
	}

	.video-modal__close:hover {
		background-color: var(--c-accent);
		color: var(--white);
	}

	.video-modal__panel::before,
	.video-modal__panel::after {
		display: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.video-modal[open] .video-modal__panel {
		animation: none;
	}
}

/*
 * The white button. The featured post's CTA fills #FFFFFF with
 * #19181B text where every other "View in Detail" on the site is the red
 * primary — on a photograph-heavy band the red would compete with the image.
 */
.btn--light {
	background-color: var(--white);
	color: var(--c-ink-dark);
}

.btn--light:hover,
.btn--light:focus-visible {
	background-color: var(--c-accent);
	color: var(--white);
}
