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

/* =========================================================================
   Thick Hunnies Brand Utilities
   Items from the brand guide (assets/thick-hunnies-brand-guide.html) that
   ACSS does not auto-generate. ACSS owns the color/spacing/type tokens —
   these compose them into the brand-spec components and override the
   ACSS defaults that the brand contradicts.
   ========================================================================= */

/* --- Type — the one heading property ACSS has no setting for ---------
   The brand type ladder (sizes, line-heights, letter-spacing, H6 eyebrow
   treatment) lives in the ACSS Dashboard's per-level Typography overrides
   as of 2026-09-14 — see docs/acss-token-map.md. ACSS 3.3.6 exposes
   h1/h2/h3/h5/h6-line-height but NOT h4-line-height (03), so H4's 1.25
   is the single value that has to live here.
   ----------------------------------------------------------------------- */
h4 {
	line-height: 1.25;
}

/* --- Token-level overrides (brand guide §6.5) --------------------------
   ACSS exposes button + link styling as CSS custom properties; overriding
   them here lets ACSS's own .btn / link rules pick up the brand spec
   without re-declaring the underlying selectors.
   ----------------------------------------------------------------------- */
:root {
	/* Pill buttons */
	--btn-radius: 9999px;
	--btn-padding-block: 0.85rem;
	--btn-padding-inline: 1.75rem;
	/* --btn-font-weight already 600 from ACSS dashboard */

	/* Cherry links (accent), Hot Candy on hover */
	--link-color: var(--accent);
	--link-color-hover: var(--primary);
}

/* --- Section surface tints (brand guide §6.5) --------------------------
   Soft tinted section backgrounds via ACSS's auto-generated *-ultra-light
   shades. Pair with ACSS .section-p-* spacing utilities.
   ----------------------------------------------------------------------- */
.section-pink      { background: var(--primary-ultra-light); }
.section-lilac     { background: var(--info-ultra-light); }
.section-mint      { background: var(--success-ultra-light); }
.section-tangerine { background: var(--warning-ultra-light); }
.section-cream     { background: var(--base-ultra-light); }

/* --- Eyebrow label (brand guide §3.2) ----------------------------------
   Small uppercase Cherry label. Use for non-heading eyebrows
   (<span class="eyebrow">…</span>) — H6 already gets the eyebrow
   treatment from ACSS dashboard config.
   ----------------------------------------------------------------------- */
.eyebrow {
	display: inline-block;
	font-family: var(--text-font-family);
	font-size: var(--text-s);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--accent);
	margin-bottom: var(--space-s);
}

/* --- Lead paragraph (brand guide §3.2) ---------------------------------
   Larger intro paragraph below an H1/H2. Slightly muted text vs. body so
   the heading still owns the eye.
   ----------------------------------------------------------------------- */
.lead {
	font-size: var(--text-xxl);
	line-height: 1.5;
	color: var(--neutral-dark);
	max-width: 65ch;
	margin-top: var(--space-m);
}

/* --- Badges (brand guide §5.3) -----------------------------------------
   Pill badges using surface-tint backgrounds and dark-shade text. Use
   `.badge` plus a variant; .badge--accent renders solid Cherry on Cream.
   Named .badge (not .tag) to avoid collision with Bricks' internal `tag`
   class added to every linked/wrapped image element. (Bricks
   includes/elements/image.php sets class="tag" on the link/picture/
   figure wrapper as a structural marker — using .tag here would leak
   onto every wrapped image site-wide.)
   ----------------------------------------------------------------------- */
.badge {
	display: inline-block;
	padding: 0.3rem 0.85rem;
	border-radius: 9999px;
	font-size: var(--text-xs);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	font-family: var(--text-font-family);
	border: 1px solid transparent;
}
.badge--primary {
	background: var(--primary-ultra-light);
	color: var(--accent);
	border-color: var(--primary-light);
}
.badge--accent {
	background: var(--accent);
	color: var(--base);
}
.badge--info {
	background: var(--info-ultra-light);
	color: var(--info-dark);
	border-color: var(--info-light);
}
.badge--success {
	background: var(--success-ultra-light);
	color: var(--success-dark);
	border-color: var(--success-light);
}
.badge--warning {
	background: var(--warning-ultra-light);
	color: var(--warning-dark);
	border-color: var(--warning-light);
}
.badge--neutral {
	background: var(--neutral-ultra-light);
	color: var(--neutral-dark);
	border-color: var(--neutral-light);
}

/* --- Callouts (brand guide §5.4) ---------------------------------------
   Soft alert boxes with a left rule and tinted background. Pair with
   <strong> as the leading label.
   ----------------------------------------------------------------------- */
