/* ==========================================================================
   Accessibility — the keyboard focus guarantee.

   WHAT THIS FIXES, AND WHY IT IS ONE FILE INSTEAD OF ELEVEN PATCHES
   ----------------------------------------------------------------
   An audit of the storefront found eleven `outline: none` declarations. One was a genuine bug (a
   base-state removal on the mobile submenu toggle, fixed at source in header.css). One was already
   correct — wishlist.css cancels `:focus` and restores a real ring on `:focus-visible`, which is
   exactly the right pattern.

   The other nine were the same design decision repeated: indicate focus by changing a 1px border
   colour. That looks deliberate and reads well with a mouse, and it FAILS for a keyboard user. WCAG
   2.4.11 (Focus Appearance, AA in WCAG 2.2) asks the indicator to have at least 3:1 contrast against
   the adjacent colours and to cover a minimum area; a 1px border shifting from #d8d3c9 to #141210 on
   an ivory field does neither reliably, and on the burgundy theme the accent-on-dark version is
   fainter still.

   Patching nine rules individually would have produced nine slightly different rings and no
   guarantee about the tenth one somebody adds next month. So the ring is declared ONCE, here, and
   this file is enqueued LAST.

   ⚠️ WHY `!important`, WHICH IS NORMALLY THE WRONG ANSWER
   ------------------------------------------------------
   Four independent sources inject CSS into this page after us: Astra, Elementor, WooCommerce and
   CartFlows. Several of them ship their own `outline: none`, at higher specificity than any selector
   a child theme can reasonably write, and they change on update. A focus indicator that the next
   plugin release can silently delete is not a fix — it is the same bug with a longer fuse, and it
   fails silently for the only users who depend on it.

   So `!important` is used, and only:
     - on ONE property (`outline` plus its offset),
     - in ONE state (`:focus-visible`, i.e. keyboard/AT only — mouse users see the designed look),
     - in ONE file that no other rule in this theme needs to override.

   That is the narrowest form of the guarantee. Anything less specific is a rule that works until it
   doesn't, with nobody watching.

   ⚠️ `:focus-visible`, NOT `:focus`
   ---------------------------------
   Using `:focus` would put a heavy ring on every mouse click, which is what drove the original
   `outline: none` declarations in the first place. `:focus-visible` is the browser's own answer to
   "did this focus arrive from a keyboard" and it is what makes the accessible version and the
   designed version able to coexist instead of trading places.
   ========================================================================== */

