/**
 * Facet Filters — component styles.
 *
 * Theme integration contract: every colour/spacing decision reads a --faf-*
 * custom property with a neutral fallback. Themes map these onto their own
 * tokens (bodysoul: src/assets/scss/integrations/_plugin-tokens.scss bridge);
 * the plugin itself stays theme- and dark-mode-ignorant.
 *
 * Palette Kit sits INSIDE that fallback, never in front of it:
 * var(--faf-fab-bg, var(--pal-action, #333)). A theme that has deliberately
 * mapped a --faf-* token keeps winning - putting --pal-* first would silently
 * overrule the bridge - so the palette only skins the tokens nobody claimed.
 * On bodysoul the bridge claims every colour token, which makes these five
 * references inert there by design; they exist for golfshed, whose theme
 * declares no custom properties at all and so has nothing to bridge with.
 * See ../AGENTS.md "Palette Kit" for the measurements.
 */

.faf {
	--_faf-gap: var(--faf-gap, 0.75rem);
	/* Resolved once: the drawer-trigger pill, its hover mix and the badge's
	   punched-out ink all have to read the same fill. */
	--_faf-trigger-bg: var(--faf-trigger-bg, var(--faf-fab-bg, var(--pal-action, #333)));
	font-size: var(--faf-font-size, 1em);
}

.faf-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* Panel ------------------------------------------------------------------ */

.faf-panel {
	display: flex;
	flex-direction: column;
	gap: var(--_faf-gap);
}

.faf-group {
	border: var(--faf-group-border, 1px solid rgba(128, 128, 128, 0.25));
	border-radius: var(--faf-radius, 6px);
	padding: var(--faf-group-padding, 0.75rem 1rem);
	margin: 0;
	min-width: 0;
}

.faf-legend {
	font-weight: var(--faf-legend-weight, 600);
	padding: 0 0.35rem;
}

.faf-options {
	list-style: none;
	margin: 0;
	padding: 0;
	/* Counts right-align into this inset so they never sit flush with the
	   edge — or under the scrollbar when the list scrolls. stable gutter
	   keeps the lane reserved whether or not a scrollbar shows, so counts
	   line up across scrolling and non-scrolling groups. */
	padding-inline-end: var(--faf-list-inset, 0.5em);
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	/* No cap of its own (0.39.1): containment is the def's `overflow`, drawn
	   by the --scroll/--swipe/--more rules below, so an uncontained list is
	   every row. The old 16rem fallback predated per-facet containment and
	   was a rem on a family that sizes in em — 160px on a 10px root, which
	   clipped `overflow: none` and short lists into native scroll boxes.
	   The token stays for a theme that wants a blanket cap. */
	max-height: var(--faf-options-max-height, none);
	overflow: auto;
	scrollbar-gutter: stable;
}

.faf-option {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	cursor: pointer;
}

.faf-option-count {
	margin-inline-start: auto;
	opacity: 0.65;
	font-size: 0.85em;
}

.faf-select {
	width: 100%;
}

/* Swatch ui (0.24.0) -----------------------------------------------------
   A checkbox wearing a chip: the input keeps every mechanic (state, no-JS
   submit, envelope swaps), the chip is decoration. Swatch colours are DATA
   (term meta), never theme tokens — only the chrome around them is themeable,
   which is why no --pal-* reference appears here. */

.faf-swatches {
	gap: var(--faf-swatch-gap, 0.5em);
	/* Ring room: the checked/focus ring is an OUTLINE (offset + width, up to
	   ~6px in grid view) that takes no layout space, and the options list is
	   an overflow container — a chip flush with its edge gets its ring, and
	   even its border curve, clipped (0.30.2, measured). The inline-end side
	   already has the 0.29.0 count inset. */
	padding-block: var(--faf-swatch-ring-room, 0.4em);
	padding-inline-start: var(--faf-swatch-ring-room, 0.4em);
}

.faf-swatch-option {
	gap: var(--faf-swatch-label-gap, 0.5em);
}

/* The chip. A fixed box so single, split and image swatches all line up. */
.faf-swatch {
	flex: none;
	width: var(--faf-swatch-size, 1.6em);
	height: var(--faf-swatch-size, 1.6em);
	border-radius: var(--faf-swatch-radius, 50%);
	border: var(--faf-swatch-border, 1px solid rgba(128, 128, 128, 0.45));
	background-size: cover;
	background-position: center;
	/* A white swatch on a white rail needs an inner edge to read as a disc. */
	box-shadow: var(--faf-swatch-shadow, inset 0 0 0 1px rgba(255, 255, 255, 0.35));
}

/* No swatch data: an honest empty chip rather than a guessed colour. The
   diagonal says "nothing recorded" without inventing a hue. */
.faf-swatch--none {
	background-image: linear-gradient(
		to bottom right,
		transparent calc(50% - 1px),
		var(--faf-swatch-none-line, rgba(128, 128, 128, 0.55)) calc(50% - 1px),
		var(--faf-swatch-none-line, rgba(128, 128, 128, 0.55)) calc(50% + 1px),
		transparent calc(50% + 1px)
	);
}

/* Selected state rides an OUTLINE, not a background: forced-colors mode
   replaces backgrounds wholesale, and the tick must survive that. */
.faf-swatch-option:has(input:checked) .faf-swatch {
	outline: var(--faf-swatch-ring, 2px solid currentColor);
	outline-offset: var(--faf-swatch-ring-offset, 2px);
}

.faf-swatch-option:has(input:focus-visible) .faf-swatch {
	outline: var(--faf-focus-outline, 2px solid currentColor);
	outline-offset: var(--faf-swatch-ring-offset, 2px);
}

/* Clipped, never removed — three things ride this one rule, for one reason:
   display:none would take them out of the accessible tree (and the checkbox out
   of the tab order and the no-JS form) while visually-hidden text keeps
   speaking. They are the swatch checkbox, which stays operable behind its chip;
   the view buttons' labels, since an icon button with no text has no accessible
   name at all; and, in GRID view, each value's name and count (0.28.0) — the
   tile shows the colour alone, but the control it labels keeps its name. */
.faf-sr-only,
.faf-group[data-faf-view='grid'] .faf-swatch-option .faf-option-label,
.faf-group[data-faf-view='grid'] .faf-swatch-option .faf-option-count,
.faf-swatch-option input[type='checkbox'] {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* Swatch views (0.26.0; icon toggle + bare tiles 0.28.0) -----------------
   Two layouts over the SAME server-rendered list: the compact row, and a tile
   grid of chips alone. The toggle is JS-only — nothing is behind it without the
   client — so it appears only under html.faf-js, the gate the slider and the
   apply button already use. */

.faf-view-toggle {
	display: none;
}

.faf-js .faf-view-toggle {
	display: flex;
	gap: var(--faf-view-toggle-gap, 0.25em);
	justify-content: flex-end;
	margin: 0 0 var(--faf-view-toggle-space, 0.5em);
}

.faf-view-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Sized in em against an inherited font (0.30.2): rem fallbacks assumed a
	   16px root, and bodysoul's html{font-size:62.5%} rendered every one at
	   ~⅝ intent — the 28px box measured 17.5px. Buttons do not inherit fonts
	   (the 0.21.0 pill lesson), so font:inherit is what gives em its meaning
	   here; min-* guard the box against theme button resets winning `width`. */
	font: inherit;
	width: var(--faf-view-btn-box, 1.75em);
	height: var(--faf-view-btn-box, 1.75em);
	min-width: var(--faf-view-btn-box, 1.75em);
	min-height: var(--faf-view-btn-box, 1.75em);
	padding: 0;
	color: inherit;
	cursor: pointer;
	background: var(--faf-view-btn-bg, transparent);
	border: var(--faf-view-btn-border, 1px solid rgba(128, 128, 128, 0.35));
	border-radius: var(--faf-view-btn-radius, 0.25em);
}

/* The glyphs (0.28.0): currentColor masks, the pattern the selected-row tick
   and the filter glyph already use, so they ride the button's own colour in any
   theme. Decoration only — the button's name comes from its clipped text. */
.faf-view-btn::before {
	content: '';
	width: var(--faf-view-icon-size, 0.95em);
	height: var(--faf-view-icon-size, 0.95em);
	background: var(--faf-view-icon, currentColor);
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: contain;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
}

/* Three bars. */
.faf-view-btn--list::before {
	-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 4h12M2 8h12M2 12h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/></svg>");
	mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 4h12M2 8h12M2 12h12' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/></svg>");
}

/* Four squares. */
.faf-view-btn--grid::before {
	-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h5v5H2zM9 2h5v5H9zM2 9h5v5H2zM9 9h5v5H9z' fill='black'/></svg>");
	mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 2h5v5H2zM9 2h5v5H9zM2 9h5v5H2zM9 9h5v5H9z' fill='black'/></svg>");
}

/* Fingers need more than the compact 28px box: on coarse pointers the buttons
   grow to the 44px platform minimum and the glyphs scale with them. A mouse
   keeps the small box — the rail is tight and a cursor does not miss. */
@media (pointer: coarse) {
	.faf-view-btn {
		width: var(--faf-view-btn-box-touch, 2.75em);
		height: var(--faf-view-btn-box-touch, 2.75em);
		min-width: var(--faf-view-btn-box-touch, 2.75em);
		min-height: var(--faf-view-btn-box-touch, 2.75em);
	}

	.faf-view-btn::before {
		width: var(--faf-view-icon-size-touch, 1.2em);
		height: var(--faf-view-icon-size-touch, 1.2em);
	}

	.faf-js .faf-view-toggle {
		gap: var(--faf-view-toggle-gap-touch, 0.4em);
	}
}

/* Which view is on cannot be carried by colour alone now that the text is gone:
   the wash comes with a ring, and an outline survives forced-colours mode. */
.faf-view-btn[aria-pressed='true'] {
	background: var(--faf-view-btn-on-bg, rgba(128, 128, 128, 0.18));
	outline: var(--faf-view-btn-on-ring, 1px solid currentColor);
	outline-offset: -1px;
}

/* Grid view (0.28.0): the tile is the CHIP, nothing else. 0.26.0 put the name
   and count under it, and at 3rem across a narrow rail they wrapped into each
   other — the user's screenshot showed two names and a stray count fused into
   one line. They are clipped instead (see the visually-hidden rule above), the
   `title` gives a mouse user the name back, and the a11y stance holds where it
   counts: the control keeps its accessible name, and selection is a ring rather
   than a change of colour. Uniform cells, so tiles cannot jostle each other. */
.faf-group[data-faf-view='grid'] .faf-swatches {
	display: grid;
	/* Fixed columns, fluid tiles: swatches are increasingly product PHOTOS
	   (powder shots), which earn real size — four across fills the rail with
	   tiles that scale to it, capped so a wide rail can't grow dinner plates.
	   Items must STRETCH (the default): the chip's size arrives through a
	   width:100% chain from the cell, and justify-items:center would make
	   every link in that chain shrink-to-fit — an empty chip then collapses
	   to a dot (0.30.1 regression fix). Centring happens inside the label. */
	grid-template-columns: repeat(var(--faf-grid-cols, 4), minmax(0, 1fr));
	gap: var(--faf-swatch-grid-gap, 0.6em);
	align-items: center;
}

.faf-group[data-faf-view='grid'] .faf-swatch-option {
	justify-content: center;
	gap: 0;
	width: 100%;
}

.faf-group[data-faf-view='grid'] .faf-swatch {
	width: 100%;
	max-width: var(--faf-swatch-size-grid-max, 5.5em);
	height: auto;
	aspect-ratio: 1;
}

/* A bare tile has to carry its own selected state: no label is showing, so the
   ring thickens. Still geometry, never hue — the swatch's own colour is the one
   thing a grid exists to show, so it never changes to say "selected", and an
   outline survives forced-colours mode where backgrounds are replaced. */
.faf-group[data-faf-view='grid'] .faf-swatch-option:has(input:checked) .faf-swatch {
	outline: var(--faf-swatch-ring-grid, 3px solid currentColor);
	outline-offset: var(--faf-swatch-ring-offset-grid, 3px);
}

/* Grid is a layout the visitor asked for, so it outranks a def's swipe row —
   a horizontal mask and snap track would fight a wrapping grid. Vertical
   containment (scroll mode) still applies, on the same height budget: the box
   is unchanged, it simply holds fewer and larger rows. */
.faf-group[data-faf-view='grid'] .faf-options--swipe {
	grid-auto-flow: row;
	grid-template-rows: none;
	grid-auto-columns: auto;
	overflow-x: visible;
	scroll-snap-type: none;
	padding-block-end: 0;
}

/* No fade over tiles: fading a COLOUR reads as a paler colour, never as
   "more below". In grid view the scrollbar and a cut-off tile row are the
   affordance; the fade stays in list view, where a dimmed text row works. */
.faf-group[data-faf-view='grid'] .faf-options--scroll,
.faf-js .faf-group[data-faf-view='grid'] .faf-options--more {
	mask-image: none;
}

/* The quickbar is a compact inline row; the layout the toggle offers does not
   exist there. Its groups are the same markup by design, so the control hides
   rather than being conditionally rendered. */
.faf-js .faf-quickbar .faf-view-toggle {
	display: none;
}

/* List overflow (0.24.0) -------------------------------------------------
   Containment for long value lists, in CSS only — no ui gains any JavaScript
   from it. --faf-list-rows comes from the def's `visible` threshold. */

.faf-options--scroll {
	max-height: calc(var(--faf-list-rows, 8) * var(--faf-list-row-height, 2em));
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	/* Fade the cut edges so a clipped list visibly continues. Vertical only —
	   the mask is what tells a mouse user there is more below. */
	mask-image: linear-gradient(
		to bottom,
		transparent 0,
		#000 var(--faf-list-fade, 0.75em),
		#000 calc(100% - var(--faf-list-fade, 0.75em)),
		transparent 100%
	);
}

/* Swipe mode (reworked 0.35.0): PAGES of `visible` rows, not one long row.
   The list flows down a column of --faf-list-rows rows, then starts the next
   column; every column is the container's full width, so each is a page and
   a horizontal swipe reveals the next `visible` values — the first page reads
   exactly like the plain list it replaces. Still pure CSS: grid column flow
   plus scroll-snap, mandatory so the row never rests between pages. No fade
   mask here — it would dim the counts sitting at the inline end of the
   visible page, and at rest there is no cut edge to announce. The thin
   scrollbar (below) is the mouse affordance; touch has the swipe itself. */
.faf-options--swipe {
	display: grid;
	grid-auto-flow: column;
	grid-template-rows: repeat(var(--faf-list-rows, 8), auto);
	grid-auto-columns: 100%;
	column-gap: var(--faf-list-page-gap, 1em);
	max-height: none;
	overflow-x: auto;
	overflow-y: hidden;
	overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	scrollbar-width: thin;
	/* The base list reserves a vertical scrollbar lane; a page must own the
	   full width or `100%` columns and the snap points drift by the lane. */
	scrollbar-gutter: auto;
	-webkit-overflow-scrolling: touch;
	/* Room for the thin scrollbar under the last row, so it does not overlay
	   the final value's text on classic-scrollbar platforms. */
	padding-block-end: var(--faf-list-scrollbar, 0.4em);
}

/* Each item snaps at its own start; the items of one column share an inline
   start, so the snap points ARE the page starts. */
.faf-options--swipe > li {
	scroll-snap-align: start;
	min-width: 0;
}

.faf-options--scroll::-webkit-scrollbar,
.faf-options--swipe::-webkit-scrollbar {
	width: var(--faf-list-scrollbar, 0.4em);
	height: var(--faf-list-scrollbar, 0.4em);
}

.faf-options--scroll::-webkit-scrollbar-thumb,
.faf-options--swipe::-webkit-scrollbar-thumb {
	border-radius: 999px;
	background: var(--faf-list-scrollbar-thumb, rgba(128, 128, 128, 0.45));
}

/* Show more (0.39.0) ------------------------------------------------------
   A `more` list renders EVERY row; the client clips it. Without the client
   it is a plain full list (the base list's own max-height lifted too) and
   the button is hidden — values are never withheld from a no-JS visitor.
   Collapsed: --faf-list-rows rows and a fade at the bottom edge, the "list
   continues" cue. Open: a taller scroll box, twice the rows unless
   --faf-list-rows-more says otherwise, with the scroll box's two-edge fade.
   A find query (faf-options--searching) opens it, so a match past the
   first rows is reachable, and the button steps aside meanwhile. */
.faf-options--more {
	max-height: none;
	overflow: visible;
}

.faf-more {
	display: none;
}

.faf-js .faf-options--more {
	max-height: calc(var(--faf-list-rows, 8) * var(--faf-list-row-height, 2em));
	overflow: hidden;
	mask-image: linear-gradient(to bottom, #000 calc(100% - var(--faf-list-fade-more, 2em)), transparent 100%);
}

.faf-js .faf-options--more-open,
.faf-js .faf-options--more.faf-options--searching {
	max-height: calc(var(--faf-list-rows-more, calc(var(--faf-list-rows, 8) * 2)) * var(--faf-list-row-height, 2em));
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	mask-image: linear-gradient(
		to bottom,
		transparent 0,
		#000 var(--faf-list-fade, 0.75em),
		#000 calc(100% - var(--faf-list-fade, 0.75em)),
		transparent 100%
	);
}

.faf-js .faf-more {
	display: inline-block;
	margin-block-start: var(--faf-more-gap, 0.4em);
	padding: var(--faf-more-padding, 0.25em 0);
	border: 0;
	background: none;
	color: var(--faf-more-color, inherit);
	font: inherit;
	font-weight: var(--faf-more-weight, 600);
	text-decoration: underline;
	text-underline-offset: 0.2em;
	cursor: pointer;
}

.faf-js .faf-options--searching + .faf-more {
	display: none;
}

/* Find box (0.39.0): client state over server rows, so it exists only with
   the client. Rows it hides carry [hidden]; flex children would otherwise
   keep their box. */
.faf-find {
	display: none;
}

.faf-js .faf-find {
	display: block;
	margin-block-end: var(--faf-find-gap, 0.5em);
}

.faf-find__input {
	box-sizing: border-box;
	width: 100%;
	padding: var(--faf-find-padding, 0.45em 0.6em);
	border: var(--faf-find-border, 1px solid rgba(128, 128, 128, 0.45));
	border-radius: var(--faf-find-radius, var(--faf-radius, 6px));
	background: var(--faf-find-bg, transparent);
	color: inherit;
	font: inherit;
}

.faf-options > li[hidden],
.faf-find__none[hidden] {
	display: none;
}

.faf-find__none,
.faf-note {
	margin: var(--faf-note-gap, 0.4em) 0 0;
	font-size: var(--faf-note-size, 0.85em);
	color: var(--faf-note-color, inherit);
	opacity: var(--faf-note-opacity, 0.8);
}

/* A masked container inside a hidden (redundant) group must not paint at all —
   [hidden] wins, and the mask must not resurrect it. */
.faf-group[hidden] .faf-options--scroll,
.faf-group[hidden] .faf-options--swipe,
.faf-group[hidden] .faf-options--more {
	display: none;
}

/* The quickbar lays values out as a wrapping inline row already: neither a
   vertical scroll box nor paged columns belong there, so both modes fall back
   to that row (the swipe half was only ever held off by specificity — its fade
   mask still applied to the wrapped row; explicit since 0.35.0). */
.faf-quickbar .faf-options--scroll,
.faf-quickbar .faf-options--swipe,
.faf-js .faf-quickbar .faf-options--more {
	display: flex;
	max-height: none;
	overflow: visible;
	mask-image: none;
	padding-block-end: 0;
}

/* Nor do the rail round's list frames: no show-more, find box or note in the
   compact row (the same markup, so they hide rather than not render). */
.faf-js .faf-quickbar .faf-more,
.faf-js .faf-quickbar .faf-find,
.faf-quickbar .faf-find__none,
.faf-quickbar .faf-note {
	display: none;
}

/* Empty-state card (every facet redundant) ------------------------------- */

.faf-empty-link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding: var(--faf-empty-btn-padding, 0.55em 1.1em);
	border: var(--faf-empty-btn-border, 0);
	border-radius: var(--faf-empty-btn-radius, var(--faf-radius, 6px));
	background: var(--faf-empty-btn-bg, rgba(128, 128, 128, 0.12));
	color: var(--faf-empty-btn-color, inherit);
	font-weight: var(--faf-legend-weight, 600);
	text-decoration: none;
}

.faf-empty-link:hover,
.faf-empty-link:focus-visible {
	background: var(--faf-empty-btn-bg-hover, rgba(128, 128, 128, 0.22));
	color: var(--faf-empty-btn-color, inherit);
}

/* Menu-style rows (links / links-single ui) ------------------------------ */

.faf-links {
	gap: var(--faf-link-gap, 0.1rem);
}

.faf-link {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	padding: var(--faf-link-padding, 0.4rem 0.6rem);
	border-radius: var(--faf-link-radius, 4px);
	text-decoration: none;
	color: var(--faf-link-color, inherit);
}

.faf-link:hover,
.faf-link:focus-visible {
	background: var(--faf-link-bg-hover, rgba(128, 128, 128, 0.12));
}

.faf-link[aria-current] {
	background: var(--faf-link-active-bg, rgba(128, 128, 128, 0.18));
	color: var(--faf-link-active-color, inherit);
	font-weight: var(--faf-link-active-weight, 600);
}

/* Selected-row tick: a currentColor mask, not text content, so it rides the
   active row's color tokens and stays invisible to screen readers — the
   state is already announced via aria-current. */
.faf-link[aria-current]::before {
	content: '';
	flex-shrink: 0;
	width: var(--faf-link-tick-size, 0.85em);
	height: var(--faf-link-tick-size, 0.85em);
	background: var(--faf-link-tick, currentColor);
	-webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 8.5 6 12.5 14 3.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
	mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 8.5 6 12.5 14 3.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
}

/* Tick: box (0.38.0) — the selected state moves from the leading tick into a
   checkbox at the row's end, after the count when there is one. Opacity
   rather than a mixed colour, so the unchecked outline needs no color-mix()
   twin; the checked fill and tick are tokens because the fill is currentColor
   and only the theme knows what reads on top of it. */
.faf-links--box .faf-link[aria-current]::before {
	content: none;
}

.faf-tickbox {
	position: relative;
	flex-shrink: 0;
	box-sizing: border-box;
	width: var(--faf-tickbox-size, 1.05em);
	height: var(--faf-tickbox-size, 1.05em);
	margin-inline-start: auto;
	border: var(--faf-tickbox-border-width, 0.1em) solid var(--faf-tickbox-border, currentColor);
	border-radius: var(--faf-tickbox-radius, 0.2em);
	background: var(--faf-tickbox-bg, transparent);
	opacity: var(--faf-tickbox-opacity, 0.55);
}

.faf-option-count ~ .faf-tickbox {
	margin-inline-start: 0;
}

.faf-links--single .faf-tickbox {
	border-radius: 50%;
}

.faf-link:hover .faf-tickbox,
.faf-link:focus-visible .faf-tickbox {
	opacity: 0.85;
}

.faf-link[aria-current] .faf-tickbox {
	border-color: var(--faf-tickbox-checked-bg, currentColor);
	background: var(--faf-tickbox-checked-bg, currentColor);
	opacity: 1;
}

.faf-link[aria-current] .faf-tickbox::after {
	content: '';
	position: absolute;
	inset: 12%;
	background: var(--faf-tickbox-tick, #fff);
	-webkit-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 8.5 6 12.5 14 3.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
	mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 8.5 6 12.5 14 3.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
}

/* "Menu" style (per-facet style: menu) — stacked full-width bars ---------- */

.faf-group--menu {
	border: 0;
	border-radius: var(--faf-menu-radius, 10px);
	padding: 0;
	overflow: hidden;
}

/* Adjacent VISIBLE menu groups fuse into ONE card: the panel's flex gap
   between them collapses to the 1px seam and the seam corners square off.
   Every group starts fully rounded because redundancy-hidden run-mates STAY
   in the DOM (display:none) and `+` cannot skip them — a hidden first group
   must not cost the next one its top corners. A hidden group mid-run just
   splits the card in two. */
.faf-group--menu:not([hidden]) + .faf-group--menu {
	margin-top: calc(var(--faf-menu-row-gap, 1px) - var(--_faf-gap, 0.75rem));
	border-start-start-radius: 0;
	border-start-end-radius: 0;
}

.faf-group--menu:has(+ .faf-group--menu:not([hidden])) {
	border-end-start-radius: 0;
	border-end-end-radius: 0;
}

.faf-group--menu > .faf-legend {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	width: 100%;
	margin: 0;
	padding: var(--faf-menu-header-padding, 0.6rem 0.8rem);
	background: var(--faf-menu-header-bg, rgba(128, 128, 128, 0.45));
	color: var(--faf-menu-header-color, inherit);
	font-family: var(--faf-menu-header-font, inherit);
	font-size: var(--faf-menu-header-size, 1em);
	font-weight: var(--faf-menu-header-weight, var(--faf-legend-weight, 600));
}

.faf-group--menu .faf-links {
	gap: var(--faf-menu-row-gap, 1px);
}

.faf-group--menu > .faf-options,
details.faf-collapse.faf-group--menu > .faf-options {
	margin-top: var(--faf-menu-row-gap, 1px);
	/* The TOKEN, not max-height itself (0.39.1): a menu list ignores a
	   theme's blanket cap, but its own containment (--scroll, --more) still
	   bounds it. Setting max-height here outranked those rules, so a menu
	   facet rendered every row under a dead "Show all" button. */
	--faf-options-max-height: none;
	/* Menu rows are full-bleed bars with their own padding — the count inset
	   would notch their right edge. The gutter must go too: classic-scrollbar
	   platforms reserve its lane even on a container that never scrolls,
	   stopping the bars ~10px short of the card edge (0.30.2 regression fix,
	   measured on bodysoul). */
	padding-inline-end: 0;
	scrollbar-gutter: auto;
}

.faf-group--menu .faf-link {
	border-radius: 0;
	padding: var(--faf-menu-row-padding, 0.55rem 0.8rem);
	background: var(--faf-menu-row-bg, rgba(128, 128, 128, 0.2));
	color: var(--faf-menu-row-color, inherit);
}

.faf-group--menu .faf-link:hover,
.faf-group--menu .faf-link:focus-visible {
	background: var(--faf-menu-row-bg-hover, rgba(128, 128, 128, 0.32));
}

.faf-group--menu .faf-link[aria-current] {
	background: var(--faf-menu-row-active-bg, rgba(128, 128, 128, 0.45));
	color: var(--faf-menu-row-active-color, inherit);
	font-weight: var(--faf-link-active-weight, 600);
}

/* Collapsible groups (per-facet collapse: open|closed) -------------------- */

details.faf-collapse > summary.faf-legend {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	padding: 0;
	cursor: pointer;
	list-style: none;
}

details.faf-collapse > summary.faf-legend::-webkit-details-marker {
	display: none;
}

details.faf-collapse > summary.faf-legend::after {
	content: "";
	width: 0.45em;
	height: 0.45em;
	margin-inline-end: 0.2em;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg);
	transition: transform 0.2s ease;
	flex: none;
}

details.faf-collapse[open] > summary.faf-legend::after {
	transform: rotate(225deg);
}

details.faf-collapse > .faf-options {
	margin-top: var(--_faf-gap, 0.75rem);
}

/* The collapse reset above zeroes summary padding at higher specificity
   than the menu-header rule — re-assert the bar padding for menu groups. */
details.faf-collapse.faf-group--menu > summary.faf-legend {
	padding: var(--faf-menu-header-padding, 0.6rem 0.8rem);
}

/* Slide open/close where the platform can animate <details>
   (interpolate-size + ::details-content); elsewhere it snaps open —
   still fully functional, and entirely JS-free either way. */
@supports (interpolate-size: allow-keywords) {
	details.faf-collapse {
		interpolate-size: allow-keywords;
	}

	details.faf-collapse::details-content {
		block-size: 0;
		overflow-y: clip;
		transition: block-size 0.25s ease, content-visibility 0.25s allow-discrete;
	}

	details.faf-collapse[open]::details-content {
		block-size: auto;
	}
}

@media (prefers-reduced-motion: reduce) {
	details.faf-collapse::details-content,
	details.faf-collapse > summary.faf-legend::after {
		transition: none;
	}
}

.faf-range {
	display: flex;
	align-items: center;
	gap: 0.5rem;
}

/* Range slider (range-slider ui) ------------------------------------------
   Two overlaid NATIVE range inputs on one rail; the number fields stay in
   the DOM as the submitted state + no-JS fallback, so without JS the group
   degrades to the plain range ui. */

html:not(.faf-js) .faf-slider-track,
html:not(.faf-js) .faf-slider-values {
	display: none;
}

.faf-js .faf-slider .faf-range {
	display: none;
}

.faf-slider-values {
	display: flex;
	justify-content: space-between;
	gap: 0.5rem;
	margin-bottom: 0.3rem;
	font-size: var(--faf-slider-label-size, 1em);
	color: var(--faf-slider-label-color, inherit);
}

.faf-slider-track {
	position: relative;
	height: var(--faf-slider-thumb-size, 16px);
}

.faf-slider-rail,
.faf-slider-fill {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	height: var(--faf-slider-track-height, 4px);
	border-radius: 999px;
}

.faf-slider-rail {
	left: 0;
	right: 0;
	background: var(--faf-slider-rail, rgba(128, 128, 128, 0.35));
}

.faf-slider-fill {
	left: 0;
	right: 0;
	background: var(--faf-slider-fill, currentColor);
}

.faf-slider-track input[type='range'] {
	position: absolute;
	top: 0;
	/* A native input keeps its thumb inside its own box, so the thumb CENTER
	   stops half a thumb short of each end. Overhang the input half a thumb
	   past both rail ends and the centers land exactly on the rail edges at
	   min/max (the fill math in filters.js relies on this linearity). */
	left: calc(var(--faf-slider-thumb-size, 16px) / -2);
	width: calc(100% + var(--faf-slider-thumb-size, 16px));
	height: 100%;
	margin: 0;
	/* Geometry must stay ours: theme form resets that pad/border generic
	   inputs (bodysoul pads ALL input types 10px) shrink the CONTENT box,
	   and the content box is the thumb's travel range. */
	padding: 0;
	border: 0;
	appearance: none;
	-webkit-appearance: none;
	background: transparent;
	pointer-events: none;
}

.faf-slider-track input[type='range']::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	pointer-events: auto;
	width: var(--faf-slider-thumb-size, 16px);
	height: var(--faf-slider-thumb-size, 16px);
	border-radius: 50%;
	border: var(--faf-slider-thumb-border, 0);
	background: var(--faf-slider-thumb, #888);
	cursor: pointer;
}

.faf-slider-track input[type='range']::-moz-range-thumb {
	pointer-events: auto;
	width: var(--faf-slider-thumb-size, 16px);
	height: var(--faf-slider-thumb-size, 16px);
	border-radius: 50%;
	border: var(--faf-slider-thumb-border, 0);
	background: var(--faf-slider-thumb, #888);
	cursor: pointer;
}

.faf-slider-track input[type='range']:focus-visible::-webkit-slider-thumb {
	outline: var(--faf-focus-outline, 2px solid currentColor);
	outline-offset: 2px;
}

.faf-slider-track input[type='range']:focus-visible::-moz-range-thumb {
	outline: var(--faf-focus-outline, 2px solid currentColor);
	outline-offset: 2px;
}

.faf-range-field input {
	width: 6em;
}

.faf-apply {
	align-self: start;
}

/* JS on: instant filtering makes the explicit buttons redundant. */
.faf-js .faf-apply {
	display: none;
}

/* Chips ------------------------------------------------------------------ */

.faf-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}

.faf-chips:empty {
	display: none;
}

/* Ghost styling on purpose: it sits among the chips but must not read as a
   removable chip — it is the escape hatch for all of them. */
.faf-clear-all {
	display: inline-flex;
	align-items: center;
	padding: var(--faf-chip-padding, 0.2rem 0.7rem);
	color: var(--faf-clear-color, inherit);
	font-size: var(--faf-clear-size, 0.9em);
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.faf-chip {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	padding: var(--faf-chip-padding, 0.2rem 0.7rem);
	border-radius: var(--faf-chip-radius, 999px);
	background: var(--faf-chip-bg, rgba(128, 128, 128, 0.15));
	color: var(--faf-chip-color, inherit);
	text-decoration: none;
	font-size: 0.9em;
}

.faf-chip:hover,
.faf-chip:focus-visible {
	background: var(--faf-chip-bg-hover, rgba(128, 128, 128, 0.3));
}

/* Loading ---------------------------------------------------------------- */

[aria-busy='true'].faf-loading,
.faf-loading {
	opacity: 0.5;
	pointer-events: none;
	transition: opacity 0.15s ease;
}

/* Quickbar --------------------------------------------------------------- */

.faf-quickbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem 1.25rem;
	margin-bottom: var(--_faf-gap, 0.75rem);
}

.faf-quickbar .faf-group {
	border: 0;
	padding: 0;
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
}

.faf-quickbar .faf-legend {
	float: left;
	padding: 0;
	margin-inline-end: 0.35rem;
	font-size: 0.9em;
}

.faf-quickbar .faf-options {
	flex-direction: row;
	flex-wrap: wrap;
	max-height: none;
	overflow: visible;
	gap: 0.75rem;
}

.faf-quickbar .faf-option-count {
	margin-inline-start: 0.25rem;
}

.faf-quickbar .faf-quick-form {
	display: inline-flex;
	align-items: center;
	gap: 0.75rem;
}

/* Drawer triggers --------------------------------------------------------
   The panel's "Filters" button and the quickbar's (the same word, or "All
   filters" beside inline facets) are the inline twins of the floating pill
   below: one action, one skin family. The --faf-trigger-* tokens fall back
   to the pill's, so a theme that mapped the pill gets these for free and can
   still diverge; the pill in turn reads the trigger's radius, padding and
   type, so a theme that skins the inline button once gets a matching pill. Until 0.18.0 they carried
   no skin at all and rendered as whatever the UA draws a bare <button> as,
   which matched no theme anywhere. */

.faf-drawer-trigger,
.faf-all-btn {
	display: inline-flex;
	align-items: center;
	gap: var(--faf-trigger-gap, 0.5rem);
	padding: var(--faf-trigger-padding, var(--faf-fab-padding, 0.6rem 1.4rem));
	border: var(--faf-trigger-border, var(--faf-fab-border, 0));
	border-radius: var(--faf-trigger-radius, 999px);
	background: var(--_faf-trigger-bg);
	box-shadow: var(--faf-trigger-shadow, none);
	color: var(--faf-trigger-color, var(--faf-fab-color, #fff));
	font: inherit;
	font-size: var(--faf-trigger-size, 1em);
	font-weight: var(--faf-trigger-weight, var(--faf-legend-weight, 600));
	line-height: 1.2;
	cursor: pointer;
}

/* Hover is the trigger fill taken 12% toward black. Two things make that
   declaration drop rather than darken: a theme that has bridged a GRADIENT
   into the fill (a gradient is not a <color>), and any browser below the
   color-mix() floor. Either way hover holds the literal below; themes wanting
   their own set --faf-trigger-bg-hover. The live mix is in the @compat block
   at the foot of this file. */
.faf-drawer-trigger:hover,
.faf-all-btn:hover {
	background: var(--faf-trigger-bg-hover, #292929);
}

/* The generic .faf-badge further down is drawn for a trigger wearing PAGE
   colour: disc in the current ink, count in the surface colour. On a filled
   pill both land on white — punch the count out in the pill's own fill. */
.faf-drawer-trigger .faf-badge {
	background: var(--faf-trigger-badge-bg, currentColor);
	color: var(--faf-trigger-badge-color, var(--_faf-trigger-bg));
}

/* Triple-stack filter glyph, trailing the label. Drawn as a currentColor mask
   like the selected-row tick above, not as text or an <img>: it inherits the
   button's ink, so it needs no per-theme colour and no dark-mode variant, and
   it stays out of the accessible name (the button already says "Filters").
   Bars taper longest-to-shortest and stay centred — off-centre bars read as
   "sort", centred ones as "filter". To drop the icon set
   --faf-trigger-icon-size to 0; blanking the IMAGE instead would leave the
   mask unset and paint a solid block. One rule for all three drawer openers:
   the glyph is the same drawing, so --faf-trigger-icon* governs the pill too
   (its own --faf-fab-* family stays what it always was — the pill's chrome:
   fill, shadow, badge). */
.faf-drawer-trigger::after,
.faf-all-btn::after,
.faf-fab::after {
	content: '';
	flex: none;
	width: var(--faf-trigger-icon-size, 1.05em);
	height: var(--faf-trigger-icon-size, 1.05em);
	background: currentColor;
	-webkit-mask: var(--faf-trigger-icon, url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 3.5h12M4.5 8h7M7 12.5h2' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'/></svg>")) center / contain no-repeat;
	mask: var(--faf-trigger-icon, url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M2 3.5h12M4.5 8h7M7 12.5h2' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'/></svg>")) center / contain no-repeat;
}

@media (min-width: 960.02px) {
	/* Desktop already shows the full panel in the sidebar. */
	.faf-all-btn {
		display: none;
	}
}

/* Floating "Filters" pill (mobile, after scrolling past the panel) -------- */

.faf-fab {
	position: fixed;
	/* --faf-fab-lift is filters.js's, set while a fixed dock (a newsletter
	   tab's lip, a cookie bar) covers the pill's resting spot: its height. */
	bottom: calc(max(1rem, env(safe-area-inset-bottom)) + var(--faf-fab-lift, 0px));
	left: 50%;
	transform: translateX(-50%);
	z-index: var(--faf-z, 1000);
	display: inline-flex;
	align-items: center;
	gap: var(--faf-fab-gap, var(--faf-trigger-gap, 0.45rem));
	padding: var(--faf-fab-padding, var(--faf-trigger-padding, 0.6rem 1.4rem));
	/* Round by default, but a theme that squared its inline trigger meant the
	   drawer's control to look like that — this is the same control, a scroll
	   later. Until 0.39.2 the 999px was fixed here, so bodysoul's soft toolbar
	   button summoned a round pill. */
	border-radius: var(--faf-fab-radius, var(--faf-trigger-radius, 999px));
	border: var(--faf-fab-border, 0);
	background: var(--faf-fab-bg, var(--pal-action, #333));
	color: var(--faf-fab-color, #fff);
	box-shadow: var(--faf-fab-shadow, 0 4px 16px rgba(0, 0, 0, 0.25));
	/* Appended to <body>, so it is the one control that inherits nothing from
	   a .faf root — and a bare <button> takes the UA's own ~13px face, which
	   is why the pill used to read a size smaller than its inline twins. Type
	   falls back to the trigger tokens: skin the inline button and the pill
	   matches without a second mapping. */
	font: inherit;
	font-size: var(--faf-fab-size, var(--faf-trigger-size, 1em));
	font-weight: var(--faf-fab-weight, var(--faf-trigger-weight, var(--faf-legend-weight, 600)));
	line-height: 1.2;
	cursor: pointer;
}

.faf-fab .faf-badge {
	display: inline-grid;
	place-items: center;
	min-width: 1.4em;
	height: 1.4em;
	border-radius: 999px;
	background: var(--faf-fab-badge-bg, rgba(255, 255, 255, 0.25));
	font-size: 0.85em;
}

/* Focus ------------------------------------------------------------------ */

.faf :focus-visible {
	outline: var(--faf-focus-outline, 2px solid currentColor);
	outline-offset: 2px;
}

/* [hidden] enforcement ----------------------------------------------------
   The UA's [hidden]{display:none} loses to ANY author display rule, and the
   fab/badge set display explicitly — the JS-toggled hidden attribute needs
   re-arming with higher specificity (class+attribute) than every display
   rule in this file. */

.faf-fab[hidden],
.faf-badge[hidden],
.faf-fab .faf-badge[hidden],
.faf[hidden],
.faf .faf-group[hidden],
.faf .faf-quick-form[hidden] {
	display: none;
}

/* Drawer (mobile) --------------------------------------------------------- */

.faf-drawer-trigger {
	display: none;
}

/* One drawer, one control. With a quickbar on the page its All-filters button
   already opens the drawer, from beside the grid instead of the top of the
   rail, so the panel's own trigger is a second button for one action — and it
   costs a whole row above the results. Hidden rather than never rendered: the
   panel renders BEFORE the quickbar (rail above grid), so the server cannot
   see it coming, and the floating pill reads its label off this element.
   Browsers without :has() keep both buttons, i.e. the pre-0.18.0 layout. */
:root:has(.faf-quickbar .faf-all-btn) .faf-drawer-trigger {
	display: none;
}

.faf-no-scroll {
	overflow: hidden;
}

@media (max-width: 960px) {
	/* The drawer is filters.js's — the trigger opens it, and the panel below is
	   parked off-screen until that script adds .faf-open. So all three pieces
	   hang off html.faf-js (0.32.0). Without the client — a browser blocking
	   JavaScript, or AJAX filtering switched off in Settings — the trigger and
	   the drawer chrome do not render at all and the panel simply stays in the
	   flow where the theme put it: scrollable, filterable, and honest. Before
	   this the trigger appeared, did nothing, and the panel it would have opened
	   was invisible, which left a no-JS phone with no way to filter. */
	.faf-js .faf-drawer-trigger {
		display: inline-flex;
	}

	.faf-badge {
		display: inline-grid;
		place-items: center;
		min-width: 1.4em;
		height: 1.4em;
		border-radius: 999px;
		background: var(--faf-badge-bg, currentColor);
		color: var(--faf-badge-color, var(--faf-surface, var(--pal-surface, #fff)));
		font-size: 0.8em;
	}

	.faf-scrim {
		position: fixed;
		inset: 0;
		background: var(--faf-scrim, rgba(0, 0, 0, 0.5));
		z-index: var(--faf-z, 1000);
	}

	.faf-js .faf-holder {
		position: fixed;
		inset: auto 0 0 0;
		max-height: 85vh;
		overflow: auto;
		background: var(--faf-surface, var(--pal-surface, #fff));
		color: var(--faf-text, var(--pal-ink, inherit));
		border-radius: var(--faf-drawer-radius, 16px) var(--faf-drawer-radius, 16px) 0 0;
		padding: var(--faf-drawer-padding, 1rem 1.25rem 1.5rem);
		z-index: calc(var(--faf-z, 1000) + 1);
		transform: translateY(105%);
		visibility: hidden;
	}

	.faf-open .faf-holder {
		transform: translateY(0);
		visibility: visible;
	}

	@media (prefers-reduced-motion: no-preference) {
		.faf-js .faf-holder {
			transition: transform 0.25s ease, visibility 0.25s;
		}
	}

	/* Drawer chrome without a drawer would be a title and a close button that
	   closes nothing. */
	html:not(.faf-js) .faf-head {
		display: none;
	}

	.faf-js .faf-head {
		display: flex;
		align-items: center;
		justify-content: space-between;
		margin-bottom: var(--_faf-gap);
	}

	.faf-title {
		font-weight: 600;
	}

	.faf-close {
		font-size: 1.5em;
		line-height: 1;
		background: none;
		border: 0;
		cursor: pointer;
		color: inherit;
	}
}

@media (min-width: 960.02px) {
	.faf-scrim,
	.faf-head {
		display: none !important;
	}
}

/* Load-ahead (0.31.0) ----------------------------------------------------
   Batches append into the HOST's product grid, so everything here has to work
   inside markup this plugin does not own: the separator spans a full row where
   that grid is a grid, and a full-width line where it is flex. Sizes are em,
   per the sizing convention — a rem here would trust a root no theme promised
   (bodysoul sets html{font-size:62.5%}). */

.faf-batch-sep {
	grid-column: 1 / -1;
	flex-basis: 100%;
	width: 100%;
	display: flex;
	align-items: center;
	gap: var(--faf-batch-gap, 0.75em);
	margin: var(--faf-batch-space, 1.6em) 0;
	padding: 0;
	list-style: none;
}

/* Mid-row under the CURRENT column count (filters.js judgeSeams): hidden so
   the next batch flows into the gap. Doubled class to beat a theme's own
   display on the separator. */
.faf-batch-sep.faf-batch-sep--mid {
	display: none;
}

/* The hairline is drawn either side of the label, so the seam reads as one
   rule across the grid rather than a stray caption. */
.faf-batch-sep::before,
.faf-batch-sep::after {
	content: '';
	flex: 1;
	height: 1px;
	background: var(--faf-batch-line, rgba(128, 128, 128, 0.28));
}

.faf-batch-label {
	flex: none;
	font-size: var(--faf-batch-label-size, 0.8em);
	opacity: 0.7;
	white-space: nowrap;
}

.faf-load-more {
	display: block;
	margin: var(--faf-load-more-space, 1.6em) auto 0;
	padding: var(--faf-load-more-pad, 0.6em 1.4em);
	font: inherit;
	color: var(--faf-load-more-color, inherit);
	cursor: pointer;
	background: var(--faf-load-more-bg, transparent);
	border: var(--faf-load-more-border, 1px solid rgba(128, 128, 128, 0.4));
	border-radius: var(--faf-load-more-radius, 999px);
}

.faf-load-more[aria-busy='true'] {
	opacity: 0.6;
	cursor: default;
}

/* A trigger, not furniture: it must occupy no visual space of its own, but it
   needs a box for the observer to intersect. */
.faf-ahead-sentinel {
	height: 1px;
	margin: 0;
}

/* Revealed items rise into place once. The class is only added when the visitor
   has not asked for less motion; this query is the second line of that defence,
   for a preference that changes after the class was set. */
.faf-batch-in {
	animation: faf-batch-in var(--faf-batch-anim, 260ms) ease-out both;
}

@keyframes faf-batch-in {
	from {
		opacity: 0;
		transform: translateY(0.5em);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

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

/* ---------------------------------------------------------------------------
   @compat color-mix
   Below Chrome 111 / Safari 16.2 a color-mix() does not flatten, it removes
   the property — and because these mixes contain a var() the browser accepts
   the declaration, then fails at substitution, so the plain base above is NOT
   what it falls back to. Hence a feature query. The var(--token, ...) lookup
   stays outside it, so a host theme keeps control on every browser; only the
   plugin's own default changes shape. Delete this block AND the literals it
   shadows when the floor passes. See ../COLOR-COMPAT.md.
   ------------------------------------------------------------------------ */
@supports (color: color-mix(in oklab, red, blue)) {
	.faf-drawer-trigger:hover,
	.faf-all-btn:hover {
		background: var(--faf-trigger-bg-hover, color-mix(in oklab, var(--_faf-trigger-bg) 88%, #000));
	}
}
