/**
 * ui.css — the components this pass added, and the motion the whole shop shares.
 *
 * WHY THIS IS A NEW FILE AND NOT FOUR EDITS.
 *
 * Three of the four things below did not exist before: the full-page blur veil,
 * the language switcher, and the hero slider's controls. A component gets a
 * file in this theme (header.css, search.css, cart.css, hero.css …), and
 * scattering three new components through three existing files would have made
 * every one of them harder to read for no benefit. The fourth section is the
 * shared micro-interaction layer, which is genuinely cross-cutting and belongs
 * nowhere else.
 *
 * IT IS ENQUEUED LAST, ON PURPOSE, AND THAT ORDERING IS LOAD-BEARING.
 * src/Assets.php calls wp_enqueue_style( 'bedi-ui' ) after both of its
 * conditional branches, so among stylesheets with no dependency relation this
 * one is printed last. Section 4 gives the hero's CTA, the rail's rows and
 * WooCommerce's product tiles hover and press states at the SAME specificity
 * hero.css and woo.css already use on those elements — a tie that is settled by
 * print order and nothing else. Enqueued earlier, every one of those rules
 * would parse, apply, and be silently overwritten.
 *
 * Its declared dependencies are only the handles that load on EVERY request.
 * Naming bedi-hero or bedi-woo would order it correctly and also drag 100KB of
 * conditional stylesheets onto every URL on the site, because WordPress
 * enqueues a dependency automatically. The note on the manifest entry in
 * Assets.php has the full argument.
 *
 * TOKENS COME FROM base.css, motion.css AND hero.css. --bedi-dur*,
 * --bedi-ease*, --bedi-space-*, --bedi-radius-*, --bedi-z-* and the palette are
 * defined in the first two; --hero-radius and --hero-pad-inline-start in the
 * third, and this file reads them rather than repeating their values so the
 * slider frame and the pager cannot drift away from the slide they sit on.
 * This file defines exactly one new custom property — --bedi-hero-tick, which
 * ui.js writes from the markup's data-autoplay — and none on :root.
 *
 * EVERY ANIMATION IN THIS FILE IS transform AND opacity ONLY, with two named
 * exceptions that are both paint-only on a single element: the veil's
 * backdrop-filter (section 1) and the dot's inline-size (section 3). Nothing
 * here animates a property that triggers layout on anything but itself.
 *
 * Sections
 *   1. The page veil          — the blur behind a hovered category rail
 *   2. The language switcher  — utility bar, Georgian / English
 *   3. The hero slider        — track, arrows, dots, pause, counter
 *   4. Shared micro-interactions
 *   5. The page-level empty state — 404, no results, empty category
 *   6. Reduced motion and forced colours
 */

/* =========================================================================
 * 1. THE PAGE VEIL
 *
 * The brief: "when hovering over categories don't blur the items but blur the
 * whole page other than header and top bar."
 *
 * hero.css used to blur the rail's own NON-hovered rows, which made the list
 * you were reading the only sharp thing in a card of mush. That rule is retired
 * (hero.css section 4 has the note). This is the replacement, and it inverts
 * the relationship: the rail stays completely sharp and the PAGE behind it goes
 * soft.
 *
 * HOW THE HEADER STAYS SHARP, WHICH IS THE WHOLE TRICK.
 *
 * backdrop-filter blurs what is painted BEHIND the element, in the same
 * stacking context, BELOW it in z-order. Nothing above it is touched. So:
 *
 *     --bedi-z-header    100   the header and the utility bar   ← sharp
 *     --bedi-z-rail-lift  70   the category rail                ← sharp
 *     --bedi-z-veil       60   this element
 *     (everything else)   auto the page                         ← blurred
 *
 * The header is above the veil, so it is not in the veil's backdrop and cannot
 * blur however hard the veil tries. That is also why the rail is LIFTED rather
 * than the veil being given a hole: an element cannot be excluded from a
 * backdrop, it can only be put on top of the thing doing the blurring.
 *
 * THE VEIL IS A SIBLING OF THE HEADER, NOT A CHILD. header.php renders it as
 * the first child of .bedi-site. Inside .bedi-header it would be trapped in the
 * header's stacking context and would paint over the page at z-index 100+,
 * blurring the bar it is supposed to spare.
 *
 * pointer-events: none ALWAYS, in both states. The veil covers the viewport; if
 * it ever accepted a pointer it would eat the click on every link on the page,
 * and — because the rail's :hover is what raises it — it would also break its
 * own trigger the instant it appeared. It is a purely optical object.
 *
 * :has() IS THE TRIGGER AND THERE IS A FALLBACK. Modern browsers raise the veil
 * from CSS alone, with no listener and no class write, which means it cannot
 * lag the pointer. assets/js/ui.js writes .bedi-has-rail-focus on the root for
 * browsers without :has(); the two selectors are separate rules rather than a
 * list, because an unsupported :has() selector invalidates the WHOLE list it
 * appears in and would take the fallback down with it.
 * ====================================================================== */

.bedi-page-veil {
	/*
	 * position: fixed and inset: 0 — the veil covers the viewport, not the
	 * document. A veil sized to the document would allocate a backdrop the
	 * height of the whole page for a blur that is only ever seen through one
	 * screenful of it.
	 */
	inset: 0;
	opacity: 0;
	pointer-events: none;
	position: fixed;
	/*
	 * visibility, not display, so the pair can transition. It is delayed on the
	 * way out only — `visibility 0s linear var(--bedi-dur)` — so the fade
	 * finishes before the element is taken out of the rendering tree; on the way
	 * in the delay is 0 and it appears immediately.
	 */
	visibility: hidden;
	transition:
		opacity var(--bedi-dur) var(--bedi-ease-out),
		visibility 0s linear var(--bedi-dur);
	z-index: var(--bedi-z-veil);
}

@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
	.bedi-page-veil {
		/*
		 * 7px and a light wash. The blur alone is not enough on this shop: a
		 * product archive is a wall of white photography on white, and blurring
		 * white against white moves almost nothing. The 46% white pushes the
		 * whole page back a step so the rail reads as lifted off it rather than
		 * merely sharper than it. saturate(105%) is there to stop the wash
		 * draining the colour out of the product shots underneath — a flat white
		 * overlay greys them, a slight saturation lift keeps them recognisable.
		 */
		-webkit-backdrop-filter: blur(7px) saturate(105%);
		backdrop-filter: blur(7px) saturate(105%);
		background-color: rgba(255, 255, 255, 0.46);
	}
}

/*
 * No backdrop-filter: a plain wash, and a heavier one. There is no blur to do
 * the separating, so the only tool left is contrast; 62% still leaves the page
 * legible underneath, which matters because this is the state a visitor gets in
 * a browser that is otherwise fine.
 */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
	.bedi-page-veil {
		background-color: rgba(255, 255, 255, 0.62);
	}
}

/*
 * The trigger. Two rules, never one selector list — see the note above.
 *
 * `:has(...)` on :root rather than on body, because the veil is inside
 * .bedi-site and the rail is inside <main>; :root is the nearest ancestor of
 * both that is guaranteed to exist whatever a page template does in between.
 */
:root:has(.bedi-hero__rail-list:hover) .bedi-page-veil,
:root:has(.bedi-hero__rail-list:focus-within) .bedi-page-veil {
	opacity: 1;
	transition:
		opacity var(--bedi-dur) var(--bedi-ease-in),
		visibility 0s linear 0s;
	visibility: visible;
}

.bedi-has-rail-focus .bedi-page-veil {
	opacity: 1;
	transition:
		opacity var(--bedi-dur) var(--bedi-ease-in),
		visibility 0s linear 0s;
	visibility: visible;
}

/*
 * THE RAIL RIDES OVER THE VEIL.
 *
 * .bedi-hero__rail is `position: relative` with z-index auto in hero.css, so it
 * takes part in its ancestor's stacking context rather than making one. Giving
 * it a z-index here puts the whole rail — card, rows, and the fly-out that
 * hangs off them — above the veil in one move.
 *
 * The transition on z-index is deliberately ABSENT. z-index is not
 * interpolatable in a useful way and animating it produces a step in the middle
 * of the fade; the rail snaps to the top of the pile the instant the pointer
 * arrives, which is correct — it is already the thing under the cursor.
 *
 * Only inside the hover/focus condition. At rest the rail must drop back to its
 * own --bedi-z-rail, or it would sit above page content that scrolls past it.
 */
