/*
 Theme Name:   Bricks Child Theme
 Theme URI:    https://bricksbuilder.io/
 Description:  Use this child theme to extend Bricks.
 Author:       Bricks
 Author URI:   https://bricksbuilder.io/
 Template:     bricks
 Version:      1.1
 Text Domain:  bricks
*/

/* Mobile menu slide-in-from-left, layered on top of Bricks' own native
   fade — see mobile-menu-slide.js for why this is driven by JS watching
   aria-expanded rather than hooking into Bricks' own (inaccessible)
   opacity/visibility toggle mechanism.
   `.bricks-mobile-menu-wrapper` is itself a <nav> nested inside
   #brx-header, so the plain class selector alone loses the specificity
   fight against `#brx-header nav`'s own `transition: top 0.8s` (a
   `transition` shorthand fully replaces the previous value rather than
   merging — confirmed via direct inspection that this was silently
   dropping the transform transition entirely, which is why the slide
   wasn't animating at all, just snapping). #brx-header prefix here
   matches that specificity so this one wins instead. */
#brx-header .bricks-mobile-menu-wrapper {
	transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Smooth scroll for anchor-link jumps (e.g. the header's "Contact" link)
   and any JS-driven scrollTo — every page except the homepage, which has
   scroll-snap-type:y mandatory (set directly in the Bricks builder) and no
   custom scroll-linked JS at all per client request; scroll-behavior:smooth
   would be redundant there at best, and this theme's history shows this
   exact page is sensitive to anything touching its scroll feel.
   Pure CSS — doesn't affect raw wheel/trackpad scrolling itself (browsers
   don't apply scroll-behavior to that), only programmatic/anchor scrolls,
   so there's no scroll-snap-fighting risk like the reverted wheel-smoothing
   attempt had.
   scroll-behavior only takes effect on the scrolling box's own element
   (:root/html here), but the "home" class WordPress adds lives on <body>,
   not <html> — :has() is what lets the html-level rule below react to a
   body-level class. */
html {
	scroll-behavior: smooth;
}
html:has(body.home) {
	scroll-behavior: auto;
}

/* /work/ "Load More" button — its flex container defaulted to
   justify-content: normal (= left-aligned); centre it instead. */
#brxe-7d4de6 {
	justify-content: center;
}

/* Footer content container (set in the Bricks builder, not this repo) —
   the base tier sets `min-width: 1425px` (plus an unhelpfully-large
   `max-width: 1800px`) with no override between it and the next real
   Bricks breakpoint down at 991px, which resets to 100vw. Anything in
   that 992–1424px gap (e.g. 1024px) just inherits the base's
   min-width: 1425px and overflows — its own parent section IS correctly
   responsive, this one element isn't. min-width is what actually forces
   the box wide regardless of what `width` says (it clamps the used
   width value), so that's the one that has to be overridden — an
   earlier attempt here only touched width/max-width and had no visible
   effect because of this. Standard responsive-container fix — width:100%
   does the real constraining now, max-width keeps the original intended
   1425px cap on wide desktop screens. */
#brxe-f8777b {
	width: 100% !important;
	min-width: 0 !important;
	max-width: 1425px !important;
}

/* Same bug, same fix, different element — the Contact page's content
   section (#brxe-0d98f4, set in the Bricks builder) has the identical
   broken min-width: 1425px / max-width: 1800px combo as the footer above,
   overflowing in the same 992–1424px breakpoint gap (confirmed at
   1024px: scrollWidth 1425 against a 1024 viewport, visible as a white
   gap on the right where the page doesn't fully extend). This looks like
   a Bricks default that several sections/containers on this site inherit
   unless explicitly overridden per element — check other pages for the
   same white-gap symptom if it turns up again. */
#brxe-0d98f4 {
	width: 100% !important;
	min-width: 0 !important;
	max-width: 1425px !important;
}

