/* bbL-motion v1.4 (2026-10-22; v1 2026-10-15) — babaLucas Creative motion package, core: reveal, hover, marquee, cycle, float, pulse. Wipes use mask-size, not clip-path: a fully clipped element has zero IntersectionObserver area and never reveals. Hidden "before" states exist only under html.anim-ready (set by bbL-anim.js) and when the visitor allows motion. Docs: README.md */
:root{--anim-duration:.7s;--anim-ease:cubic-bezier(.16,1,.3,1);--anim-delay:0s;--anim-stagger:.1s;--anim-distance:24px;--hov-ease:cubic-bezier(.165,.84,.44,1);--hov-transform:translateY(-4px);--marquee-speed:30s;--marquee-gap:3rem;--cycle-slot-min:10rem;--cycle-height:4.5rem;--cycle-gap:1.25rem 2.5rem}
@media (prefers-reduced-motion:no-preference){
.anim-ready :is(.anim-fade,.anim-up,.anim-down,.anim-left,.anim-right,.anim-scale,.anim-blur):not(.is-inview),.anim-ready .anim-stagger:not(.is-inview)>*{opacity:0}
.anim-ready .anim-up:not(.is-inview),.anim-ready .anim-stagger:not(.is-inview)>*{transform:translateY(var(--anim-distance))}
.anim-ready .anim-down:not(.is-inview){transform:translateY(calc(-1*var(--anim-distance)))}
.anim-ready .anim-left:not(.is-inview){transform:translateX(calc(-1*var(--anim-distance)))}
.anim-ready .anim-right:not(.is-inview){transform:translateX(var(--anim-distance))}
.anim-ready .anim-scale:not(.is-inview){transform:scale(.94)}
.anim-ready .anim-blur:not(.is-inview){filter:blur(8px)}
.anim-ready .anim-clip-up:not(.is-inview){-webkit-mask-size:100% 0%;mask-size:100% 0%}
.anim-ready .anim-clip-left:not(.is-inview){-webkit-mask-size:0% 100%;mask-size:0% 100%}
.anim-fade,.anim-up,.anim-down,.anim-left,.anim-right,.anim-scale,.anim-blur,.anim-clip-up,.anim-clip-left,.anim-stagger>*{transition-property:opacity,transform,filter,-webkit-mask-size,mask-size;transition-duration:var(--anim-duration);transition-timing-function:var(--anim-ease);transition-delay:var(--anim-delay)}
.anim-clip-up,.anim-clip-left{-webkit-mask-image:linear-gradient(#000 0 0);mask-image:linear-gradient(#000 0 0);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%}
.anim-clip-up{-webkit-mask-position:0 100%;mask-position:0 100%}.anim-clip-left{-webkit-mask-position:0 0;mask-position:0 0}
.anim-stagger>*{--anim-delay:calc(var(--i,0)*var(--anim-stagger))}
.anim-delay-1{--anim-delay:.15s}.anim-delay-2{--anim-delay:.3s}.anim-delay-3{--anim-delay:.45s}.anim-delay-4{--anim-delay:.6s}.anim-slow{--anim-duration:1.2s}.anim-fast{--anim-duration:.4s}
.hov-lift,.hov-scale,.hov-shadow{transition:transform .3s var(--hov-ease),box-shadow .3s var(--hov-ease)}
.hov-lift:is(:hover,:focus-within){transform:var(--hov-transform)}
.hov-scale:is(:hover,:focus-within){transform:scale(1.03)}
.hov-shadow:is(:hover,:focus-within){box-shadow:0 18px 40px -16px #0005}
.hov-zoom{overflow:hidden}.hov-zoom img{transition:transform .6s var(--hov-ease)}.hov-zoom:is(:hover,:focus-within) img{transform:scale(1.06)}
.hov-reveal .hov-target,.hov-stagger>*{transition:opacity .4s var(--hov-ease),transform .4s var(--hov-ease)}
.hov-stagger>*{transition-delay:calc(var(--i,0)*.05s)}
.hov-reveal:not(:hover,:focus-within) .hov-target,.hov-stagger:not(:hover,:focus-within)>*{opacity:0;transform:translateY(8px)}
.hov-twin{position:relative;overflow:hidden;display:inline-block}.hov-twin>*{display:block;transition:transform .5s var(--hov-ease)}.hov-twin>:last-child{position:absolute;inset:0;transform:translateY(110%)}
.hov-twin:is(:hover,:focus-within)>:first-child{transform:translateY(-110%)}.hov-twin:is(:hover,:focus-within)>:last-child{transform:none}
.anim-marquee{display:flex;gap:var(--marquee-gap);overflow:hidden}
.anim-marquee>*{display:flex!important;flex:none;align-items:center;justify-content:space-around;gap:var(--marquee-gap);min-width:100%;animation:bbL-marquee var(--marquee-speed) linear infinite}
.anim-marquee-reverse>*{animation-direction:reverse}.anim-marquee:hover>*{animation-play-state:paused}
@keyframes bbL-marquee{to{transform:translateX(calc(-100% - var(--marquee-gap)))}}
.anim-float{animation:bbL-float 6s ease-in-out infinite}@keyframes bbL-float{50%{transform:translateY(-8px)}}
.anim-pulse{animation:bbL-pulse 2.4s ease-in-out infinite}@keyframes bbL-pulse{50%{opacity:.55}}
}
/* anim-cycle: still, wrapped row without JS or with reduced motion; bbL-anim.js adds .is-cycling and builds the slots. */
.anim-cycle{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:var(--cycle-gap)}
.anim-cycle.is-cycling{display:grid;grid-template-columns:repeat(var(--cycle-slots,4),minmax(0,var(--cycle-slot-max,1fr)));justify-content:center;gap:0}
.anim-cycle .cycle-slot{display:grid;place-items:center;overflow:hidden;min-height:var(--cycle-height)}
.anim-cycle .cycle-slot>*{grid-area:1/1}.anim-cycle .cycle-pool{display:none}
/* cycle-spread: item k of n sits at k/(n-1) of the free space, so the ends are flush and the gaps even. Uses the translate property, not transform, which the swap animates. */
.anim-cycle.cycle-spread .cycle-slot{justify-items:start}
.anim-cycle.cycle-spread .cycle-slot>*{--cycle-f:calc(var(--slot-i,0)/max(var(--cycle-slots,2) - 1,1));position:relative;left:calc(var(--cycle-f)*100%);translate:calc(var(--cycle-f)*-100%) 0}
.cycle-sr{position:absolute!important;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;padding:0}
.cycle-toggle{display:block;margin:1rem auto 0;padding:.3em .9em;font:inherit;font-size:.8em;line-height:1.4;color:inherit;background:none;border:1px solid currentColor;border-radius:999px;opacity:.7;cursor:pointer}
.cycle-toggle:is(:hover,:focus-visible){opacity:1}