:root {
	/* One token, so the ring is the same everywhere and can be themed per store. The colour is the
	   brand agate rather than the browser blue; the DOUBLE ring (dark core + light halo) is what keeps
	   it visible on both the ivory storefront and the obsidian panels, where a single colour always
	   loses against one of them. */
	--yz-focus-ring: var(--yz-agate, #8c2f24);
	--yz-focus-halo: var(--yz-ivory, #f5f1e9);
	--yz-focus-width: 3px;
	--yz-focus-offset: 2px;
}

/* --------------------------------------------------------------------------
   The guarantee.

   Element selectors are listed explicitly rather than wrapped in `:where()`, because `:where()`
   contributes ZERO specificity — every existing `.yazan input:focus { outline: none }` would beat
   it, which would make this file look like a fix while changing nothing.
   -------------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
details:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible,
[role="link"]:focus-visible,
[role="tab"]:focus-visible,
[role="menuitem"]:focus-visible,
[contenteditable="true"]:focus-visible {
	outline: var(--yz-focus-width) solid var(--yz-focus-ring) !important;
	outline-offset: var(--yz-focus-offset) !important;

	/* The halo. Not `!important`: if a component has a considered reason to drop the outer glow it
	   may, and the ring itself still stands. */
	box-shadow: 0 0 0 calc(var(--yz-focus-width) + var(--yz-focus-offset)) var(--yz-focus-halo);
}

/* On dark surfaces the agate ring loses contrast against the background, so the two layers swap:
   the light halo becomes the ring and the dark colour becomes the backing. Same visual weight,
   inverted, rather than a second ring nobody tuned. */
.yz-verify-form :focus-visible,
.yz-signin__card :focus-visible,
[data-yz-surface="dark"] :focus-visible,
body.woocommerce-account .woocommerce-MyAccount-navigation :focus-visible,
html[data-yz-theme="burgundy"] .yz-footer :focus-visible {
	outline-color: var(--yz-focus-halo) !important;
	box-shadow: 0 0 0 calc(var(--yz-focus-width) + var(--yz-focus-offset)) rgba(20, 18, 16, 0.85);
}

/* --------------------------------------------------------------------------
   Composite controls.

   Where the focusable element is visually inside a wrapper that draws the border — the price range
   filter is the case here — ringing the bare <input> puts the indicator inside the box and clips it.
   The wrapper takes the ring instead, via :focus-within.
   -------------------------------------------------------------------------- */
.yazan .yz-price__field:focus-within {
	outline: var(--yz-focus-width) solid var(--yz-focus-ring);
	outline-offset: var(--yz-focus-offset);
}

/* …and the inner input then must NOT also ring, or the two overlap into a smear. */
.yazan .yz-price__field input:focus-visible {
	outline: none !important;
	box-shadow: none;
}

/* --------------------------------------------------------------------------
   Skip link — WCAG 2.4.1 (Bypass Blocks).

   ⚠️ NO LINK IS ADDED HERE, DELIBERATELY. Verified against the rendered page rather than assumed:
   Astra emits `<a class="skip-link screen-reader-text" href="#content">` as the first focusable
   element, `#content` exists, and Astra's own `.screen-reader-text:focus` rule reveals it. A second
   skip link would put TWO of them ahead of the navigation, which is worse than one — the user tabs
   twice to reach the same place and neither is obviously the real one.

   An earlier draft of this file did add one, on the assumption that the mega menu had pushed the
   main content out of reach. Checking the actual markup showed the assumption was wrong.

   What IS missing is emphasis: revealed at Astra's default styling the link is easy to miss against
   a photographic hero. This restyles the existing element on brand and does not create another.
   -------------------------------------------------------------------------- */
.yazan .skip-link:focus {
	inset-inline-start: 1rem !important;
	inset-block-start: 1rem !important;
	z-index: 100000;

	padding: 0.75rem 1.25rem;
	background: var(--yz-ink, #141210);
	color: var(--yz-ivory, #f5f1e9);
	border-radius: 0;
	clip: auto;
	clip-path: none;

	font-family: inherit;
	font-size: 0.875rem;
	letter-spacing: 0.04em;
	text-decoration: none;
}

/* --------------------------------------------------------------------------
   Motion.

   WCAG 2.3.3. The scroll reveals and the chevron rotations are the point of the storefront, so this
   does not delete them — it makes them instant. `0.01ms` rather than `0s` because a zero duration
   makes some browsers skip the `transitionend`/`animationend` event, and the reveal script waits for
   it: setting it to zero would leave elements permanently at `opacity: 0`, i.e. an accessibility
   preference that blanks the page.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}

	/* The reveal classes set `opacity: 0` and rely on a transition to bring them back. With motion
	   reduced they must start visible, or the preference costs the reader the content.

	   ⚠️ THIS SELECTOR LIST IS THE CONTRACT AND IT MUST MATCH motion.js's OBSERVER LIST.
	   It did not, for a long time, and the mismatch was invisible: this file guarded
	   `.yz-reveal-up` and `[data-yz-reveal]` — neither of which exists anywhere in the theme —
	   while motion.css guarded `[data-reveal]` and motion.js observed
	   `.yz-reveal, [data-reveal], [data-img-reveal]`. Three lists, three different answers to
	   "what is a reveal", and the only symptom of getting it wrong is content that stays at
	   `opacity: 0` forever for the users who asked for less motion. One list now, in three files
	   that all say so. */
	.yz-reveal,
	[data-reveal] {
		opacity: 1 !important;
		transform: none !important;
		translate: none !important;
	}

	[data-img-reveal] {
		clip-path: inset(0) !important;
	}

	[data-img-reveal] img {
		transform: none !important;
	}

	/* The global blanket above zeroes DURATIONS. It does not neutralise a RESTING transform, so
	   anything parked off-position by a start-state rule stays parked. woocommerce.css is the
	   largest motion surface in the theme (the sticky add-to-cart bar and the quick-add bar each
	   sit at `translateY(100%)` until shown) and shipped no reduced-motion rules of its own. */
	.yz-sticky-atc,
	.yz-card .ast-on-card-button {
		transition: none !important;
	}
}

/* --------------------------------------------------------------------------
   Screen-reader-only text, for labels the design does not show.
   -------------------------------------------------------------------------- */
.yz-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.yz-sr-only:focus-within,
.yz-sr-only.is-visible {
	position: static;
	width: auto;
	height: auto;
	margin: 0;
	overflow: visible;
	clip: auto;
	white-space: normal;
}

/* --------------------------------------------------------------------------
   The closed Power Coupons drawer must be out of the tab order (YZ-068).

   power-coupons prints `#power-coupons-drawer` in the footer of EVERY page with
   `aria-hidden="true"` and hides it with `opacity: 0` alone, so its close button stays
   focusable: a keyboard user tabs into an invisible dialog that screen readers were told
   does not exist (axe aria-hidden-focus, on every page). `visibility: hidden` removes the
   whole subtree from the tab order and the accessibility tree. The visibility transition
   is delayed by the plugin's own 0.3s fade on close and immediate on open, so the fade is
   unchanged and the plugin's focus-the-close-button (100ms after open) still lands.
   Same rule is inlined for the checkout in checkout.css (theme sheets do not load there).
   (The asset-hygiene `coupons` rule that would drop this CSS off-checkout is OFF by design:
   see inc/asset-hygiene.php — without its CSS the drawer unfolds into the page.)
   -------------------------------------------------------------------------- */
.power-coupons-drawer:not(.is-open) {
	visibility: hidden;
	transition: opacity 0.3s ease, visibility 0s linear 0.3s;
}
.power-coupons-drawer.is-open {
	visibility: visible;
}