.callout {
	margin-top: var(--space-m);
	padding: var(--space-m);
	background: var(--primary-ultra-light);
	border-left: 3px solid var(--primary);
	border-radius: 0 var(--radius-xxl) var(--radius-xxl) 0;
	font-size: var(--text-m);
}
.callout strong {
	display: block;
	margin-bottom: 4px;
	color: var(--accent);
	font-weight: 700;
}
.callout--info {
	background: var(--info-ultra-light);
	border-left-color: var(--info);
}
.callout--info strong { color: var(--info-dark); }
.callout--warning {
	background: var(--warning-ultra-light);
	border-left-color: var(--warning);
}
.callout--warning strong { color: var(--warning-dark); }

/* --- Italic lockout (brand guide §3.3) ---------------------------------
   System loads no italic font weights. Render emphasis via weight only.
   ----------------------------------------------------------------------- */
em,
i {
	font-style: normal;
	font-weight: 600;
}

/* =========================================================================
   Video Grid + Card
   Reusable across archive, taxonomy, related, search. Class names match
   the Bricks Global Classes (BEM-style) registered on those elements.
   ========================================================================= */

/* --- Grid: responsive column count + explicit gap --- */
.video-grid__wrapper {
	display: grid;
	grid-template-columns: var(--grid-1);
	gap: var(--space-m);
}

@media (min-width: 768px) {
	.video-grid__wrapper { grid-template-columns: var(--grid-2); }
}

@media (min-width: 992px) {
	.video-grid__wrapper { grid-template-columns: var(--grid-3); }
}

@media (min-width: 1366px) {
	.video-grid__wrapper { grid-template-columns: var(--grid-4); }
}

/* --- Performer profile+videos grid: same responsive steps, capped at 3 ---
   Deliberately no 1366px->4 rule — the brief calls for a fixed 3x3 (profile
   card + up to 8 videos), not a grid that keeps widening on large screens. */
.performer-videos__grid {
	display: grid;
	grid-template-columns: var(--grid-1);
	gap: var(--space-m);
}

@media (min-width: 768px) {
	.performer-videos__grid { grid-template-columns: var(--grid-2); }
}

@media (min-width: 992px) {
	.performer-videos__grid { grid-template-columns: var(--grid-3); }
}

/* --- Performer archive grid: same escalating steps as .video-grid__wrapper,
   including the 1366px->4 column step (no fixed-count brief here, unlike
   the profile page's 3x3 grid above). --- */
.performer-grid__wrapper {
	display: grid;
	grid-template-columns: var(--grid-1);
	gap: var(--space-m);
}

@media (min-width: 768px) {
	.performer-grid__wrapper { grid-template-columns: var(--grid-2); }
}

@media (min-width: 992px) {
	.performer-grid__wrapper { grid-template-columns: var(--grid-3); }
}

@media (min-width: 1366px) {
	.performer-grid__wrapper { grid-template-columns: var(--grid-4); }
}

/* --- Performer archive card: hover lift + photo zoom, same "subtle hover"
   language as .video-card (see that block below) — lift/shadow numbers
   match exactly, for one consistent card feel site-wide. No stretched-link
   trick needed here at all: the photo's own `link` already covers the
   entire clickable area (no separate title/description competing for
   space), and the overlaid name has its own independent link to the same
   destination — nothing to stretch, nothing to fight over. */
.performer-archive-card {
	transition: transform .2s ease, box-shadow .2s ease;
}

.performer-archive-card:hover {
	transform: translateY(-2px);
	box-shadow: 0 6px 18px rgba(42, 20, 24, .08);
}

.performer-archive-card__image {
	transition: transform .3s ease;
}

.performer-archive-card:hover .performer-archive-card__image {
	transform: scale(1.03);
}

/* --- Card: override the pure-white bg, set up for stretched link + hover ---
   `article.video-card` bumps specificity above the Bricks Global Class output
   (which uses the bare `.video-card` selector) so the bg override wins
   regardless of inline-style load order. */
article.video-card {
	background-color: var(--white);
}

.video-card {
	position: relative;
	transition:
		transform .2s ease,
		box-shadow .2s ease,
		border-color .2s ease;
}

/* Stretched link — the image's <a> and the title's <a> each cover the
   whole card, so a click anywhere lands on the video. Deliberately scoped
   to just these two rather than a blanket `.video-card a[href]::after`:
   that broader selector stretched EVERY anchor in the card, and once the
   card grew a real inner link (Performers, added 2026-08-30) the
   later-in-DOM performer anchor painted its own full-card stretch on top
   of the video's, silently sending every click on a performer-having card
   to the performer instead of the video (`CLAUDE.md` → Video Card —
   Performers Display). Scoping to the two intended anchors is the fix;
   any future inner link added to the card is safe by default instead of
   needing its own exclusion. This is a paywalled member site, so the
   duplicate-link-per-card tradeoff against strict a11y purism is accepted
   here — see `01`'s clickable-card convention for the visible-anchor
   default this reverts to. */