/* Hero section (front page, #brxe-nsvmzk) — Adam flagged it should carry
   no border/border-radius at all. border-grow-in-observer.js already
   excludes it from the clip-path grow-in effect other sections get, but
   Bricks applies border-radius: 20px to every .bricks-background-video-
   wrapper by default regardless (a generic, unscoped inline rule) — for
   every other section that's masked automatically since clip-path
   overrides border-radius once present, but the hero gets no clip-path
   at all now, so its raw 20px was showing through unmasked. */
#brxe-nsvmzk .bricks-background-video-wrapper {
	border-radius: 0 !important;
}

/* Header background + padding on scroll, per Adam's feedback: the header
   is transparent at rest, which clashed with its text/logo against
   thumbnail images underneath once scrolled (seen on the /work/ portfolio
   grid). The nav's own `top: 50px` (set directly in the Bricks builder,
   stays as-is at rest — needed there) sits inside #brx-header's own box,
   which starts at the very top of the viewport (verified: header's box is
   y:0, nav's visible text sits within that), so a background/padding on
   #brx-header itself does actually land where the nav visually renders.
   Every page except the homepage (header-scroll-bg.js enqueues via
   !is_front_page()) — homepage keeps the header transparent and handles
   the nav-over-video clash via the top offset below instead. */
#brx-header {
	transition: background-color 0.5s ease, padding 0.5s ease;
}
#brx-header.nav-scrolled-bg {
	background-color: #fdeae3;
	padding-top: 16px;
	padding-bottom: 16px;
}

/* Nav top offset removed on scroll — every page except the homepage,
   which has no custom scroll-linked JS at all (client's explicit
   request): its nav keeps whatever static top value is set directly in
   the Bricks builder, full stop.
   (header-scroll-remove-top-offset.js only enqueues where
   !is_front_page(), see functions.php.) */
#brx-header nav {
	transition: top 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}
#brx-header nav.nav-scrolled-remove-top {
	top: 0 !important;
}

/* Bricks' AJAX "Load More" spinner (.brx-loading-animation) gets inserted
   as a regular item straight into the portfolio grid itself, so it just
   lands in the next open grid cell (leftmost column) like any other card
   instead of being centred under the button. Span it across every column
   and centre it within that span. */
.brxe-container.brx-grid > .brx-loading-animation {
	grid-column: 1 / -1;
	justify-self: center;
}

/* Nav link hover text-reveal — matches the original Salient site's
   .nectar-text-reveal-button effect (verified against its actual CSS). The
   link text is duplicated via a ::after pseudo-element carrying the same
   string (content: attr(data-text)), stacked just below the visible text
   and clipped by the wrapper's overflow:hidden. On hover both slide up in
   sync — the original exits upward, the duplicate enters from below.
   Markup (the wrapping spans + data-text attribute) is injected at runtime
   by nav-text-reveal.js, since Bricks' native nav menu doesn't offer this. */
#brx-header .brxe-text-link {
	position: relative;
}
#brx-header .nectar-text-reveal-button {
	overflow: hidden;
	display: block;
	line-height: 1.3;
	transform: translateZ(0);
}
#brx-header .nectar-text-reveal-button__text {
	transition: transform 0.55s cubic-bezier(0.25, 1, 0.33, 1);
	display: block;
}
#brx-header .nectar-text-reveal-button__text::after {
	transition: transform 0.55s cubic-bezier(0.25, 1, 0.33, 1);
	content: attr(data-text);
	position: absolute;
	left: 0;
	bottom: -120%;
}
#brx-header a:hover .nectar-text-reveal-button__text {
	transform: translateY(-100%);
}
#brx-header a:hover .nectar-text-reveal-button__text::after {
	transform: translateY(-20%);
}

/* Cinematic scroll hero — rounded, contained, overflow hidden.
   Border stays static (matches the original Salient site's own behaviour —
   its border-radius was never scroll-animated either, verified against its
   actual CSS). A real scroll-driven border-grow effect is still wanted for
   later, but needs a different technique than margin/border-radius on this
   exact section — two prior attempts corrupted the video's layout, likely
   from conflicting with how Bricks measures/sizes its background video. */