:root:has(.bedi-hero__rail-list:hover) .bedi-hero__rail,
:root:has(.bedi-hero__rail-list:focus-within) .bedi-hero__rail {
	z-index: var(--bedi-z-rail-lift);
}

.bedi-has-rail-focus .bedi-hero__rail {
	z-index: var(--bedi-z-rail-lift);
}

/*
 * A touch device has no hover, so it would never raise the veil — but it CAN
 * focus a rail link with an external keyboard, and :focus-within above covers
 * that. What it must not do is blur the page because a finger happens to be
 * resting on a row mid-scroll. The pointer query is the standard test for that
 * and it is why this rule exists rather than being folded into the two above.
 */
@media (hover: none) {
	.bedi-page-veil {
		opacity: 0;
		visibility: hidden;
	}
}

/* =========================================================================
 * 2. THE LANGUAGE SWITCHER
 *
 * Utility bar, right-hand cell, after the pages menu. Two languages, Georgian
 * and English, each with a circle-flags disc.
 *
 * IT SITS ON #101A41, WHICH DECIDES EVERY COLOUR HERE. The trigger's ink is
 * --bedi-hdr-ink-on-utility (#FFFFFF, 16.8:1 on the band) and its resting fill
 * is a 10% white — an opaque chip colour would have had to be maintained
 * against the band by hand, and a translucent one tracks it for free if the
 * band is ever re-toned. The MENU, by contrast, is a white popover on the page
 * below the band, so it uses the page palette and not the band's.
 * ====================================================================== */

.bedi-lang {
	/*
	 * The positioning context for the popover, and the reason the popover can be
	 * absolute rather than fixed: absolute keeps it glued to the trigger when
	 * the utility band scrolls away, with no scroll listener and no re-measure.
	 */
	position: relative;
	flex: none;
}