.video-card__img[href]::after,
.video-card__heading a[href]::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

/* Both stretched overlays above cover the ENTIRE card, not just their own
   anchor's visible footprint — `inset: 0` is relative to `.video-card`
   (the nearest `position: relative` ancestor), so they blanket the
   performer link's area too despite living nowhere near it in the DOM.
   Scoping the stretched rule to two anchors (previous block) fixed which
   link wins when they overlap; it does nothing about a plain-flow element
   sitting underneath either overlay having no way to win a click at all.
   Lifting the performer link into its own stacking context above them
   (z-index: 2) is what makes it independently clickable again — this is
   the standard "elevate the secondary link above a stretched-link
   overlay" pattern, not a variant of the scoping fix. */
.video-card__performer-link {
	position: relative;
	z-index: 2;
}

/* Hover / focus feedback --- */
.video-card:hover {
	transform: translateY(-2px);
	box-shadow: 0 6px 18px rgba(42, 20, 24, .08);
}

.video-card:focus-within {
	outline: 2px solid var(--primary);
	outline-offset: 2px;
}

/* Image subtly zooms on card hover. `overflow: hidden` is already on
   .video-card via its Bricks Global Class. */
.video-card__img {
	transition: transform .3s ease;
}

.video-card:hover .video-card__img {
	transform: scale(1.03);
}

/* Play-icon overlay — sits on the poster area only (aspect 16/9, top of card),
   fades in on hover. `pointer-events: none` keeps the stretched-link click
   target intact. SVG is inline via data URI — no extra HTTP request, no
   Media-Library coupling. Cream circle + Espresso triangle, matching brand.
   Tint rgba uses Espresso (42 20 24) RGB to align with --neutral. */
.video-card::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	aspect-ratio: 16 / 9;
	background-color: rgba(42, 20, 24, .35);
	background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%23FBF6EE' fill-opacity='.95'/><path d='M10 8v8l6-4z' fill='%232A1418'/></svg>");
	background-position: center;
	background-repeat: no-repeat;
	background-size: 56px auto;
	opacity: 0;
	transition: opacity .25s ease;
	pointer-events: none;
	z-index: 2;
}

.video-card:hover::before {
	opacity: 1;
}

/* --- Line-clamp: lock card heights so rows stay even ---
   Heading was clamped to 1 line, which ellipsised any title longer than the
   card width. Raised to 2 on 2026-09-15 so longer titles wrap instead of
   truncating. There is no text-level limit anywhere — the elements render a
   bare {post_title} — so this clamp is the only thing governing it, and the
   card's global class is shared by all five copies of the card markup
   (archive, taxonomy, related grid, performer grid, homepage). */
.video-card__heading {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
}

.video-card__description {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* =========================================================================
   Home Notice — dismissable banner between header and Latest Release
   Hide-when-content-empty is handled by a Bricks Condition on the section.
   Dismissal is JS-driven (home-notice.js), keyed by a hash of the visible
   content, so updating the text auto-re-shows the banner for everyone.
   ========================================================================= */

.home-notice {
	padding-block: var(--space-xs);
	background-color: var(--primary-light-trans-10);
	color: var(--neutral);
}

.home-notice__container {
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-m);
}

.home-notice__content {
	flex: 1 1 auto;
	font-family: "JetBrains MOno";
	font-weight: 500;
	font-size: var(--text-s);
	line-height: 1.5;
	color: var(--neutral);
}

.home-notice__content p {
	margin: 0;
}

.home-notice__content p + p {
	margin-top: var(--space-xs);
}

.home-notice__content a {
	color: var(--primary);
	text-decoration: underline;
	text-underline-offset: 2px;
}

.home-notice__close {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	padding: 0;
	color: var(--neutral);
	background: transparent;
	border: 0;
	border-radius: var(--radius-xs);
	cursor: pointer;
	transition: color .15s ease, background .15s ease;
}
.home-notice__close:hover {
	color: var(--primary);
}
.home-notice__close:focus-visible {
	outline: 2px solid var(--primary);
	outline-offset: 2px;
}