/* Framing via inset on the video wrapper, not margin on the section itself.
   margin on a full-bleed section fights with 100vw-based sizing (which
   always accounts for scrollbar width, even with the scrollbar hidden as
   below), and was clipping the right edge. Insetting just the video keeps
   the section's own box genuinely edge-to-edge — no overflow ambiguity —
   with its cream background showing through the gap instead. */
#brx-content > section.has-bg-video {
	background-color: #fdeae3;
	/* The non-hero sections carry a 16px border set in the Bricks builder,
	   colour-matched to this same background so it reads as invisible — but
	   it still occupies layout space, stacking with the wrapper's own 16px
	   inset below to double the framing gap to 32px on those sections only
	   (the hero has no such border, so it stayed correct at 16px). Neutralise
	   it here so every section frames identically. */
	border: 0 !important;
}
#brx-content > section.has-bg-video:first-of-type {
	will-change: transform, opacity;
}

/* Project section titles: bottom-left instead of centred. The section
   itself already positions its content box at the bottom-left correctly
   (justify-content: flex-end / align-items: flex-start, set in the Bricks
   builder) — but that content box spans the section's full width, and its
   own internal flex (justify-content/align-items: center, also builder-set)
   re-centres the heading inside it, cancelling that positioning out
   visually. Overriding just the inner alignment here fixes it without
   touching the builder-set outer box. Scoped off the hero (:first-of-type)
   — this is only about the individual project sections. */
#brx-content > section.has-bg-video:not(:first-of-type) > .brxe-container {
	justify-content: flex-start !important;
	align-items: flex-end !important;
}
#brx-content > section.has-bg-video:not(:first-of-type) > .brxe-container .brxe-heading {
	text-align: left !important;
}

/* Border-grow-in, per Adam's video feedback: every section sits full-bleed
   while it's the active one, and its frame grows IN as it recedes on any
   transition (either direction) — the reverse of the reference site's
   example, which grows a framed card OUT to full-bleed on scroll. Applies
   uniformly to every video section, not just the hero — originally hero-
   only, generalised once it was clear the effect should read consistently
   throughout.
   Rounding has to live inside clip-path's own `round <radius>` — once
   clip-path is present it fully defines the element's clip shape, so a
   separate `border-radius` property has no visible effect at all (tried
   that split first; the corners just went square). clip-path itself is
   still what keeps this layout-safe: a pure paint-time mask, not touching
   the box's own width/height/margin — unlike the two earlier attempts that
   fought with how Bricks measures/sizes the background video.
   Tied to the same 850ms/easing as the parallax transform slide (section-
   snap.js's DURATION/EASING) and started in the same style flush, so the
   frame grows in DURING the scroll transition itself rather than as a
   separate animation after the fact. Toggled by section-snap.js's
   prepareSectionFrame()/applySectionFrame(): grown for the section being
   scrolled TO, reset to full-bleed for the one being left.
   No `transition` set here in the stylesheet itself — section-snap.js sets
   it inline per-transition (see prepareSectionFrame's comment for why:
   `transition` has to be registered and reflow-flushed before the
   clip-path value changes, same as the transform, or the browser can skip
   straight to the end value on the very first change after a fresh page
   load). */
#brx-content > section.has-bg-video .bricks-background-video-wrapper {
	top: 0 !important;
	left: 0 !important;
	width: 100% !important;
	height: 100% !important;
	border-radius: 0;
	clip-path: inset(0px round 0px);
	overflow: hidden;
}

/* Hide the native scrollbar visually only — scroll functionality (used by
   section-snap.js's window.scrollTo) stays fully intact. This mirrors the
   original Salient site's immersive full-screen feel, which it achieved
   differently (overflow:hidden on body/html) because it doesn't use real
   document scroll at all — not an option here without breaking our snap. */
html {
	scrollbar-width: none; /* Firefox */
	-ms-overflow-style: none; /* old Edge/IE */
}
html::-webkit-scrollbar {
	display: none; /* Chrome/Safari/new Edge */
}

