/* ==========================================================================
   Saraf · motion. Everything is visible by default. The hidden "before" states exist only
   under html.sf-anim, which the script adds after a clean init; a watchdog removes it.
   ========================================================================== */
.rv { transition: opacity .7s var(--ease-out), transform .8s var(--ease-out), filter .7s var(--ease-out); transition-delay: calc(var(--i, 0) * 70ms); }
html.sf-anim .rv:not(.is-in) { opacity: 0; transform: translateY(42px); filter: blur(6px); }
.split .w { display: inline-block; will-change: transform; transition: opacity .8s var(--ease-out), transform .9s var(--ease-out), filter .8s var(--ease-out); transition-delay: calc(var(--i, 0) * 55ms); }
html.sf-anim .split:not(.is-in) .w { opacity: 0; transform: translateY(.55em) rotate(3deg); filter: blur(8px); }

/* hero intro: the slab lands, the pieces arrive one by one, the headline rises word by word */
html.sf-anim .hero:not(.is-live) .hero__copy > :not(.hero__title), html.sf-anim .hero:not(.is-live) .hero__scroll { opacity: 0; transform: translateY(28px); }
.hero__copy > *, .hero__scroll { transition: opacity .9s var(--ease-out), transform 1s var(--ease-out); }
.hero.is-live .hero__copy > :nth-child(1) { transition-delay: .05s; }
.hero.is-live .hero__copy > :nth-child(3) { transition-delay: .35s; }
.hero.is-live .hero__copy > :nth-child(4) { transition-delay: .5s; }
.hero.is-live .hero__copy > :nth-child(5) { transition-delay: .65s; }
.hero.is-live .hero__scroll { transition-delay: 1.1s; }
.hero__title .w { transition: opacity .9s var(--ease-out), transform 1s var(--ease-out); transition-delay: calc(.15s + var(--i, 0) * 90ms); }
html.sf-anim .hero__title:not(.is-in) .w { opacity: 0; transform: translateY(.4em); }
html.sf-anim .hero:not(.is-live) .hero__slab { opacity: 0; transform: translateY(60px) scale(.9) rotate(-6deg); }
.hero__slab { transition: opacity 1.2s var(--ease-out), transform 1.4s var(--ease-out); }
html.sf-anim .hero:not(.is-live) .hero__float { opacity: 0; transform: translateY(40px) scale(.8); }
.hero__float { transition: opacity 1s var(--ease-out), transform 1.2s var(--ease-spring); transition-delay: calc(.5s + var(--i, 0) * 140ms); }
.hero.is-live .hero__slab { transition-delay: .1s; }

/* chapter hover micro-motion */
.slab { transition: transform .6s var(--ease-out), box-shadow .6s; }
.slab[data-tilt] { transform-style: preserve-3d; }

/* image mask reveal (.mk is added by JS to .slab / .tile / .ig__item / .step__frame / product frames; without JS nothing is clipped).
   The frame wipes open top to bottom while the picture inside settles from 1.12 to 1; --i staggers, and JS zeroes --i after
   the reveal so hover motion is never delayed. transform stays free for the tilt / hover rules. */
.mk, .wd-product .product-element-top.mk { transition: clip-path 1.1s var(--ease-out), transform .6s var(--ease-out), box-shadow .6s, border-color .4s; transition-delay: calc(var(--i, 0) * 90ms); }
html.sf-anim .mk:not(.is-in) { clip-path: inset(0 0 100% 0); }
.mk:not([data-parallax-soft]) > img, .mk .tile__img, .mk .step__img, .mk .product-image-link img { transition: transform 1.4s var(--ease-out), opacity .6s var(--ease-out); transition-delay: calc(var(--i, 0) * 90ms); }
.mk > video { transition: transform 1.4s var(--ease-out), opacity .8s; transition-delay: calc(var(--i, 0) * 90ms); }
html.sf-anim .mk:not(.is-in):not([data-parallax-soft]) > img, html.sf-anim .mk:not(.is-in) > video, html.sf-anim .mk:not(.is-in) .tile__img, html.sf-anim .mk:not(.is-in) .step__img, html.sf-anim .mk:not(.is-in) .product-image-link img { transform: scale(1.12); }

/* headline: the words rise (above); a thin gold line draws under the emphasised word once the heading has landed.
   Static (drawn) without JS; JS writes --n (word count) so the line waits for the last word. */