/* =========================================================================
   Video Single — Info section responsive stack
   The 3:1 two-column layout (title/description | Categories aside) is set
   via a Bricks Global Class (.video-info__container). On narrow viewports
   the right column squeezes until the taxonomy values truncate off-screen.
   Stack at ≤767px. Doubled selector beats Bricks' inline CSS cascade.
   ========================================================================= */

@media (max-width: 767px) {
	.video-info__container.video-info__container {
		grid-template-columns: 1fr;
		grid-gap: var(--space-m);
	}
}

/* =========================================================================
   Browse Filter + Active Filters + Empty State
   Single consolidated block. Uses doubled class selectors (e.g.
   `.browse-filter.browse-filter` or compound selectors) to bump specificity
   above any Bricks or ACSS rule. All styling lives here — Bricks Global
   Classes for browse-* should remain empty.
   ========================================================================= */

/* ----- FILTER BAR CONTAINER ----- */

.browse-filter {
	position: sticky;
	top: 0;
	z-index: 10;
	background-color: var(--base);
	border-bottom: 1px solid var(--primary-light);
}

/* ----- PAGE HEADER (shared with video-archive + video-taxonomy) ----- */

/* On narrow viewports the "Member Videos" h1 and its "26 Videos" count
   share a single flex row that wraps mid-line — awkward. Stack them
   vertically instead at ≤767px so each gets its own line. */
@media (max-width: 767px) {
	/* Doubled class name — Bricks emits inline-style CSS for Global Classes
	   later in the cascade than this external sheet, so equal-specificity
	   rules lose. Doubling raises specificity to (0,2,0) and wins cleanly. */
	.page-header__heading-wrapper.page-header__heading-wrapper {
		flex-direction: column;
		align-items: flex-start;
	}
}

/* ----- FORM GRID (3 cols: search | facets | clear) ----- */
/* Compound selector .browse-filter .browse-filter__form beats Bricks 
   .brxe-block at 0-2-0 > 0-1-0 specificity. */

.browse-filter .browse-filter__form {
	display: grid;
	grid-template-columns: 2fr auto auto;
	gap: var(--space-m);
	align-items: center;
	width: 100%;
	flex-direction: unset;
}

/* Prevent grid items from stretching to the cell's full height —
   when facets wrap to 2 rows, the search was inflating with them. */
.browse-filter .browse-filter__form > * {
	align-self: center;
}