.bedi-lang__trigger {
	align-items: center;
	appearance: none;
	background-color: rgba(255, 255, 255, 0.1);
	border: 0;
	border-radius: var(--bedi-radius-pill);
	color: var(--bedi-hdr-ink-on-utility);
	column-gap: var(--bedi-space-3xs);
	cursor: pointer;
	display: inline-flex;
	font-family: var(--bedi-font-display);
	font-size: var(--bedi-text-sm);
	font-weight: var(--bedi-weight-medium);
	line-height: 1;
	padding: 5px 10px 5px 5px;
	transition:
		background-color var(--bedi-dur-micro) var(--bedi-ease-out),
		transform var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-lang__trigger:hover,
.bedi-lang__trigger:focus-visible {
	background-color: rgba(255, 255, 255, 0.18);
}

/*
 * The press. -1px rather than a scale, because this chip sits in a 64px band
 * next to a menu of text links: a scaling control in a row of static ones draws
 * the eye to itself every time the pointer crosses it. A 1px dip reads as a
 * button and nothing more.
 */
.bedi-lang__trigger:active {
	transform: translateY(1px);
}

.bedi-lang__trigger:focus-visible {
	outline: var(--bedi-focus-width) solid var(--bedi-hdr-ink-on-utility);
	outline-offset: var(--bedi-focus-offset);
}

.bedi-lang__flag-slot {
	display: inline-flex;
}

/*
 * The disc. A 1px inset ring rather than a border: a border would grow the
 * element and shift the label, and the ring is only there to stop the white
 * field of either flag dissolving into the band's few light pixels.
 */
.bedi-lang__flag {
	block-size: 22px;
	border-radius: var(--bedi-radius-round);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
	display: block;
	inline-size: 22px;
}

.bedi-lang__code {
	letter-spacing: 0.02em;
}

/*
 * The chevron flips when the menu opens. It is the one piece of state on the
 * closed control, so it is worth animating properly: 220ms with the standard
 * ease, not a snap.
 */
.bedi-lang__chevron {
	display: inline-flex;
	opacity: 0.75;
	transition: transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-lang__trigger[aria-expanded="true"] .bedi-lang__chevron {
	transform: rotate(180deg);
}

/*
 * THE POPOVER.
 *
 * inset-inline-end: 0 rather than start, so it hangs from the RIGHT edge of the
 * trigger. This control is the last thing in the band; anchored from the left it
 * would overflow the viewport on a 768px tablet, which is exactly the width at
 * which the band first appears.
 *
 * z-index is one above the header's own bar so the popover clears it. It is
 * INSIDE .bedi-header, whose stacking context is --bedi-z-header, so this number
 * is resolved among the header's own children — it is not competing with the
 * page ladder and does not belong on it.
 */
.bedi-lang__menu {
	background-color: var(--bedi-surface);
	border: var(--bedi-border-width) solid var(--bedi-hdr-line);
	border-radius: var(--bedi-radius-lg);
	box-shadow: var(--bedi-hdr-shadow);
	inset-block-start: calc(100% + 8px);
	inset-inline-end: 0;
	list-style: none;
	margin: 0;
	min-inline-size: 170px;
	opacity: 0;
	overflow: hidden;
	padding: var(--bedi-space-3xs);
	position: absolute;
	/*
	 * The entrance: a 6px drop with the origin at the top-right corner, so the
	 * panel appears to unfold FROM the trigger rather than fade in over it. The
	 * 0.96 scale is small on purpose — a popover this size that scales from 0.8
	 * reads as a modal, which it is not.
	 */
	transform: translateY(-6px) scale(0.96);
	transform-origin: 100% 0;
	transition:
		opacity var(--bedi-dur-micro) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
	z-index: 101;
}

/*
 * ui.js removes [hidden] a frame BEFORE it adds .is-open, so the element is laid
 * out in its closed state and the transition has a value to start from. Both
 * are needed: [hidden] is display:none, which nothing can transition out of.
 */
.bedi-lang__menu[hidden] {
	display: none;
}

.bedi-lang__menu.is-open {
	opacity: 1;
	transform: translateY(0) scale(1);
}

.bedi-lang__item + .bedi-lang__item {
	margin-block-start: 2px;
}

.bedi-lang__link {
	align-items: center;
	border-radius: var(--bedi-radius-md);
	color: var(--bedi-hdr-ink);
	column-gap: var(--bedi-space-2xs);
	display: flex;
	font-size: var(--bedi-text-base);
	padding: var(--bedi-space-2xs) var(--bedi-space-xs);
	text-decoration: none;
	transition:
		background-color var(--bedi-dur-micro) var(--bedi-ease-out),
		color var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-lang__link:hover,
.bedi-lang__link:focus-visible {
	background-color: var(--bedi-hdr-wash);
	color: var(--bedi-hdr-accent-deep);
}

.bedi-lang__name {
	flex: 1 1 auto;
	min-inline-size: 0;
}

/*
 * The tick occupies its cell whether or not it is drawn, so the two rows have
 * the same width and the menu does not reflow when the current language
 * changes. Scaled to 0 rather than hidden, so switching language animates the
 * tick into place on the next page rather than making it pop.
 */
.bedi-lang__tick {
	color: var(--bedi-hdr-accent);
	display: inline-flex;
	flex: none;
	opacity: 0;
	transform: scale(0.4);
	transition:
		opacity var(--bedi-dur-micro) var(--bedi-ease-in),
		transform var(--bedi-dur) var(--bedi-ease-in);
}

.bedi-lang__link.is-current .bedi-lang__tick {
	opacity: 1;
	transform: scale(1);
}

.bedi-lang__link.is-current {
	color: var(--bedi-hdr-accent-deep);
	font-weight: var(--bedi-weight-medium);
}

/*
 * The band itself is hidden below 48em (header.css section 5), so the switcher
 * goes with it and this rule is belt and braces for a template that renders the
 * part on its own. The panel's own language row, if one is ever added, is a
 * different component.
 */
@media (max-width: 47.9375em) {
	.bedi-lang {
		display: none;
	}
}

/* =========================================================================
 * 3. THE HERO SLIDER
 *
 * The right-hand side of the hero was a single static banner. It is three
 * slides now, and the brief is explicit that it should be "not static block but
 * the slider".
 *
 * THE TRACK IS A NATIVE SCROLLER WITH SNAP POINTS, NOT A TRANSFORMED STRIP.
 * A translateX track has to be driven every frame of a drag, needs its own
 * momentum maths on release, and fights iOS's own touch scrolling. Snap points
 * give all three to the platform: the swipe is native and interruptible, it
 * never touches the main thread, and the programmatic move is one scrollTo().
 * The cost is that the "current slide" has to be READ from scrollLeft rather
 * than held in a variable — ui.js does that, once per scroll-end.
 *
 * WHAT THIS BUYS WITH NO JAVASCRIPT AT ALL: a horizontally swipeable strip of
 * three real banners. Not an empty box, not three stacked headings. Every
 * control is rendered [hidden] and un-hidden by ui.js precisely because the
 * controls are the only part that needs it.
 * ====================================================================== */

/*
 * THE SLIDER IS THE CLIPPING FRAME; THE SLIDES INSIDE KEEP THEIR OWN GEOMETRY.
 *
 * `order` and `min-inline-size` are NOT repeated here — hero.css owns them, on
 * this same selector, because they are the grid CELL's properties and the cell
 * is what this element is. Everything below is new behaviour the cell did not
 * have when it held one static panel.
 *
 * --hero-radius is hero.css's own token, not a literal: the slide inside draws
 * its corners with it too, and a second copy of `10px` here is the kind of pair
 * that quietly diverges.
 */
.bedi-hero__slider {
	/* The positioning context for the arrows and the pager, both of which are
	   absolute against this box rather than against a slide — they must not move
	   with the track. */
	position: relative;
	border-radius: var(--hero-radius, 10px);
	/*
	 * The clip. Without it the track's third slide paints past the hero band's
	 * rounded corner and the arrows' discs are drawn outside the frame.
	 */
	overflow: hidden;
}

.bedi-hero__track {
	display: grid;
	grid-auto-columns: 100%;
	grid-auto-flow: column;
	/*
	 * AIR BETWEEN THE SLIDES.
	 *
	 * The columns are 100% of the track, so a snapped slide still fills it
	 * exactly and the gap is only ever seen mid-swipe — which is the whole
	 * point. Without it the four banners slid past each other edge to edge and
	 * a drag looked like one continuous image being dragged rather than four
	 * separate cards, particularly between the two that share a dark backdrop.
	 *
	 * It does NOT need matching scroll-padding: each slide's snap-align is
	 * `start` and the gap sits after the slide, not before it, so the snap
	 * position is unchanged.
	 */
	column-gap: var(--bedi-space-4, 16px);
	/*
	 * mandatory, not proximity: with three full-width slides there is no
	 * meaningful in-between position, and proximity lets a slow drag come to
	 * rest showing two half slides.
	 */
	scroll-snap-type: x mandatory;
	overflow-x: auto;
	overscroll-behavior-x: contain;
	/*
	 * The scrollbar is suppressed on every engine. This is a three-item banner,
	 * not a document: the dots below are the position indicator and a 15px
	 * gutter of grey under the artwork is the single ugliest thing a
	 * scroll-snap carousel can do to a hero.
	 */
	scrollbar-width: none;
	-ms-overflow-style: none;
}

.bedi-hero__track::-webkit-scrollbar {
	display: none;
}

/*
 * THE SLIDE ADDS SNAPPING AND NOTHING ELSE.
 *
 * Its fill, radius, padding, min-height, flex direction and stacking context
 * are all in hero.css under this same selector — they are the export's recorded
 * panel geometry and they did not change when the panel became a slide. The two
 * declarations here are the only ones that belong to it being part of a track.
 */
.bedi-hero__slide {
	/*
	 * `center` rather than `start`: a slide narrower than the track — which
	 * happens for a frame mid-resize, before the grid re-measures — snaps to the
	 * middle instead of sliding to the left edge and showing a sliver of its
	 * neighbour.
	 */
	scroll-snap-align: center;
	/*
	 * A fast flick must not skip a slide. Without `always`, a hard swipe on a
	 * trackpad crosses two snap points and lands on the third banner, and the
	 * visitor never sees the second one at all.
	 */
	scroll-snap-stop: always;
}

/*
 * THE SCRIM, AND IT IS NOT DECORATION — IT IS WHAT MAKES THE COPY LEGIBLE.
 *
 * Each of the three artworks is drawn 16:9 with its left 40% kept empty for the
 * text. The slide it lands in is closer to 1.4:1, and `object-fit: cover` crops
 * the difference off BOTH sides — so at a mid-width viewport the products slide
 * left into the space the copy needs, and a white 42px headline ends up over a
 * backlit keyboard. Relying on the artwork's own empty corner only works at one
 * viewport width, and there is no such thing as one viewport width.
 *
 * A gradient from the panel's own #000338 across the inline-start half fixes it
 * at every size and for every future image, including a photograph of real
 * stock passed through `bedi_theme_hero_slides`. 92% at the edge rather than
 * 100% so the artwork is still faintly present behind the text and the slide
 * does not look like a dark box with a picture stuck to one end.
 *
 * z-index 1: above the backdrop, which hero.css pins at -1, and below
 * .bedi-hero__body at 7 and the collage's recorded 3–6. The slide isolates, so
 * none of those numbers leak out of it.
 *
 * `inset: 0` and not a width, because the gradient's own stops decide where it
 * stops being opaque — sizing the element instead would put a hard edge down
 * the middle of the slide at the point the gradient was cut off.
 */
.bedi-hero__slide::before {
	background-image: linear-gradient(
		to right,
		rgba(0, 3, 56, 0.92) 0%,
		rgba(0, 3, 56, 0.78) 26%,
		rgba(0, 3, 56, 0.35) 52%,
		rgba(0, 3, 56, 0) 74%
	);
	content: "";
	inset: 0;
	pointer-events: none;
	position: absolute;
	z-index: 1;
}

/*
 * THE SCRIM COMES OFF ANY SLIDE THAT CARRIES ITS OWN ARTWORK.
 *
 * The gradient above is a navy wash at 92% down the left edge, and it was
 * right when it was written: the headline and the sentence were white HTML
 * laid over a photograph, and without a dark ground under them they were
 * unreadable on a pale image.
 *
 * The copy is part of the picture now, so the wash has nothing to protect and
 * is simply painting over the client's artwork — which is what has been making
 * the slider look washed out and different from the file that was supplied.
 * It survives on a slide with no backdrop, where the collage still needs it.
 *
 * It lives in ui.css rather than hero.css, which is worth recording because it
 * is the reason the first two attempts to remove it looked in the wrong file.
 */
.bedi-hero__slide:has(.bedi-hero__backdrop)::before {
	background-image: none;
	content: none;
}

/*
 * Under 48em the copy column is the FULL width of the slide — hero.css takes
 * --hero-body-width to 100% there — so a gradient that fades out by 74% of the
 * way across would leave the end of every line, and the headline's 100px
 * overhang, sitting on bare photography. The scrim becomes an even top-to-
 * bottom veil at that width instead.
 */
@media (max-width: 47.9375em) {
	.bedi-hero__slide::before {
		background-image: linear-gradient(
			to bottom,
			rgba(0, 3, 56, 0.72) 0%,
			rgba(0, 3, 56, 0.82) 100%
		);
	}
}

/*
 * THE HEADLINE IS FLUID BETWEEN THE TWO RECORDED SIZES.
 *
 * hero.css steps --hero-heading-size from 32px to the export's 42px at 64em and
 * holds it there. 42px is right at 1440; at 1024 — the first width where the
 * rail takes its 300px column — the copy has about 380px to work in, and
 * "მოწყობილობები" is a single 13-character word that does not break. It wrapped
 * mid-word, which Georgian does not do gracefully.
 *
 * The clamp keeps BOTH recorded values as its bounds and only fills the gap
 * between them: 42px is still exactly what renders at and above ~1370px, and
 * nothing below 30px is reachable. It is written here rather than in hero.css
 * because the extracted 42px there is a recorded number and should stay one —
 * this is the slider's accommodation of it, not a correction to it.
 */
@media (min-width: 64em) {
	.bedi-hero__slide {
		--hero-heading-size: clamp(30px, 3.05vw, 42px);
	}
}

/*
 * AND THE SAME PROBLEM AT THE OTHER END, FOR A DIFFERENT REASON.
 *
 * Below 64em the recorded size is 32px, the copy column is the full width of
 * the slide less 24px of padding, and the headline is allowed to overhang that
 * column by 100px — which hero.css documents as deliberate and safe, because
 * the slide clips. That was true of the single headline the token was tuned
 * against: "ტექნიკა და აქსესუარები" is two short words.
 *
 * The slider ships three CATEGORY names, and "პერიფერიალები" is thirteen
 * glyphs with nowhere to break. Measured at 375px it came to 311px in a 311px
 * gap — the final ი sat exactly on the clip. A headline that is one glyph away
 * from being cut in half is not a headline anyone should have to trust.
 *
 * The clamp costs about four points at phone width and reaches the recorded
 * 32px again by ~432px. The overhang is untouched: it is a recorded value with
 * a documented reason, and the word now fits inside the column without needing
 * it.
 */
@media (max-width: 63.9375em) {
	.bedi-hero__slide {
		--hero-heading-size: clamp(22px, 7.4vw, 32px);
	}
}

/*
 * THE COPY RISES AS THE SLIDE ARRIVES.
 *
 * `animation-timeline: view()` drives it from the slide's own position in the
 * scroller rather than from a class ui.js would have to write on every scroll
 * frame — the animation is on the compositor and the main thread is never
 * involved. Browsers without scroll-driven animations ignore the timeline and
 * run the animation once on load, which is a perfectly good degradation: the
 * copy is at full opacity either way, it just does not re-play on every swipe.
 *
 * The range stops at `cover 46%` so the copy is fully settled slightly before
 * the slide is centred; landing exactly on centre makes the text look like it
 * is still catching up when the scroll has visibly stopped.
 */
@supports (animation-timeline: view()) {
	.bedi-hero__slide .bedi-hero__body {
		animation: bedi-hero-copy-in linear both;
		animation-timeline: view(inline);
		animation-range: cover 6% cover 46%;
	}
}

@keyframes bedi-hero-copy-in {
	from {
		opacity: 0;
		transform: translateX(28px);
	}

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

/*
 * THE ARROWS.
 *
 * Vertically centred, inset from the edges, and — unlike the pager — they are
 * NOT hidden on a touch screen. A tablet user can swipe, but a tablet user with
 * a trackpad or a stylus still reaches for an arrow, and hiding a control on the
 * assumption that a touch-capable device is a touch-only device is how a laptop
 * with a touchscreen ends up with no controls at all.
 */
.bedi-hero__controls {
	position: absolute;
	inset-block: 0;
	inset-inline: var(--bedi-space-2xs);
	display: flex;
	align-items: center;
	justify-content: space-between;
	pointer-events: none;
}

.bedi-hero__controls[hidden] {
	display: none;
}

.bedi-hero__arrow {
	align-items: center;
	appearance: none;
	/*
	 * A translucent white disc with a blur behind it, so one button works over
	 * all three artworks — a solid fill would have to be chosen against whichever
	 * happened to be underneath, and there are three of them.
	 */
	background-color: rgba(255, 255, 255, 0.16);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	block-size: 44px;
	border: 0;
	border-radius: var(--bedi-radius-round);
	box-shadow: 0 6px 20px -8px rgba(0, 0, 0, 0.45);
	color: #ffffff;
	cursor: pointer;
	display: flex;
	inline-size: 44px;
	justify-content: center;
	/* The wrapper is inert so it never blocks a swipe across the middle of the
	   slide; the buttons themselves take pointers back. */
	pointer-events: auto;
	padding: 0;
	transition:
		background-color var(--bedi-dur-micro) var(--bedi-ease-out),
		opacity var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

/*
 * At rest the arrows sit at 0 and tucked 8px toward their own edge; the slider's
 * :hover and :focus-within bring them in. On a touch device there is no hover,
 * so the `@media (hover: none)` rule at the end of this block leaves them
 * permanently visible rather than permanently invisible.
 */
.bedi-hero__arrow--prev {
	opacity: 0;
	transform: translateX(-8px);
}

.bedi-hero__arrow--next {
	opacity: 0;
	transform: translateX(8px);
}

.bedi-hero__slider:hover .bedi-hero__arrow,
.bedi-hero__slider:focus-within .bedi-hero__arrow {
	opacity: 1;
	transform: none;
}

.bedi-hero__arrow:hover {
	background-color: rgba(255, 255, 255, 0.3);
	transform: scale(1.08);
}

.bedi-hero__arrow:active {
	transform: scale(0.92);
}

/*
 * A disabled arrow is dimmed and inert but NOT removed. ui.js sets [disabled]
 * at the two ends of a non-looping track; keeping the button in the layout
 * stops the other one jumping sideways when it does.
 */
.bedi-hero__arrow[disabled] {
	cursor: default;
	opacity: 0.28 !important;
	transform: none !important;
}

.bedi-hero__arrow:focus-visible {
	opacity: 1;
	outline: var(--bedi-focus-width) solid #ffffff;
	outline-offset: var(--bedi-focus-offset);
	transform: none;
}

@media (hover: none) {
	.bedi-hero__arrow--prev,
	.bedi-hero__arrow--next {
		opacity: 1;
		transform: none;
	}
}

/*
 * THE PAGER: dots, pause, counter — one row, bottom-left, over the artwork.
 *
 * Bottom-LEFT rather than centred, because every one of the three artworks
 * keeps its left 40% deliberately empty for the copy, and the copy's own bottom
 * edge is the button. Centred dots would land on the products.
 */
.bedi-hero__pager {
	align-items: center;
	column-gap: var(--bedi-space-2xs);
	display: flex;
	inset-block-end: var(--bedi-space-sm);
	/*
	 * CENTRED, AT EVERY WIDTH.
	 *
	 * These used to be anchored to --hero-pad-inline-start so they sat directly
	 * under the call-to-action button. There is no longer a button to sit under
	 * — the artwork carries it — so the dots are the only thing left on the
	 * slide and they belong in the middle of it. Mobile already centred them;
	 * this makes desktop agree instead of the two disagreeing by 40px.
	 */
	inset-inline: 0;
	justify-content: center;
	position: absolute;
	z-index: 2;
}

.bedi-hero__pager[hidden] {
	display: none;
}

.bedi-hero__dots {
	align-items: center;
	column-gap: 6px;
	display: flex;
}

/*
 * THE DOT IS A TRACK AND THE FILL INSIDE IT IS THE PROGRESS BAR.
 *
 * The current dot stretches from 8px to 30px, and inside it a fill sweeps left
 * to right over the autoplay interval — so the dots are both the position
 * indicator and the countdown, and the slider never moves without having shown
 * that it was about to.
 *
 * inline-size IS animated here and it is the one layout property this file
 * touches. It is confined to a 30px box in a flex row of three, the row is the
 * last thing painted on the slide, and nothing reads its geometry — the cost is
 * a re-layout of one flex line, once per slide change. A transform:scaleX()
 * alternative would have squashed the dot's rounded ends into ellipses.
 */
.bedi-hero__dot {
	appearance: none;
	background-color: rgba(255, 255, 255, 0.35);
	block-size: 8px;
	border: 0;
	border-radius: var(--bedi-radius-pill);
	cursor: pointer;
	display: block;
	inline-size: 8px;
	overflow: hidden;
	padding: 0;
	position: relative;
	transition:
		background-color var(--bedi-dur) var(--bedi-ease-out),
		inline-size var(--bedi-dur-lg) var(--bedi-ease-out);
}

.bedi-hero__dot:hover {
	background-color: rgba(255, 255, 255, 0.6);
}

.bedi-hero__dot.is-current {
	background-color: rgba(255, 255, 255, 0.35);
	inline-size: 30px;
}

.bedi-hero__dot:focus-visible {
	outline: var(--bedi-focus-width) solid #ffffff;
	outline-offset: 3px;
}

/*
 * The fill. transform-origin at the inline-start edge and scaleX from 0 to 1 —
 * a width animation here would fight the dot's own width transition above and
 * the two would arrive at different times.
 *
 * The duration is --bedi-hero-tick, which ui.js writes onto the slider from the
 * data-autoplay attribute. Declared with a fallback so a missing property gives
 * a sensible 6s rather than an invalid animation that never runs.
 */
.bedi-hero__dot-fill {
	background-color: #ffffff;
	border-radius: inherit;
	display: block;
	inset: 0;
	position: absolute;
	transform: scaleX(0);
	transform-origin: 0 50%;
}

.bedi-hero__dot.is-current .bedi-hero__dot-fill {
	animation: bedi-hero-tick var(--bedi-hero-tick, 6000ms) linear forwards;
}

/*
 * Paused — by the button, by hover, by focus, or because the tab went away.
 * `animation-play-state` freezes the fill exactly where it is, so resuming
 * continues the countdown instead of restarting it. That is the honest
 * behaviour: the visitor paused it three quarters of the way through and should
 * get the last quarter back, not a fresh six seconds.
 */
.bedi-hero__slider.is-paused .bedi-hero__dot-fill {
	animation-play-state: paused;
}

@keyframes bedi-hero-tick {
	from {
		transform: scaleX(0);
	}

	to {
		transform: scaleX(1);
	}
}

.bedi-hero__pause {
	align-items: center;
	appearance: none;
	background-color: rgba(255, 255, 255, 0.16);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	block-size: 26px;
	border: 0;
	border-radius: var(--bedi-radius-round);
	color: #ffffff;
	cursor: pointer;
	display: flex;
	inline-size: 26px;
	justify-content: center;
	margin-inline-start: var(--bedi-space-3xs);
	padding: 0;
	transition:
		background-color var(--bedi-dur-micro) var(--bedi-ease-out),
		transform var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-hero__pause:hover {
	background-color: rgba(255, 255, 255, 0.3);
}

.bedi-hero__pause:active {
	transform: scale(0.9);
}

.bedi-hero__pause:focus-visible {
	outline: var(--bedi-focus-width) solid #ffffff;
	outline-offset: var(--bedi-focus-offset);
}

/*
 * The two glyphs are stacked in the same 14px cell and swapped by
 * aria-pressed, so the button never changes size between states and the
 * swap can cross-fade. aria-pressed is the source of truth for BOTH the
 * visual and the assistive-technology state — there is no second class to
 * fall out of step with it.
 */
.bedi-hero__pause-icon {
	display: grid;
	place-items: center;
}

.bedi-hero__pause-glyph,
.bedi-hero__play-glyph {
	grid-area: 1 / 1;
	transition:
		opacity var(--bedi-dur-micro) var(--bedi-ease-out),
		transform var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-hero__play-glyph {
	opacity: 0;
	transform: scale(0.6);
}

.bedi-hero__pause[aria-pressed="true"] .bedi-hero__pause-glyph {
	opacity: 0;
	transform: scale(0.6);
}

.bedi-hero__pause[aria-pressed="true"] .bedi-hero__play-glyph {
	opacity: 1;
	transform: none;
}

/*
 * The 01 / 03 counter. aria-hidden in the markup: the dots are already
 * labelled "slide 1", "slide 2" and the live region announces the move, so
 * reading a third copy of the same number is noise. Tabular figures so the
 * numerals do not jitter as they change width.
 */
.bedi-hero__counter {
	color: rgba(255, 255, 255, 0.85);
	font-family: var(--bedi-font-display);
	font-size: var(--bedi-text-xs);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.06em;
	margin: 0;
	margin-inline-start: var(--bedi-space-2xs);
}

.bedi-hero__counter-sep {
	opacity: 0.55;
	padding-inline: 2px;
}

/*
 * Narrow: the pager moves to the middle and the arrows go. Under 48em the copy
 * is centred over the artwork rather than pinned left (hero.css), so a
 * left-aligned pager would sit under nothing, and a 44px disc on each edge of a
 * 360px slide covers a quarter of it. Swipe is the interaction here, and it
 * needs no chrome.
 */
@media (max-width: 47.9375em) {
	.bedi-hero__controls {
		display: none;
	}

	/*
	 * The mobile override that used to centre these is gone: the base rule
	 * centres them now, and a breakpoint restating what is already true is a
	 * rule somebody will later change on one side only.
	 */
}

/* =========================================================================
 * 4. SHARED MICRO-INTERACTIONS
 *
 * The brief: "everything you will do add very smooth and interactive micro
 * interactions, every revealing clicking or expanding or etc."
 *
 * Everything in this section is written as a rule the whole shop inherits,
 * rather than as a class a template has to remember to add. A micro-interaction
 * that has to be opted into is one that will be missing from the next component
 * somebody writes.
 *
 * THE ONE RULE ALL OF THESE FOLLOW: transform and opacity only, 120–220ms, and
 * the resting state is always the identity value. A control that has to be
 * hovered to look right is a control that looks wrong on a touch screen.
 * ====================================================================== */

/*
 * EVERY INTERACTIVE THING ACKNOWLEDGES A PRESS.
 *
 * :active is the one state that is universally missing from a CSS codebase and
 * universally noticed when it is absent — it is the difference between a page
 * that feels wired up and one that feels like a screenshot. 0.97 is deliberately
 * small: at 0.9 a button visibly shrinks, at 0.97 it feels like it depressed.
 *
 * The :not() list is not padding. .bedi-hero__dot animates its own width and a
 * scale on top of that fights it; .bedi-search__go, .bedi-hero__arrow and
 * .bedi-hero__pause each declare a compound :active transform of their own,
 * which this would override by source order. Each exclusion is a rule that
 * already does this job better for that element.
 */
a[href]:active,
button:not([disabled]):active,
[role="button"]:not([aria-disabled="true"]):active,
input[type="submit"]:active,
label.bedi-press:active {
	transition-duration: 60ms;
}

.bedi-btn:not([disabled]):active,
.bedi-cart-action:not([disabled]):active,
.bedi-hero__cta:active,
.bedi-lang__link:active,
.woocommerce a.button:active,
.woocommerce button.button:active,
.woocommerce .button:active {
	transform: scale(0.97);
}

/*
 * THE CALL TO ACTION LIFTS.
 *
 * The hero's button is the single most important control on the front page and
 * it had no hover state at all. -2px with a shadow underneath reads as the
 * button coming off the surface toward the pointer; on :active the lift is given
 * back, which is what makes the press feel like a press rather than a jump.
 */
.bedi-hero__cta {
	transition:
		background-color var(--bedi-dur) var(--bedi-ease-out),
		box-shadow var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-hero__cta:hover,
.bedi-hero__cta:focus-visible {
	box-shadow: 0 12px 28px -12px rgba(45, 129, 255, 0.75);
	transform: translateY(-2px);
}

.bedi-hero__cta:active {
	box-shadow: 0 4px 10px -6px rgba(45, 129, 255, 0.7);
	transform: translateY(0) scale(0.98);
}

/*
 * THE CATEGORY PILL OPENS THE MEGA MENU, SO IT SHOULD LOOK LIKE IT IS ABOUT TO.
 *
 * The nine-square icon rotates a few degrees and grows on hover, and the whole
 * pill lifts 1px. When the panel is actually open the icon holds a quarter turn
 * — so the control reads as "this is the thing that is open", which is the
 * state aria-expanded carries for everyone else.
 */
.bedi-cat-trigger {
	transition:
		background-color var(--bedi-dur) var(--bedi-ease-out),
		box-shadow var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-cat-trigger:hover {
	transform: translateY(-1px);
}

.bedi-cat-trigger:active {
	transform: translateY(0) scale(0.98);
}

.bedi-cat-trigger__icon {
	display: inline-flex;
	transition: transform var(--bedi-dur-lg) var(--bedi-ease-out);
}

.bedi-cat-trigger:hover .bedi-cat-trigger__icon {
	transform: rotate(-12deg) scale(1.1);
}

.bedi-cat-trigger[aria-expanded="true"] .bedi-cat-trigger__icon {
	transform: rotate(90deg);
}

/*
 * THE ACTION ICONS — account, wishlist, cart.
 *
 * The icon lifts inside a button that does not move. Moving the button would
 * shift its neighbours' optical alignment across a 90px bar; moving only the
 * 20px glyph inside it does not.
 */
.bedi-action .bedi-action__icon {
	display: inline-flex;
	transition: transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-action:hover .bedi-action__icon,
.bedi-action:focus-visible .bedi-action__icon {
	transform: translateY(-2px);
}

.bedi-action:active .bedi-action__icon {
	transform: translateY(0) scale(0.9);
}

/*
 * The wishlist heart gets its own: a heart that merely rises is a generic icon,
 * a heart that beats once is the only icon in the row with a personality. Two
 * beats, 520ms, and only on hover — never on load, and never in a loop.
 */
.bedi-action--wishlist:hover .bedi-action__icon {
	animation: bedi-heartbeat 520ms var(--bedi-ease-out) 1;
}

@keyframes bedi-heartbeat {
	0% {
		transform: scale(1);
	}

	22% {
		transform: scale(1.18);
	}

	42% {
		transform: scale(0.98);
	}

	62% {
		transform: scale(1.12);
	}

	100% {
		transform: scale(1);
	}
}

/*
 * THE CATEGORY ROW FOLLOWS THE POINTER.
 *
 * hero.css's sibling blur is gone (section 1 has the note) and this is what the
 * rail's hover feedback is now: the hovered row slides 3px toward its fly-out
 * and its chevron goes with it, a little further, so the arrow appears to lead.
 * Two elements moving different distances in the same direction is what makes it
 * read as a gesture rather than as a highlight.
 */
.bedi-hero__rail-link {
	transition:
		background-color var(--bedi-dur) var(--bedi-ease-out),
		color var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-hero__rail-item:hover > .bedi-hero__rail-link,
.bedi-hero__rail-item:focus-within > .bedi-hero__rail-link {
	transform: translateX(3px);
}

.bedi-hero__rail-arrow {
	transition:
		opacity var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-hero__rail-item:hover > .bedi-hero__rail-link .bedi-hero__rail-arrow,
.bedi-hero__rail-item:focus-within > .bedi-hero__rail-link .bedi-hero__rail-arrow {
	opacity: 1;
	transform: translateX(3px);
}

/*
 * THE FLY-OUT'S CHILDREN ARRIVE IN SEQUENCE.
 *
 * The panel itself already slides in (hero.css section 11). Its links used to
 * arrive with it, fully formed, which made a fly-out of nine children land like
 * a block. A 22ms stagger turns it into a list that unrolls — long enough to
 * read as sequential, short enough that the ninth row is in place 200ms after
 * the first.
 *
 * SIX STOPS, NOT NINE, AND :nth-child() RATHER THAN A CUSTOM PROPERTY PER ROW.
 * A --i written by JavaScript would be exact and would also mean a script
 * touching every fly-out on the page at render time. Six declarations cover the
 * common case; the seventh child onward inherits the sixth's delay and arrives
 * with it, which is invisible because by then the eye is already at the top of
 * the list.
 */
.bedi-hero__sublist li {
	opacity: 0;
	transform: translateX(-6px);
	transition:
		opacity var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li,
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li {
	opacity: 1;
	transform: none;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(1),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(1) {
	transition-delay: 40ms;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(2),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(2) {
	transition-delay: 62ms;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(3),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(3) {
	transition-delay: 84ms;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(4),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(4) {
	transition-delay: 106ms;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(5),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(5) {
	transition-delay: 128ms;
}

.bedi-hero__rail-item:hover > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(n + 6),
.bedi-hero__rail-item:focus-within > .bedi-hero__flyout .bedi-hero__sublist li:nth-child(n + 6) {
	transition-delay: 150ms;
}

/*
 * A fly-out link slides on hover, like the parent row it came from. Same
 * direction, same easing, half the distance — the sub-list is a smaller thing
 * and should move like one.
 */
.bedi-hero__sublink {
	display: block;
	transition:
		color var(--bedi-dur-micro) var(--bedi-ease-out),
		transform var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-hero__sublink:hover,
.bedi-hero__sublink:focus-visible {
	transform: translateX(2px);
}

/*
 * THE CATEGORY CARDS ON THE FRONT PAGE.
 *
 * A card that lifts and whose photograph grows slightly inside it — the image
 * moving faster than the frame is the whole effect, and it needs overflow
 * hidden on the frame to read as depth rather than as a picture escaping.
 */
.bedi-cards__item,
.bedi-card {
	transition:
		box-shadow var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.bedi-cards__item:hover,
.bedi-card:hover {
	transform: translateY(-4px);
}

.bedi-cards__item img,
.bedi-card img {
	transition: transform var(--bedi-dur-lg) var(--bedi-ease-out);
}

.bedi-cards__item:hover img,
.bedi-card:hover img {
	transform: scale(1.05);
}

/*
 * PRODUCT TILES, WOOCOMMERCE'S OWN MARKUP INCLUDED.
 *
 * ul.products li.product is what Woo prints on every archive, and it has no
 * theme class to hook. Naming it here is the only way to give the shop's
 * largest repeating element a hover state without editing a Woo template.
 */
.woocommerce ul.products li.product,
.bedi-product-card {
	transition:
		box-shadow var(--bedi-dur) var(--bedi-ease-out),
		transform var(--bedi-dur) var(--bedi-ease-out);
}

.woocommerce ul.products li.product:hover,
.bedi-product-card:hover {
	transform: translateY(-4px);
}

.woocommerce ul.products li.product img,
.bedi-product-card img {
	transition: transform var(--bedi-dur-lg) var(--bedi-ease-out);
}

.woocommerce ul.products li.product:hover img,
.bedi-product-card:hover img {
	transform: scale(1.04);
}

/*
 * LINK UNDERLINES GROW FROM THE START EDGE.
 *
 * A background-size transition on a linear-gradient rather than a
 * pseudo-element: no extra box, no positioning context, and it works on an
 * inline element that wraps across two lines — which a ::after underline does
 * not.
 *
 * Scoped to the two navigations that are plain text links. It is deliberately
 * NOT applied to `a` globally: product titles, breadcrumb trails and the footer
 * would all inherit an underline animation nobody asked for.
 */
.bedi-utility-nav__list a,
.bedi-panel__pages-list a {
	background-image: linear-gradient(currentColor, currentColor);
	background-position: 0 100%;
	background-repeat: no-repeat;
	background-size: 0% 1px;
	transition:
		background-size var(--bedi-dur) var(--bedi-ease-out),
		color var(--bedi-dur-micro) var(--bedi-ease-out);
}

.bedi-utility-nav__list a:hover,
.bedi-utility-nav__list a:focus-visible,
.bedi-panel__pages-list a:hover,
.bedi-panel__pages-list a:focus-visible {
	background-size: 100% 1px;
}

/*
 * THE FOCUS RING ITSELF ANIMATES.
 *
 * outline-offset is animatable and outline-color is not worth animating; going
 * from 0 to the theme's 2px offset makes the ring appear to snap outward from
 * the control, which is a clearer signal of "focus landed here" than a ring that
 * is simply present. 90ms — this is feedback for a keyboard user moving fast,
 * and anything slower is a ring that lags behind Tab.
 */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
	transition: outline-offset 90ms var(--bedi-ease-out);
}

/*
 * THE WOOCOMMERCE CART BLOCK'S EMPTY STATE GETS THE SAME ILLUSTRATION.
 *
 * The drawer's empty state is the theme's own markup and takes the picture from
 * mini-cart.php. The /cart/ PAGE is not: it is the `woocommerce/cart` BLOCK, and
 * its empty state is a heading whose ::before paints a 70px sad-face SVG that
 * WooCommerce inlines as a data URI. Two different empty carts, two different
 * drawings, one shop — and the page is the one a customer actually lands on
 * after removing their last item.
 *
 * A ::before SWAP, NOT A TEMPLATE OVERRIDE. The alternative was to copy
 * cart-empty.php into woocommerce/ and maintain WooCommerce's markup forever,
 * or to filter the block's output — for a background-image. This is one rule and
 * it survives every Woo update that does not rename the class.
 *
 * THE MASK IS THE PART THAT IS NOT OBVIOUS, AND IT COSTS AN HOUR IF YOU MISS
 * IT. Woo does NOT draw that icon as a background-image. It draws a solid
 * `background-color: currentColor` and MASKS it to a sad-face silhouette with
 * `mask-image: url(data:image/svg+xml;base64,...)`. Setting background-image
 * alone leaves the mask in place, so the illustration is punched through a
 * sad face and renders as an unrecognisable dark blob — which is exactly what
 * it did on the first attempt. The mask and the fill must BOTH be cleared.
 *
 * background-size and background-repeat are restated for the same class of
 * reason: Woo leaves them at the initial `auto` / `repeat`, which is invisible
 * for a masked colour fill and would tile a 440px raster four times over.
 */
.wc-block-cart__empty-cart__title.with-empty-cart-icon::before,
.wc-block-checkout-empty-cart__title.with-empty-cart-icon::before {
	animation: bedi-empty-art-in 420ms var(--bedi-ease-out) both;
	background-color: transparent;
	background-image: url("../img/empty/cart.webp");
	background-position: center;
	background-repeat: no-repeat;
	background-size: contain;
	block-size: 160px;
	inline-size: 160px;
	-webkit-mask-image: none;
	mask-image: none;
	margin-block-end: var(--bedi-space-sm);
	margin-inline: auto;
}

@keyframes bedi-empty-art-in {
	from {
		opacity: 0;
		transform: translateY(12px) scale(0.96);
	}

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

/* =========================================================================
 * 5. THE PAGE-LEVEL EMPTY STATE
 *
 * One component behind every dead end on the site: the 404, a search with no
 * hits, an empty archive, and a shop or category archive that matched nothing.
 * template-parts/empty-state.php renders it; four callers pass it different
 * content. The two rule sets it replaces — .bedi-no-results and .bedi-error404
 * in layout.css — are gone, and that file carries a note saying where they went.
 *
 * CENTRED, AND CAPPED AT A NARROW MEASURE. These pages have no content to lay
 * out, so the usual page grid has nothing to do; a centred column stops the one
 * sentence on the page running the full 1280px and reads as a designed state
 * rather than as a page that failed to load.
 *
 * THE WHOLE THING ENTERS AS ONE PIECE, IN FIVE STEPS. The parts are staggered
 * 60ms apart — picture, eyebrow, title, sentence, then the controls — so the
 * state assembles itself downward the way the eye reads it. It is an animation
 * and not a transition because there is no previous state to transition from:
 * the page arrives with this already in the document.
 * ====================================================================== */

.bedi-empty {
	margin-inline: auto;
	max-inline-size: 34rem;
	padding-block: var(--bedi-space-xl);
	text-align: center;
}

/*
 * A page whose entire content is this state gets more air above it, so the
 * illustration is not jammed under the header. .bedi-main--empty is set by
 * 404.php; the in-page callers are inside a template that has already printed a
 * title and want the tighter spacing.
 */
.bedi-main--empty .bedi-empty {
	padding-block: var(--bedi-space-2xl);
}

.bedi-empty__art {
	margin-block-end: var(--bedi-space-sm);
}

.bedi-empty__art img {
	block-size: auto;
	/*
	 * min() rather than a percentage alone: 240px is the size these were drawn
	 * for and 56% keeps them from filling a phone screen edge to edge. The
	 * intrinsic 440x440 in the markup reserves the box either way, so nothing
	 * jumps when the file arrives.
	 */
	inline-size: min(240px, 56%);
	max-inline-size: 240px;
	/*
	 * `margin-inline: auto` AND NOT the `text-align: center` the block already
	 * inherits. base.css sets `img { display: block }` theme-wide — which is
	 * right, it kills the descender gap under every image on the site — and a
	 * block-level image is not text, so text-align does nothing to it. Without
	 * this the illustration sits hard against the inline-start edge of a
	 * perfectly centred column, which is exactly how it shipped the first time.
	 */
	margin-inline: auto;
}

/*
 * The eyebrow — '404' on the error page, nothing anywhere else. Small, spaced
 * and in the accent, so it labels the state instead of being it. The old design
 * drew this number at `clamp(4rem, 18vw, 9rem)` in light grey, which made the
 * error code the single largest element on the page; the illustration carries
 * that weight now and the number can go back to being a reference the visitor
 * quotes in an email.
 */
.bedi-empty__eyebrow {
	color: var(--bedi-accent);
	font-family: var(--bedi-font-display);
	font-size: var(--bedi-text-sm);
	font-weight: var(--bedi-weight-bold);
	letter-spacing: 0.18em;
	margin: 0 0 var(--bedi-space-3xs);
	text-transform: uppercase;
}

.bedi-empty__title {
	font-size: var(--bedi-text-2xl);
	line-height: var(--bedi-leading-tight, 1.2);
	margin: 0;
	text-wrap: balance;
}

.bedi-empty__text {
	color: var(--bedi-ink-muted);
	margin-block: var(--bedi-space-2xs) 0;
	/*
	 * The measure is capped INSIDE the already-capped column. A centred
	 * paragraph that fills its container to the last pixel has a ragged right
	 * edge on both sides and reads as misaligned; pulling it in gives it a
	 * shape.
	 */
	margin-inline: auto;
	max-inline-size: 30rem;
	text-wrap: pretty;
}

.bedi-empty__search {
	margin-block-start: var(--bedi-space-md);
	margin-inline: auto;
	max-inline-size: 26rem;
	/*
	 * The form's own label and button are laid out start-aligned by layout.css;
	 * inheriting `text-align: center` from the block above would centre the
	 * placeholder inside the field.
	 */
	text-align: start;
}

.bedi-empty__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--bedi-space-2xs);
	justify-content: center;
	margin-block-start: var(--bedi-space-md);
}

/*
 * TWO WEIGHTS OF BUTTON, AND BOTH START FROM .bedi-button.
 *
 * layout.css's .bedi-button is a FILLED NAVY button with no border at all.
 * That is the right primary on a content page and the wrong one here: these
 * states put two actions side by side, and two identical filled buttons give a
 * lost visitor no steer about which one to press.
 *
 * So the primary becomes the accent blue — the same blue as the hero's CTA, so
 * "the blue one is the way forward" is consistent across the shop — and the
 * secondary becomes a ghost. Both carry a 1px border, including the primary,
 * where it is the SAME colour as the fill: a filled button with no border and a
 * ghost with one differ by two pixels in height, and side by side that reads as
 * a mistake.
 */
.bedi-empty__action {
	background-color: transparent;
	border: var(--bedi-border-width) solid var(--bedi-rule);
	color: var(--bedi-ink);
}

.bedi-empty__action:hover,
.bedi-empty__action:focus-visible {
	background-color: transparent;
	border-color: var(--bedi-accent);
	color: var(--bedi-accent);
}

.bedi-empty__action--primary {
	background-color: var(--bedi-accent);
	border-color: var(--bedi-accent);
	color: var(--bedi-on-accent);
}

.bedi-empty__action--primary:hover,
.bedi-empty__action--primary:focus-visible {
	background-color: var(--bedi-accent-strong);
	border-color: var(--bedi-accent-strong);
	color: var(--bedi-on-accent);
}

/*
 * The staggered entrance. Each part declares the same animation and its own
 * delay; `both` holds the from-state before it starts, which is what keeps the
 * title from flashing at full opacity for two frames before its turn.
 */
.bedi-empty__art,
.bedi-empty__eyebrow,
.bedi-empty__title,
.bedi-empty__text,
.bedi-empty__search,
.bedi-empty__actions {
	animation: bedi-empty-in 520ms var(--bedi-ease-out) both;
}

.bedi-empty__art {
	/* The picture leads and gets its own, slightly larger, movement. */
	animation-name: bedi-empty-art-in;
	animation-duration: 620ms;
}

.bedi-empty__eyebrow {
	animation-delay: 80ms;
}

.bedi-empty__title {
	animation-delay: 140ms;
}

.bedi-empty__text {
	animation-delay: 200ms;
}

.bedi-empty__search {
	animation-delay: 260ms;
}

.bedi-empty__actions {
	animation-delay: 320ms;
}

@keyframes bedi-empty-in {
	from {
		opacity: 0;
		transform: translateY(10px);
	}

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

/*
 * The illustration drifts, forever, and it is the only looping animation in
 * this theme.
 *
 * It is allowed because it is four pixels over six seconds on a decorative
 * drawing — well under any reasonable reading of "moving content" — and because
 * a dead end is the one page where a completely static screen reads as a site
 * that has stopped working. It is `ease-in-out` and `alternate` rather than a
 * loop with a jump, so there is no frame where it snaps back. Section 6 stops
 * it dead under prefers-reduced-motion.
 */
.bedi-empty__art img {
	animation: bedi-empty-float 6s var(--bedi-ease-in) 620ms infinite alternate;
}

@keyframes bedi-empty-float {
	from {
		transform: translateY(0);
	}

	to {
		transform: translateY(-4px);
	}
}

/* =========================================================================
 * 6. REDUCED MOTION AND FORCED COLOURS
 *
 * The switch is not "make it faster". Everything in sections 1–4 is decoration
 * over a state that is already communicated some other way — a class, an
 * aria-expanded, a colour — so under `prefers-reduced-motion: reduce` the
 * decoration is removed outright and the state is untouched.
 *
 * THE TWO THINGS THAT ARE NOT SWITCHED OFF, AND WHY.
 *
 *   The veil's opacity. It is the only thing telling a visitor that the page
 *   behind the rail has gone inert; removing the fade would make it a hard cut,
 *   which is more jarring than the fade, not less. It is shortened to 1ms
 *   instead, which is what this file does everywhere a state MUST remain
 *   visible.
 *
 *   The autoplay timer. It is not shortened, it is STOPPED — ui.js reads the
 *   same query and never starts it. A slider that rotates by itself is the
 *   textbook case the preference exists for, and no duration makes that
 *   acceptable.
 * ====================================================================== */

@media (prefers-reduced-motion: reduce) {
	.bedi-page-veil {
		transition-duration: 1ms !important;
	}

	.bedi-lang__menu,
	.bedi-lang__chevron,
	.bedi-lang__tick,
	.bedi-hero__arrow,
	.bedi-hero__dot,
	.bedi-hero__pause-glyph,
	.bedi-hero__play-glyph,
	.bedi-hero__cta,
	.bedi-cat-trigger,
	.bedi-cat-trigger__icon,
	.bedi-action .bedi-action__icon,
	.bedi-hero__rail-link,
	.bedi-hero__rail-arrow,
	.bedi-hero__sublist li,
	.bedi-hero__sublink,
	.bedi-cards__item,
	.bedi-card,
	.bedi-cards__item img,
	.bedi-card img,
	.woocommerce ul.products li.product,
	.woocommerce ul.products li.product img,
	.bedi-product-card,
	.bedi-product-card img,
	.bedi-utility-nav__list a,
	.bedi-panel__pages-list a {
		transition-duration: 1ms !important;
		transition-delay: 0ms !important;
	}

	/*
	 * Transforms are reset rather than merely made instant. A 1ms transition to
	 * translateY(-4px) still moves the element; the point of the preference is
	 * that it should not move at all.
	 */
	.bedi-hero__cta:hover,
	.bedi-hero__cta:active,
	.bedi-cat-trigger:hover,
	.bedi-cat-trigger:active,
	.bedi-cat-trigger:hover .bedi-cat-trigger__icon,
	.bedi-action:hover .bedi-action__icon,
	.bedi-action:focus-visible .bedi-action__icon,
	.bedi-action:active .bedi-action__icon,
	.bedi-hero__rail-item:hover > .bedi-hero__rail-link,
	.bedi-hero__rail-item:focus-within > .bedi-hero__rail-link,
	.bedi-hero__sublink:hover,
	.bedi-hero__sublink:focus-visible,
	.bedi-hero__arrow:hover,
	.bedi-hero__arrow:active,
	.bedi-hero__pause:active,
	.bedi-lang__trigger:active,
	.bedi-cards__item:hover,
	.bedi-card:hover,
	.bedi-cards__item:hover img,
	.bedi-card:hover img,
	.woocommerce ul.products li.product:hover,
	.woocommerce ul.products li.product:hover img,
	.bedi-product-card:hover,
	.bedi-product-card:hover img,
	.bedi-btn:not([disabled]):active,
	.bedi-cart-action:not([disabled]):active,
	.bedi-lang__link:active,
	.woocommerce a.button:active,
	.woocommerce button.button:active,
	.woocommerce .button:active {
		transform: none !important;
	}

	/*
	 * The fly-out's children are at opacity 0 at rest and are revealed by the
	 * staggered rule. With the stagger gone they must still be revealed, or a
	 * reduced-motion visitor gets an empty fly-out — which is the one failure
	 * mode a stagger built on opacity can have.
	 */
	.bedi-hero__sublist li {
		opacity: 1;
		transform: none;
	}

	.bedi-action--wishlist:hover .bedi-action__icon,
	.bedi-hero__dot.is-current .bedi-hero__dot-fill,
	.bedi-hero__slide .bedi-hero__body,
	.wc-block-cart__empty-cart__title.with-empty-cart-icon::before,
	.wc-block-checkout-empty-cart__title.with-empty-cart-icon::before,
	/*
	 * The empty state's five-step entrance AND the illustration's endless
	 * drift. The entrance uses `both`, so switching the animation off without
	 * resetting opacity would leave the whole state stuck at its from-state —
	 * invisible. The rule below restores it.
	 */
	.bedi-empty__art,
	.bedi-empty__art img,
	.bedi-empty__eyebrow,
	.bedi-empty__title,
	.bedi-empty__text,
	.bedi-empty__search,
	.bedi-empty__actions {
		animation: none !important;
	}

	.bedi-empty__art,
	.bedi-empty__art img,
	.bedi-empty__eyebrow,
	.bedi-empty__title,
	.bedi-empty__text,
	.bedi-empty__search,
	.bedi-empty__actions {
		opacity: 1;
		transform: none;
	}

	/*
	 * The arrows are revealed by the slider's :hover, which is a transform AND an
	 * opacity. With transforms off they must not stay invisible.
	 */
	.bedi-hero__arrow--prev,
	.bedi-hero__arrow--next {
		opacity: 1;
		transform: none;
	}

	.bedi-hero__track {
		scroll-behavior: auto !important;
	}
}

/*
 * FORCED COLOURS. The user's palette replaces this file's entirely, so what has
 * to survive is structure, not decoration.
 *
 * The veil is REMOVED rather than restyled. Its whole job is an optical wash,
 * forced-colours mode has no translucency to render it with, and a solid
 * Canvas-coloured sheet over the page would hide the page instead of softening
 * it.
 */
@media (forced-colors: active) {
	.bedi-page-veil {
		display: none;
	}

	.bedi-lang__menu {
		border: 1px solid CanvasText;
	}

	.bedi-lang__trigger,
	.bedi-hero__arrow,
	.bedi-hero__pause {
		border: 1px solid ButtonText;
	}

	/*
	 * A dot's state is a background colour and a width, and forced colours
	 * discards the first. A visible border restores the distinction: the current
	 * dot is the filled one.
	 */
	.bedi-hero__dot {
		border: 1px solid ButtonText;
	}

	.bedi-hero__dot.is-current {
		background-color: Highlight;
	}

	.bedi-hero__dot-fill {
		display: none;
	}
}