.h2 em { position: relative; }
.h2 em::after { content: ""; position: absolute; inset-inline: .04em; bottom: -.03em; height: 2px; border-radius: 2px; background: var(--accent-line, var(--sf-gold)); pointer-events: none; transform: scaleX(1); transform-origin: 100% 50%; transition: transform .9s var(--ease-out); transition-delay: calc(.3s + var(--n, 3) * 55ms); }
.h2--latin em::after { transform-origin: 0 50%; }
html.sf-anim .h2.split:not(.is-in) em::after { transform: scaleX(0); }

/* product cards: lift, slow zoom, a soft gold ring, and a paper pill fades in behind the price. Fine pointers only. */
@media (hover: hover) and (pointer: fine) {
	.wd-product .product-element-top, .wd-product .product-element-top.mk { transition: clip-path 1.1s var(--ease-out), transform .6s var(--ease-out), box-shadow .6s var(--ease-out), border-color .4s; }
	.wd-product:hover .product-element-top { transform: translateY(-6px); border-color: rgba(196,174,134,.9); box-shadow: var(--sf-shadow-sm), 0 0 0 3px rgba(196,174,134,.28); }
	.wd-product:hover .product-image-link img { transform: scale(1.06); }
	.wd-product .price { position: relative; isolation: isolate; display: inline-block; padding: .1em .55em; margin-inline-start: -.55em; }
	.wd-product .price::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: 999px; background: var(--sf-paper-2); opacity: 0; transform: scale(.92); transition: opacity .3s var(--ease-out), transform .4s var(--ease-out); }
	.wd-product:hover .price::before { opacity: 1; transform: scale(1); }
}

/* header: hides on the way down, slides back on the way up (JS toggles .sf-hdr-hidden on .whb-header once html.sf-hdr is set).
   WoodMart fixes .whb-main-header when stuck; its entrance keyframe is dropped so the slide is the only motion. */
html.sf-hdr .whb-header.whb-sticked .whb-main-header { animation: none; transition: transform .45s var(--ease-out); }
html.sf-hdr .whb-header.whb-sticked.sf-hdr-hidden .whb-main-header { transform: translateY(-105%); }
html.sf-hdr .whb-header.sf-hdr-hidden .wd-dropdown { visibility: hidden; }

/* touch and small screens: GPU diet (no blur filters, no decorative loops) */
@media (hover: none), (pointer: coarse), (max-width: 900px) {
	html.sf-anim .rv:not(.is-in) { filter: none; }
	html.sf-anim .split:not(.is-in) .w { filter: none; }
	.rv, .split .w { transition-property: opacity, transform; }
	.hero.is-live .hero__rings { animation: none; }
	/* mask reveal becomes a plain rise; no inner zoom, no clip on touch */
	.mk, .wd-product .product-element-top.mk { transition: opacity .7s var(--ease-out), transform .8s var(--ease-out), box-shadow .6s; }
	html.sf-anim .mk:not(.is-in) { clip-path: none; opacity: 0; transform: translateY(26px); }
	html.sf-anim .mk:not(.is-in):not([data-parallax-soft]) > img, html.sf-anim .mk:not(.is-in) > video, html.sf-anim .mk:not(.is-in) .tile__img, html.sf-anim .mk:not(.is-in) .step__img, html.sf-anim .mk:not(.is-in) .product-image-link img { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	html.sf-anim .rv:not(.is-in), html.sf-anim .split:not(.is-in) .w, html.sf-anim .hero:not(.is-live) .hero__copy > *, html.sf-anim .hero:not(.is-live) .hero__slab, html.sf-anim .hero:not(.is-live) .hero__float, html.sf-anim .hero__title:not(.is-in) .w { opacity: 1; transform: none; filter: none; }
	html.sf-anim .mk:not(.is-in) { clip-path: none; opacity: 1; transform: none; }
	html.sf-anim .mk:not(.is-in) > img, html.sf-anim .mk:not(.is-in) > video, html.sf-anim .mk:not(.is-in) .tile__img, html.sf-anim .mk:not(.is-in) .step__img, html.sf-anim .mk:not(.is-in) .product-image-link img { transform: none; }
	html.sf-anim .h2.split:not(.is-in) em::after { transform: scaleX(1); }
	.chapter__glow, .hero__glow { display: none; }
	html.sf-hdr .whb-header.whb-sticked.sf-hdr-hidden .whb-main-header { transform: none; }
}