@media (max-width: 991px) {
	.browse-filter .browse-filter__form {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 767px) {
	.browse-filter .browse-filter__form {
		grid-template-columns: 1fr auto;
	}
}

/* ----- SEARCH INPUT (wrapper + inner Bricks wrapper + input) ----- */

.browse-filter .browse-filter__search {
	position: relative;
	width: 100%;
	flex-direction: unset;
}

.browse-filter__search-input,
.browse-filter__search-input.brxe-filter-search {
	position: relative;
	width: 100%;
	background-color: var(--primary-ultra-light);
	border: 1px solid var(--primary-light);
	border-radius: var(--radius-m);
	overflow: hidden;
}

.browse-filter__search-input:focus-within,
.browse-filter__search-input.brxe-filter-search:focus-within {
	border-color: var(--primary);
	outline: 2px solid var(--primary);
	outline-offset: 2px;
}

.browse-filter__search-input input[type="search"] {
	box-sizing: border-box;
	width: 100%;
	height: 44px;
	padding-block: 0;
	padding-inline: calc(var(--space-m) * 2.5) var(--space-m);
	font-size: var(--text-s);
	line-height: 44px;
	/* --base is the page canvas (Cream), not a text colour. It read as
	   light-on-light (1.02:1) — inherited from the clone source, whose
	   --base was near-black. */
	color: var(--neutral);
	background-color: transparent;
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%232A1418' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: left var(--space-m) center;
	border: 0;
	outline: none;
	font-family: inherit;
}

.browse-filter__search-input input[type="search"]::placeholder {
	/* --base-semi-dark is an auto-derived shade of warm Cream and resolves
	   to #916622, a mustard. Not in the palette. */
	color: var(--neutral-trans-70);
}

/* Hide Bricks' auto-injected search-clear icon */
.browse-filter__search-input .icon {
	display: none !important;
}

/* ----- FACETS GROUP (horizontal flex) ----- */

.browse-filter .browse-filter__facets {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: var(--space-s);
	width: auto;
	align-items: center;
}

@media (max-width: 991px) {
	.browse-filter .browse-filter__facets {
		justify-content: flex-start;
	}
}

@media (max-width: 767px) {
	.browse-filter .browse-filter__facets {
		display: none;
	}
}

/* Individual facet wrapper (holds a select) */
.browse-filter .browse-filter__facet {
	position: relative;
	width: auto;
	flex-direction: unset;
}

/* Hide the facet that matches the current taxonomy archive.
   On /body-type/curvy/ the Body Type dropdown is redundant and would
   clash with the path-segment filter if used. Piggybacks on WP's native
   tax-<slug> body class (added automatically by body_class() on term
   archives). Covers desktop + sheet facets in one go.
   Keep this list in step with ms_video_taxonomies() in the plugin. */
body.tax-body-type .browse-filter__facet--body-type,
body.tax-bust-size .browse-filter__facet--bust-size,
body.tax-scene-finish .browse-filter__facet--scene-finish,
body.tax-ethnicity .browse-filter__facet--ethnicity {
	display: none;
}

/* The actual <select> element */
.browse-filter .browse-filter__facet-select,
.browse-filter select.browse-filter__facet-select {
	appearance: none;
	-webkit-appearance: none;
	height: 44px;
	padding: 0 calc(var(--space-m) * 2) 0 var(--space-s);
	font-size: var(--text-s);
	font-family: inherit;
	color: var(--base);
	background-color: var(--primary);
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23FBF6EE' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right var(--space-m) center;
	background-size: 18px 18px;
	border: 1px solid var(--primary);
	border-radius: var(--radius-circle);
	cursor: pointer;
	min-width: 110px;
}

.browse-filter .browse-filter__facet-select:focus {
	outline: 2px solid var(--primary-dark);
	outline-offset: 2px;
	border-color: var(--primary-dark);
}

/* Active state — Bricks marks the empty "All" option with class="placeholder";
   any selected option that isn't the placeholder means the filter is active. */
.browse-filter .browse-filter__facet-select:has(option:checked:not(.placeholder)) {
	background-color: var(--primary);
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%232A1418' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-size: 18px 18px;
	color: var(--text-light);
	border-color: var(--primary);
}

/* ----- CLEAR-ALL TEXT LINK (filter bar) ----- */

.browse-filter .browse-filter__clear {
	font-size: var(--text-s);
	font-weight: 500;
	color: var(--neutral);
	text-decoration: underline;
	text-underline-offset: 3px;
	white-space: nowrap;
	padding: var(--space-xs) var(--space-s);
	width: auto;
	transition: color 0.15s ease;
	background-color: var(--neutral-ultra-light);
	border-radius: var(--radius-circle);
}

.browse-filter .browse-filter__clear:hover {
	color: var(--primary);
}

@media (max-width: 767px) {
	.browse-filter .browse-filter__clear {
		display: none;
	}
}

/* ----- MOBILE TOGGLE ----- */

.browse-filter .browse-filter__mobile-toggle {
	display: none;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	gap: var(--space-xs);
	width: auto;
	/* Match the search input's visual weight — 44px tall, modest padding,
	   body-font size instead of inheriting a display-size default. */
	height: 44px;
	padding: 0 var(--space-m);
	font-size: var(--text-s);
	font-weight: 500;
	color: var(--neutral);
	background-color: var(--primary-ultra-light);
	border: 1px solid var(--primary-light);
	border-radius: var(--radius-m);
}

.browse-filter .browse-filter__mobile-toggle:hover {
	border-color: var(--primary);
	color: var(--primary);
}

/* Scope the icon size — the SVG in the button was inheriting Bricks' default
   button-icon sizing, which paints a ~40px hamburger on mobile. */
.browse-filter .browse-filter__mobile-toggle svg {
	width: 18px;
	height: 18px;
	flex-shrink: 0;
}

@media (max-width: 767px) {
	.browse-filter .browse-filter__mobile-toggle {
		display: inline-flex;
	}
}

/* ----- BOTTOM SHEET (mobile modal) ----- */

.browse-filter__sheet-overlay {
	display: none;
	position: fixed;
	inset: 0;
	background-color: var(--black-trans-60);
	z-index: 50;
	opacity: 0;
	transition: opacity 0.25s ease;
}

.browse-filter__sheet-overlay[data-open="true"] {
	display: block;
	opacity: 1;
}

.browse-filter__sheet {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 51;
	height: 85vh;
	max-height: 85vh;
	background-color: var(--base-ultra-light);
	border-top-left-radius: var(--radius-xl);
	border-top-right-radius: var(--radius-xl);
	box-shadow: 0 -8px 32px var(--black-trans-20);
	transform: translateY(100%);
	transition: transform 0.3s ease;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.browse-filter__sheet[data-open="true"] {
	transform: translateY(0);
}

.browse-filter__sheet .browse-filter__sheet-handle {
	display: flex;
	flex-direction: row;
	justify-content: center;
	align-items: center;
	padding: var(--space-s) 0 var(--space-xs);
	flex-shrink: 0;
	width: 100%;
}

.browse-filter__sheet-handle-bar {
	width: 40px;
	height: 4px;
	background-color: var(--primary-light);
	border-radius: var(--radius-xl);
}

.browse-filter__sheet .browse-filter__sheet-header {
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: space-between;
	padding: var(--space-s) var(--space-l) var(--space-m);
	border-bottom: 1px solid var(--primary-light);
	flex-shrink: 0;
	width: 100%;
}

.browse-filter__sheet-title {
	font-size: var(--h3);
	font-weight: 600;
	color: var(--neutral);
	margin: 0;
}

.browse-filter__sheet-close {
	display: inline-flex;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	background: transparent;
	border: 0;
	border-radius: var(--radius-50);
	color: var(--neutral-trans-70);
	cursor: pointer;
}

.browse-filter__sheet-close:hover {
	background-color: var(--primary-ultra-light);
	color: var(--neutral);
}

.browse-filter__sheet-search {
	padding: var(--space-m) var(--space-l);
	background-color: var(--base-ultra-light);
	border-bottom: 1px solid var(--primary-light);
	flex-shrink: 0;
	width: 100%;
}

.browse-filter__sheet-body {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: var(--space-l);
	width: 100%;
}

.browse-filter__sheet-facets {
	display: flex;
	flex-direction: column;
	gap: var(--space-m);
	width: 100%;
}

.browse-filter__sheet-facet {
	display: flex;
	flex-direction: column;
	width: 100%;
}

.browse-filter__sheet-facet-label {
	display: block;
	font-family: 'JetBrains Mono', ui-monospace, monospace;
	font-size: var(--text-xs);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--neutral-trans-70);
	margin-bottom: var(--space-xs);
}

.browse-filter__facet-select--in-sheet {
	width: 100%;
	font-size: var(--text-m);
	padding-block: var(--space-xs);
}

.browse-filter__sheet .browse-filter__sheet-footer {
	display: flex;
	flex-direction: row;
	gap: var(--space-s);
	padding: var(--space-m) var(--space-l);
	border-top: 1px solid var(--primary-light);
	background-color: var(--base-ultra-light);
	flex-shrink: 0;
	width: 100%;
}

.browse-filter__sheet-footer-clear {
	flex: 0 0 auto;
	width: auto;
	padding: var(--space-s) var(--space-m);
	font-size: var(--text-m);
	font-weight: 500;
	color: var(--neutral-trans-70);
	background: transparent;
	border: 1px solid var(--primary-light);
	border-radius: var(--radius-m);
	cursor: pointer;
}

.browse-filter__sheet-footer-clear:hover {
	color: var(--primary);
	border-color: var(--primary);
}

.browse-filter__sheet-footer-apply {
	flex: 1 1 auto;
	width: auto;
}

/* ----- ACTIVE-FILTER CHIPS SECTION ----- */

.browse-active-filters {
	background-color: var(--base-ultra-light);
	border-bottom: 1px solid var(--primary-light);
}

/* Hide the whole section when there are no active filter chips to show.
   Bricks' own CSS hides the empty <ul>, but the section's "Active:" label
   and "Clear All Filters" button stay visible, creating an empty band.
   `:has()` re-evaluates when AJAX filter changes add/remove <li> children,
   so this stays accurate without JS. */
.browse-active-filters:has(.browse-active-filters__list:empty) {
	display: none;
}

.browse-active-filters .browse-active-filters__container {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-xs);
}

