/* ==========================================================================
   Motion — tokens, the entrance gate, press and lift.

   One source per token: these custom properties here, and their JS copy in
   assets/js/motion/tokens.js (plugins/bonzivan-custom/tests/Unit/motion.test.mjs
   keeps them equal). Rules: ClaudeVault references/design/motion-premium-playbook.md.

   Markup contract (templates only mark, assets/js/motion/motion.js does the rest):
     data-motion-scope="scroll|page|reveal"  owner of the entrances inside it
     data-reveal="" | "down" | "fade"        rises 12px · drops 8px · opacity only
     data-act="count"                        inside a [data-reveal]: the number counts once per session
     data-count-key="…"                      "already counted" key (else its position on the page)
     .press / .lift                          press and hover feedback, CSS only
   ========================================================================== */

:root {
	--dur-press: 100ms;
	--dur-fast: 200ms;
	--dur-base: 260ms;
	--dur-enter: 360ms;
	--dur-long: 450ms;
	--dist-1: 8px;
	--dist-2: 12px;
	--dist-3: 16px;
	--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-out-soft: cubic-bezier(0.215, 0.61, 0.355, 1);
	--ease-in-out-soft: cubic-bezier(0.455, 0.03, 0.515, 0.955);
}

/* --------------------------------------------------------------------------
   The gate. The inline script in <body> (functions.php) adds html.mm-motion
   when this load has motion, and takes it away after 1.2 s if motion.js has
   not set html.mm-motion-ready. Only opacity: the text stays for screen
   readers and Ctrl+F. Only inside a scope: a loose [data-reveal] stays visible.
   -------------------------------------------------------------------------- */
html.mm-motion [data-motion-scope] [data-reveal]:not([data-motion-scope="reveal"]):not([data-revealed]),
html.mm-motion [data-reveal][data-motion-scope]:not([data-motion-scope="reveal"]):not([data-revealed]),
html.mm-motion:not(.mm-motion-ready) [data-reveal][data-motion-scope]:not([data-revealed]) {
	opacity: 0;
}

/* Printing halfway through an entrance prints the finished page. */
@media print {
	[data-reveal] {
		opacity: 1 !important;
		transform: none !important;
	}
}

/* --------------------------------------------------------------------------
   Press and lift. Press sinks in --dur-press and comes back in --dur-fast
   (the asymmetry is what makes it feel physical); lift only with a fine
   pointer, where hover is real. Both use the individual `scale` / `translate`
   properties, so they never fight a component's own `transform`.
   -------------------------------------------------------------------------- */
:is(
	.press, .lift,
	.bv-btn, .button, .dokan-btn,
	.bv-search-form__submit, .bv-search-trigger,
	.bv-filter-pill__trigger, .bv-filter-pill--toggle, .bv-filter-option-btn,
	.bv-com-chip, .bv-cf-tab, .bv-shop-view__btn
):not(:disabled, [aria-disabled="true"]) {
	transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, box-shadow, opacity, transform, scale, translate;
	transition-duration: var(--dur-fast);
	transition-timing-function: var(--ease-out-soft);
}

@media (prefers-reduced-motion: no-preference) {
	:is(
		.press,
		.bv-btn, .button, .dokan-btn,
		.bv-search-form__submit, .bv-search-trigger,
		.bv-filter-pill__trigger, .bv-filter-pill--toggle, .bv-filter-option-btn,
		.bv-com-chip, .bv-cf-tab, .bv-shop-view__btn
	):not(:disabled, [aria-disabled="true"]):active {
		scale: 0.97;
		transition-duration: var(--dur-press);
	}
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
	.lift:not(:disabled, [aria-disabled="true"]):hover {
		translate: 0 -2px;
	}
}

/* F0 pressed and lifted with `transform` (components.css .bv-btn:active,
   .bv-search-form__submit:active, .bv-card:hover; rutas.css .bv-ruta-card:hover),
   with fixed timings and no reduced-motion guard. Press and lift live here
   now; these keep the old rules from stacking on top (.97 × .97, −2 − 2 px). */
.bv-btn:active,
.bv-search-form__submit:active,
.lift:hover {
	transform: none;
}

/* --------------------------------------------------------------------------
   Overlays: dropdowns, popovers, sheets, modals and their scrim.
   One contract for every surface that appears: give it a .bv-appear class (the header's .bv-pop menus keep their name) and
   show / hide it with the `hidden` attribute. The entrance comes from
   @starting-style, the exit from transitioning `display` (allow-discrete),
   so no JS timing is needed; browsers without either just show and hide.
     .bv-appear          drops 8px from its trigger (menus and panels below it)
     .bv-appear--up      rises 8px (panels above their trigger)
     .bv-appear--scale   grows from 96% (centred dialogs)
     .bv-appear--sheet   slides up from the bottom edge (phone sheets)
     .bv-scrim        the dimmed backdrop behind a dialog or sheet
   Something that must stay in the layout while closed (an accordion body,
   a component that toggles a class instead of `hidden`) uses the same
   tokens on its own rules. Reduced motion: opacity only, --dur-fast.
   -------------------------------------------------------------------------- */
.bv-appear,
.bv-scrim {
	transition:
		opacity var(--dur-fast) var(--ease-out-soft),
		translate var(--dur-base) var(--ease-out-expo),
		scale var(--dur-base) var(--ease-out-expo),
		display var(--dur-base) allow-discrete,
		overlay var(--dur-base) allow-discrete;
}

.bv-appear[hidden],
.bv-scrim[hidden] {
	display: none;
	opacity: 0;
}

.bv-appear[hidden] { translate: 0 calc(var(--dist-1) * -1); }
.bv-appear--up[hidden] { translate: 0 var(--dist-1); }
.bv-appear--scale[hidden] { translate: none; scale: 0.96; }
.bv-appear--sheet[hidden] { translate: 0 100%; }

@starting-style {
	.bv-appear:not([hidden]),
	.bv-scrim:not([hidden]) { opacity: 0; }
	.bv-appear:not([hidden]) { translate: 0 calc(var(--dist-1) * -1); }
	.bv-appear--up:not([hidden]) { translate: 0 var(--dist-1); }
	.bv-appear--scale:not([hidden]) { translate: none; scale: 0.96; }
	.bv-appear--sheet:not([hidden]) { translate: 0 100%; }
}

/* Exits are quicker than entrances. */
.bv-appear[hidden],
.bv-scrim[hidden] {
	transition-duration: var(--dur-fast);
	transition-timing-function: var(--ease-in-out-soft);
}

.bv-scrim {
	position: fixed;
	inset: 0;
	background: rgb(18 24 32 / 0.45);
}

@media (prefers-reduced-motion: reduce) {
	.bv-appear,
	.bv-appear[hidden],
	.bv-scrim,
	.bv-scrim[hidden] {
		translate: none;
		scale: none;
		transition:
			opacity var(--dur-fast) linear,
			display var(--dur-fast) allow-discrete,
			overlay var(--dur-fast) allow-discrete;
	}
	@starting-style {
		.bv-appear:not([hidden]) { translate: none; scale: none; }
	}
}