/* One-time fade-in on page load — matches the original Salient site's own
   technique (a fixed-duration CSS @keyframes animation, not scroll-linked).
   Opacity only, deliberately not touching transform/margin/size on this
   section given its history above. */
@keyframes hero-fade-in {
	from {
		opacity: 0;
	}
	to {
		opacity: 1;
	}
}
#brx-content > section.has-bg-video:first-of-type {
	animation: hero-fade-in 1.2s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}

#brx-content > section.has-bg-video:first-of-type video {
	will-change: transform;
}

#brx-content > section.has-bg-video:first-of-type .brxe-heading {
	will-change: transform, opacity;
}

/* Nav: fade + slide down once on load — same technique/timing as the
   original Salient site's #header-outer.entrance-animation.
   `forwards` fill-mode permanently leaves this element with a non-none
   `transform` after the animation completes (translateY(0) — visually a
   no-op, but the transform PROPERTY'S mere presence, any value including
   an identity translate, makes this element the containing block for any
   `position: fixed` descendant instead of the viewport). That broke
   Bricks' native mobile menu overlay/backdrop, nested inside this nav —
   it was sizing against this 64px-tall nav instead of the full viewport
   (reported: background images weren't dimmed while the mobile menu was
   open). nav-entrance-cleanup.js clears animation+transform once the
   entrance finishes (visually identical, since translateY(0) and no
   transform at all render the same) — see that file for why this is a JS
   fix, not just a CSS one. */