.browse-active-filters__label {
	font-family: 'JetBrains Mono', ui-monospace, monospace;
	font-size: var(--text-xs);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--neutral-trans-70);
	margin: 0 var(--space-xs) 0 0;
	width: auto;
}

.browse-active-filters .browse-active-filters__list {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: var(--space-xs);
	list-style: none;
	margin: 0;
	padding: 0;
	width: auto;
}

.browse-active-filters__item {
	display: inline-flex;
	width: auto;
}

.browse-active-filters__chip {
	display: inline-flex;
	flex-direction: row;
	align-items: center;
	gap: var(--space-xs);
	width: auto;
	min-width: 80px;
	padding: var(--space-xs) var(--space-s);
	font-size: var(--text-s);
	color: var(--text-light);
	background-color: var(--secondary);
	border: 0;
	border-radius: var(--radius-xl);
	cursor: pointer;
	transition: background-color 0.15s ease;
}

.browse-active-filters__chip:hover {
	background-color: var(--primary);
}

.browse-active-filters__chip-x {
	display: inline-flex;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	width: 14px;
	height: 14px;
}

.browse-active-filters__clear-all {
	margin-left: auto;
	width: auto;
	padding: var(--space-xs) var(--space-s);
	font-size: var(--text-s);
	font-weight: 500;
	color: var(--neutral-trans-70);
	background: transparent;
	border: 0;
	cursor: pointer;
	text-decoration: underline;
	text-underline-offset: 3px;
	transition: color 0.15s ease;
}

.browse-active-filters__clear-all:hover {
	color: var(--primary);
}

@media (max-width: 767px) {
	.browse-active-filters__clear-all {
		margin-left: 0;
		width: 100%;
		text-align: left;
	}
}

/* ----- EMPTY STATE -----
   Show .browse-empty only when the video grid returned 0 results.
   Bricks always emits a .brx-query-trail element inside the loop wrapper
   carrying data-max-pages — it's literally "0" when no posts matched.
   :has() re-evaluates when Bricks AJAX-swaps the grid innerHTML on filter
   change, so this stays accurate without JS.

   NOTE: we intentionally do NOT hide .video-grid itself — Bricks' JS binds
   to that element for filter AJAX, and display:none on an ancestor would
   break event delegation to the filter-select elements. Collapsing the
   empty grid's visible footprint is handled by .video-grid__wrapper:empty
   below instead. */
.browse-empty {
	display: none;
}

.video-grid:has(.brx-query-trail[data-max-pages="0"]) ~ .browse-empty {
	display: block;
}

/* Collapse the grid's visible padding when the loop is empty — the
   .video-grid__wrapper (the <ul>) has no <li> children in that case. */
.video-grid__wrapper:empty {
	display: none;
}

.browse-empty__heading {
	font-size: var(--h2);
	font-weight: 600;
	color: var(--neutral);
}

.browse-empty__text {
	font-size: var(--text-m);
	color: var(--neutral-trans-70);
}

.browse-empty__action {
	display: inline-block;
	width: auto;
}

/* ----- REDUCED MOTION ----- */

@media (prefers-reduced-motion: reduce) {
	.browse-filter__sheet-overlay,
	.browse-filter__sheet,
	.browse-active-filters__chip,
	.browse-active-filters__clear-all,
	.browse-filter .browse-filter__clear {
		transition: none;
	}
}

/* ==========================================================================
   HEADER — MOBILE OFFCANVAS (BricksExtras)                       2026-08-11
   ==========================================================================
   Below 991px the header collapses to logo + search + burger, and the main
   nav plus the account links move into a right-side offcanvas panel.

   This replaces the Bricks NATIVE mobile menu, which is retired rather than
   restyled: its toggle icon was a chevron-down (reads as "expand a dropdown",
   not "open the menu"), and its panel was styled in --white / --black /
   --accent, none of which belong to the Thick Hunnies 8-colour system.

   991px is deliberate — it matches the breakpoint the native mobile menu
   already used (nav-menu `mobileMenu: tablet_portrait`), so the point at
   which navigation changes shape is unchanged for anyone used to the site.
   ========================================================================== */

/* The burger is a mobile-only affordance. */
/* ⚠️ Every visibility rule below uses the DOUBLED-CLASS trick (`.foo.foo`).
   That is not stylistic — a single class loses here. BricksExtras ships
   `.brxe-xburgertrigger { display: inline-flex }` at (0,1,0), and
   `x-burger-trigger-css` enqueues AFTER `bricks-child-css`, so at equal
   specificity the plugin wins on source order and the burger stayed visible
   at every width. `bricks-style-manager-css` also loads after the child
   theme, so the same trap applies to the Bricks global classes below.
   Doubling costs one selector and lifts these to (0,2,0), which beats both
   without reaching for !important. See 03 — "Doubled-class selectors beat
   Bricks inline CSS cascade" and "author rules with equal specificity lose
   to @layer bricks framework rules". */

.header__burger.header__burger {
	display: none;
}

@media (max-width: 991px) {
	.header__burger.header__burger {
		display: flex;
	}

	/* Retire the native mobile menu wholesale — hiding the element also hides
	   its chevron toggle, its slide-out panel and its overlay in one go. */
	.header__menu.header__menu {
		display: none;
	}

	/* The utility bar's two links now live in the panel, so it stops eating
	   vertical space above the fold. */
	.header-utility.header-utility {
		display: none;
	}
}

/* The offcanvas is mobile-only. BE renders the panel markup at every width;
   without this the backdrop and panel remain reachable on desktop, where the
   burger that opens them is hidden. */
@media (min-width: 992px) {
	.header__offcanvas.header__offcanvas {
		display: none;
	}
}