@keyframes nav-entrance-in {
	from {
		opacity: 0;
		transform: translateY(-100%);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}
nav.brxe-section {
	animation: nav-entrance-in 1.5s cubic-bezier(0.25, 1, 0.5, 1) forwards;
}

/* Scroll-snap on the front page is handled entirely by Bricks' own native
   per-page setting (set directly in the builder, not this repo) —
   deliberately no CSS overrides here. Several were tried and reverted
   (scroll-snap-type: proximity, scroll-snap-stop: always, a footer
   scroll-snap-align guard, overscroll-behavior-y: contain) while chasing
   footer-reachability and snap-commit issues; client asked to let Bricks
   own this fully instead rather than keep layering fixes. See git log
   around 2ce2f54 through 210009e for that history if any of it needs
   revisiting. section-snap.js (the old custom wheel-hijack/parallax
   version) is separately deactivated in functions.php. */

/* Video Card element — poster image + hover-loaded Vimeo embed */
.video-card {
	position: relative;
	/* <a> defaults to display:inline (unlike <div>), which broke the card's
	   layout when a Link is set and the root tag switches from div to a. */
	display: block;
	/* Its flex parent's default align-items:stretch only stretches the cross
	   axis (height), not width — and every child in here is position:absolute
	   (removed from flow), so with no explicit width this collapses to 0,
	   which then collapses .thumbnail-wrapper's aspect-ratio height too. */
	width: 100%;
	text-decoration: none;
	color: inherit;
}
/* Bricks' query loop leaves an empty duplicate/template .video-card
   sibling alongside each real rendered card — not always carrying the
   data-brx-loop-start attribute itself, so matching on that alone missed
   some of them. Since a real card always has children (thumbnail wrapper
   at minimum), any genuinely empty .video-card is always a bogus one —
   hide it. In a `display: grid` container an empty-but-present element
   still claims its own cell, which was pushing real cards into the wrong
   grid slots and causing the overlap/gap pattern on /work/. */
.video-card:empty {
	display: none !important;
}
/* Cards in the masonry grid are often taller/shorter than 16:9 (4:3 videos,
   SA Police, etc.), so the rounded corners must live on the card itself and
   the wrapper must fill it — otherwise the 16:9 wrapper stops short of the
   grid cell and the curve is lost on the outer edge. */
.video-card {
	height: 100%;
	border-radius: inherit;
	overflow: hidden;
}
.video-card .thumbnail-wrapper {
	position: relative;
	aspect-ratio: 16 / 9;
	width: 100%;
	height: 100%;
	border-radius: inherit;
	overflow: hidden;
	background: #000;
}
.video-card .poster {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* Same 1.1 zoom as the hover video's iframe below, so the poster and the
	   video line up and the swap on hover isn't a visible jump. Keep the two
	   values in sync. */
	transform: scale(1.1);
	z-index: 2;
	transition: opacity 0.25s ease;
}
.video-card .vimeo-embed-slot {
	position: absolute;
	inset: 0;
	z-index: 1;
	/* An <iframe> is a real embedded browsing context — it captures clicks
	   itself regardless of z-index, swallowing them before they can reach
	   the card's own link (whether that's the click-catcher or an outer
	   query-loop <a>). The video is muted/autoplay background only, so it
	   never needs to receive pointer interaction. */
	pointer-events: none;
}
.video-card .vimeo-embed-slot iframe {
	width: 100%;
	height: 100%;
	position: absolute;
	inset: 0;
	border: 0;
	/* Large cards letterbox the video with black bars; a slight zoom fills the
	   frame (wrapper's overflow:hidden crops the excess). */
	transform: scale(1.1);
}
.video-card.is-playing .poster {
	opacity: 0;
	pointer-events: none;
}
.video-card .click-catcher {
	position: absolute;
	inset: 0;
	z-index: 4;
	cursor: pointer;
}
.video-card .duration {
	position: absolute;
	bottom: 10px;
	right: 10px;
	z-index: 3;
	background: rgba(0, 0, 0, 0.75);
	color: #fff;
	font-family: monospace;
	font-size: 11px;
	padding: 3px 6px;
	border-radius: 4px;
}
.video-card .card-title {
	position: absolute;
	z-index: 3;
	margin: 0;
	padding: 0;
	pointer-events: none;
}
.video-card .card-title--bottom-left {
	bottom: 14px;
	left: 14px;
	right: 14px;
	text-align: left;
}
.video-card .card-title--bottom-right {
	bottom: 14px;
	left: 14px;
	right: 14px;
	text-align: right;
}
.video-card .card-title--top-left {
	top: 14px;
	left: 14px;
	right: 14px;
	text-align: left;
}
.video-card .card-title--top-right {
	top: 14px;
	left: 14px;
	right: 14px;
	text-align: right;
}
/* Single portfolio page — Bricks' video wrapper has a border radius +
   overflow:hidden, but the Vimeo iframe's own compositing layer can paint
   over the clip and show square corners. clip-path (matching the 30px
   radius) clips the iframe layer reliably. */
.single-portfolio .brxe-video {
	clip-path: inset(0 round 30px);
}
.single-portfolio .brxe-video iframe {
	border-radius: 30px;
}

/* Default for any project video whose ratio couldn't be looked up (e.g.
   YouTube): keep the box within the viewport height at 16:9, centred. The
   per-video ratio rule printed in <head> (functions.php) overrides this. */
.single-portfolio .brxe-video {
	width: min(100%, calc((100vh - 200px) * 1.7778));
	margin-inline: auto;
}

/* Single portfolio pages — same inherited Bricks min-width: 1425px bug as the
   footer/Contact rules above: the video section can't shrink below 1425px, so
   in a narrower browser window the page overflows sideways and the video is
   cut off. Let it shrink with the window; the video box inside is already
   capped by width:100% / the viewport-height clamp. */
.single-portfolio main .brxe-section,
.single-portfolio main .brxe-container {
	min-width: 0 !important;
	max-width: 100%;
}

/* Single portfolio — title + description row under the video: scale the type
   with the window, and stack the two columns once there isn't room for both
   side by side. (#brxe-8d7486 = the row, #brxe-c3a66b = title, set in the
   Portfolio Single template.) */
.single-portfolio #brxe-c3a66b {
	font-size: clamp(22px, 2.6vw, 35px);
}
.single-portfolio #brxe-8d7486 .brxe-text,
.single-portfolio #brxe-8d7486 .brxe-text p {
	font-size: clamp(14px, 1.35vw, 18px);
}
@media (max-width: 900px) {
	.single-portfolio #brxe-8d7486 {
		flex-direction: column;
		gap: 24px;
	}
	.single-portfolio #brxe-8d7486 > * {
		width: 100%;
	}
}