/* =========================================================================
   Homepage — transparent header over the first section
   =========================================================================
   Scoped entirely to body.home; every other page keeps the header exactly
   as built (static, solid Cream, in normal document flow) with zero change.

   The utility bar no longer exists anywhere — removed from the Header
   template itself, site-wide, not just hidden here. The header search
   was removed from the template too (2026-09-06), so the bar is
   logo + nav + Login + Join everywhere.

   The header starts at position:absolute; top:0 (removed from flow, so
   the section right after it renders underneath instead of being pushed
   down) with a transparent fill and light-on-dark nav-link colors. Once
   the user scrolls past the header's own height, .is-scrolled swaps it to
   position:fixed with the normal solid styling — a standard
   overlay-then-sticky pattern, not a site-wide header change. */
body.home .header {
	position: absolute;
	top: 0;
	inset-inline: 0;
	z-index: 100;
	background-color: transparent;
	border-bottom-color: transparent;
	transition: background-color 0.25s ease, border-color 0.25s ease;
}
body.home .header.is-scrolled {
	position: fixed;
	top: 0;
	background-color: var(--base);
	border-bottom-color: var(--neutral-ultra-light);
}

/* The outlined Login pill (header__login) sits beside the nav and needs the
   same light treatment over the hero video; the filled Join pill does not. */
body.home .header:not(.is-scrolled) .header__login {
	color: var(--base);
	border-color: var(--base);
}
body.home .header:not(.is-scrolled) .header__login:hover,
body.home .header:not(.is-scrolled) .header__login:focus-visible {
	color: var(--primary-light);
	border-color: var(--primary-light);
}
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li > a,
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li > .brx-submenu-toggle > * {
	color: var(--base);
}
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li:hover > a,
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li:hover > .brx-submenu-toggle > * {
	color: var(--secondary);
}

/* Legibility over the hero video.
   Everything above is light-on-video, which holds on a dark frame and
   washes out on a bright one. A shadow gives each element its own local
   substrate, so contrast depends less on what the video is showing.

   ⚠️ This is a mitigation, not a fix, and the gap is measured. Sampling
   the top 12% of the live clip (th-vanna-rose-prv.mp4) once per second on
   2026-09-15 gave a median luminance of Y=190 left / Y=201 right — Cream
   text at 1.5–1.7:1, failing AA 4.5:1 for 90% of the runtime on the nav
   side and 98% on the logo side. The bright frames are the rule for this
   clip, not the exception. Shadows measurably help but cannot carry a
   1.5:1 baseline on their own. A 60% Espresso scrim was built and tested
   (it brings the median to 5.41:1) and dropped on 2026-09-15 by decision —
   the band it put across the top of the video was not wanted. If nav
   legibility is revisited, the options are that scrim, or inverting the
   bar to dark-on-bright, which suits this clip far better than light-on-
   dark does. See CLAUDE.md.

   Two stops on the text: a tight 2px blur for edge definition against a
   busy frame, and a wide diffuse 14px that darkens the pixels behind the
   glyph itself. One stop alone does one job or the other, not both.

   Scoped to :not(.is-scrolled) throughout — once the header goes solid
   Cream it is Espresso-on-Cream and a dark shadow would only read as
   muddy. It drops on the same scroll event that swaps the fill. */
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li > a,
body.home .header:not(.is-scrolled) .header__menu .bricks-nav-menu > li > .brx-submenu-toggle > * {
	text-shadow: 0 1px 2px var(--neutral-trans-60), 0 0 14px var(--neutral-trans-50);
}

/* The Login pill needs both forms, and for different parts of itself.
   `drop-shadow()` traces the element's rendered alpha, so it follows the
   2px Cream outline around the pill's radius — which `box-shadow` could
   not do without painting a rectangle behind a rounded element. But it
   only ever draws OUTSIDE that traced edge, so it does nothing for the
   Cream label sitting in the pill's transparent middle. That still needs
   a text-shadow of its own. */
body.home .header:not(.is-scrolled) .header__login {
	text-shadow: 0 1px 2px var(--neutral-trans-60), 0 0 14px var(--neutral-trans-50);
	filter: drop-shadow(0 1px 3px var(--neutral-trans-60));
}

/* Logo is a pink script mark delivered as <picture>, so it needs the
   filter form too. drop-shadow on the anchor follows the mark's own
   transparency, which keeps the shadow on the lettering instead of
   boxing the whole file. */
body.home .header:not(.is-scrolled) .header__logo {
	filter: drop-shadow(0 1px 3px var(--neutral-trans-60)) drop-shadow(0 0 10px var(--neutral-trans-40));
}

@media (prefers-reduced-motion: reduce) {
	body.home .header {
		transition: none;
	}
}