/* Title/description row follows the video's width (default 16:9; the
   per-video ratio rule printed in <head> overrides this), so the two stay
   aligned when the video shrinks to fit the screen height. */
.single-portfolio #brxe-8d7486 {
	width: min(100%, calc((100vh - 200px) * 1.7778));
	margin-inline: auto;
}

/* Contact page — the two address blocks (#brxe-e75787 = fadeInLeft,
   #brxe-5f4f9a = fadeInRight, set as Bricks interactions in the builder)
   slide in horizontally from off-screen. On iPhone that pushes content past
   the viewport edge (the sideways drag, then content sliding/cut off once
   overflow was clipped). On phones/tablets use a plain fade instead. */
@media (max-width: 991px) {
	#brxe-e75787,
	#brxe-5f4f9a {
		/* No animation at all here: swapping in a different keyframe name
		   left them stuck at their starting opacity: 0 (invisible), so just
		   show them. */
		animation: none !important;
		transform: none !important;
		opacity: 1 !important;
		visibility: visible !important;
	}
}

/* Contact page on phones/tablets — explicit single-column layout. iPhone
   (WebKit) laid the two address blocks out wider than the screen (they sat
   off to the right and the page could be dragged sideways) even though
   desktop/Android Chrome stack them correctly, so don't rely on the
   builder's wrap + percentage widths here. Overflow is contained to the
   Contact sections only (not html/body — clipping the root hid the content
   on iOS). #brxe-0d98f4 = address section, #brxe-19e8da = row,
   #brxe-e75787 / #brxe-5f4f9a = Adelaide / Melbourne blocks. */
@media (max-width: 991px) {
	#brxe-0d98f4,
	#brxe-08f32e {
		width: 100% !important;
		max-width: 100% !important;
		min-width: 0 !important;
		box-sizing: border-box;
		overflow-x: hidden;
	}
	#brxe-19e8da {
		display: flex;
		flex-direction: column;
		flex-wrap: nowrap;
		align-items: center;
		width: 100%;
		max-width: 100%;
		min-width: 0;
		column-gap: 0;
		box-sizing: border-box;
	}
	#brxe-19e8da > #brxe-e75787,
	#brxe-19e8da > #brxe-5f4f9a {
		width: 100%;
		max-width: 100%;
		min-width: 0;
		flex: 0 0 auto;
		box-sizing: border-box;
	}
}

/* Contact page — ROOT CAUSE of the "address off to the right / page draggable
   on iPhone" bug. The address section (#brxe-0d98f4) is nested INSIDE the
   title section (#brxe-08f32e), which the builder sets to
   flex-direction: column + flex-wrap: wrap. When the content is taller than
   that section's height (short screens, e.g. iPhone with browser toolbars),
   the address section wraps into a NEW COLUMN to the right instead of
   continuing below. Never wrap; let it grow downward. Also drop the
   overflow-x: hidden added above — it forced a scroll container here. */
#brxe-08f32e {
	flex-wrap: nowrap !important;
	height: auto !important;
}
@media (max-width: 991px) {
	#brxe-0d98f4,
	#brxe-08f32e {
		overflow-x: visible !important;
	}
}

/* Footer — keep breathing room at the sides: the acknowledgement-of-country
   paragraph (#brxe-9ab90c) ran edge to edge on phones. */
#brxe-f8777b #brxe-9ab90c,
#brxe-9ab90c {
	box-sizing: border-box;
	padding-inline: clamp(20px, 6vw, 60px);
}

/* Global footer section (#brxe-f8777b) — widen the side gutters so the
   footer content isn't tight to the screen edges (was a flat 25px). */
#brxe-f8777b {
	padding-inline: clamp(25px, 5vw, 60px) !important;
	box-sizing: border-box;
}
