/* qm-motion.css — shared spatial motion layer (additive; see highestchina-cms/docs/MOTION.md).
   Nothing here hides content unless qm-motion.js has set html.qm-motion-ready AND tagged the element.
   Transform/opacity only. Group files (qm-motion-*.css) reuse the tokens below. */

:root {
  --qm-ease: cubic-bezier(.2, .7, .2, 1);
  --qm-ease-expo: cubic-bezier(.16, 1, .3, 1);
  --qm-ease-io: cubic-bezier(.65, 0, .35, 1);
  --qm-spring: var(--qm-ease);
  --qm-dur-xs: .2s;
  --qm-dur-s: .45s;
  --qm-dur-m: .8s;
  --qm-dur-l: 1.1s;
  --qm-dur-xl: 1.4s;
  --qm-dur-xxl: 1.4s;
  --qm-stagger: 80ms;
  --qm-persp: 1400px;
}

/* ---------- Elementor entrance animations: always visible, never slide/bounce ---------- */
.elementor-invisible { visibility: visible !important; opacity: 1 !important; }
.elementor-element.animated[class*="slideIn"],
.elementor-element.animated[class*="bounce"],
.elementor-element.animated[class*="fadeIn"],
.elementor-element.animated[class*="zoomIn"],
.elementor-element.animated[class*="rotateIn"],
.elementor-element.animated[class*="lightSpeed"],
.elementor-element.animated[class*="flip"],
.elementor-element .animated[class*="slideIn"],
.elementor-element .animated[class*="bounce"] { animation: none !important; }
/* Elementor hover "shrink" pushes away from the pointer — the wrong direction. */
.elementor-animation-shrink:hover,
.elementor-animation-shrink:focus,
.elementor-animation-shrink:active { transform: none !important; }
/* Elementor hover scale capped at 1.02 (class added by qm-motion.js when the widget asks for more). */
.qm-cap-scale > .elementor-widget-container:hover { --e-transform-scale: 1.02 !important; }

/* ---------- Scroll reveal (3D depth: cards/media push from behind the page toward the viewer) ---------- */
html.qm-motion-ready .qm-r {
  opacity: 0;
  transform: perspective(var(--qm-persp)) translate3d(0, var(--qm-y, 24px), var(--qm-z, 0)) rotateX(var(--qm-rx, 0deg));
  transform-origin: 50% 100%;
}
html.qm-motion-ready .qm-r.qm-in {
  opacity: 1;
  transform: perspective(var(--qm-persp)) translate3d(0, 0, 0) rotateX(0deg);
  transition:
    opacity var(--qm-dur-m) var(--qm-ease) var(--qm-d, 0ms),
    transform var(--qm-dur-xl) var(--qm-ease) var(--qm-d, 0ms);
}
html.qm-motion-ready .qm-r--card { --qm-y: 40px; --qm-z: -90px; --qm-rx: 6deg; }
html.qm-motion-ready .qm-r--media { --qm-y: 32px; --qm-z: -60px; --qm-rx: 4deg; }
html.qm-motion-ready .qm-r--text { --qm-y: 20px; }
/* Elements that already carry their own transform: opacity + independent translate only. */
html.qm-motion-ready .qm-r--soft { transform: none; translate: 0 var(--qm-y, 20px); }
html.qm-motion-ready .qm-r--soft.qm-in {
  transform: none; translate: 0 0;
  transition: opacity var(--qm-dur-m) var(--qm-ease) var(--qm-d, 0ms), translate var(--qm-dur-xl) var(--qm-ease) var(--qm-d, 0ms);
}
/* Instant (anchor jumps, focus, print): shown without animation. */
html.qm-motion-ready .qm-r.qm-now,
html.qm-motion-ready .qm-hl.qm-now,
html.qm-motion-ready .qm-line-i.qm-now { transition: none !important; }

/* ---------- Headline: line by line, opacity + rise (no blur) ---------- */
html.qm-motion-ready .qm-hl { opacity: 0; }
html.qm-motion-ready .qm-hl.qm-split { opacity: 1; }
html.qm-motion-ready .qm-hl.qm-in { opacity: 1; transition: opacity var(--qm-dur-m) var(--qm-ease) var(--qm-d, 0ms); }
.qm-line { display: block; }
.qm-line-i { display: inline-block; }
html.qm-motion-ready .qm-line-i { opacity: 0; transform: translate3d(0, .5em, 0); }
html.qm-motion-ready .qm-line-i.qm-in {
  opacity: 1; transform: none;
  transition: opacity var(--qm-dur-m) var(--qm-ease) var(--qm-d, 0ms), transform var(--qm-dur-l) var(--qm-ease) var(--qm-d, 0ms);
}

/* ---------- Media settles 1.06 → 1 on enter (removed afterwards; never permanent) ---------- */
html.qm-motion-ready .qm-zoom { scale: 1.06; }
html.qm-motion-ready .qm-zoom.qm-in { scale: 1; transition: scale var(--qm-dur-xl) var(--qm-ease) var(--qm-d, 0ms); }

/* ---------- Generic hero: media recedes, copy lifts away (vars scrubbed by JS) ---------- */
html.qm-motion-ready .qm-hero-media {
  scale: var(--qm-hs, 1);
  translate: 0 var(--qm-hy, 0px);
}
html.qm-motion-ready .qm-hero-copy {
  translate: 0 var(--qm-cy, 0px);
  opacity: var(--qm-co, 1);
}
.qm-hero-clip { overflow: clip; }

/* ---------- Parallax layers (translate scrubbed by JS while on screen) ---------- */
html.qm-motion-ready .qm-px { scale: 1.08; translate: 0 var(--qm-px, 0px); }

/* ---------- Boot: hide only the page's first h1 between head and core init; CSS failsafe reveals it at 2.4s ---------- */
@keyframes qm-failsafe { to { opacity: 1; } }
html.qm-motion-boot:not(.qm-motion-live) :is(#content, .site-main, main) h1 {
  opacity: 0;
  animation: qm-failsafe .01s linear 2.4s forwards;
}

/* ---------- Hover lift: precise pointers only; max scale 1.02 ---------- */
@media (hover: hover) and (pointer: fine) {
  html.qm-motion-ready .qm-lift {
    transition: translate var(--qm-dur-s) var(--qm-ease), scale var(--qm-dur-s) var(--qm-ease);
  }
  html.qm-motion-ready .qm-lift:hover,
  html.qm-motion-ready .qm-lift:focus-within { translate: 0 -4px; scale: 1.015; }
}

/* ---------- Counters ---------- */
.qm-count { font-variant-numeric: tabular-nums; }

/* ---------- Safety ---------- */
html.qm-motion-off .qm-r,
html.qm-motion-off .qm-hl,
html.qm-motion-off .qm-line-i,
html.qm-motion-off .qm-zoom,
html.qm-motion-off .qm-px,
html.qm-motion-off .qm-hero-media,
html.qm-motion-off .qm-hero-copy { opacity: 1 !important; transform: none !important; scale: none !important; translate: none !important; }

@media (max-width: 767px) {
  html.qm-motion-ready .qm-r { --qm-z: 0px !important; --qm-rx: 0deg !important; --qm-y: 14px !important; }
  html.qm-motion-ready .qm-r.qm-in { transition-duration: var(--qm-dur-m), var(--qm-dur-m); }
  html.qm-motion-ready .qm-line-i { transform: translate3d(0, .3em, 0); }
  html.qm-motion-ready .qm-zoom { scale: 1.03; }
  html.qm-motion-ready .qm-px { scale: 1; translate: none; }
}

@media (prefers-reduced-motion: reduce) {
  html.qm-motion-ready .qm-r,
  html.qm-motion-ready .qm-hl,
  html.qm-motion-ready .qm-line-i,
  html.qm-motion-ready .qm-zoom,
  html.qm-motion-ready .qm-hero-media,
  html.qm-motion-ready .qm-hero-copy,
  html.qm-motion-ready .qm-px,
  html.qm-motion-ready .qm-lift { opacity: 1 !important; transform: none !important; scale: none !important; translate: none !important; transition: none !important; }
  html.qm-motion-boot :is(#content, .site-main, main) h1 { opacity: 1 !important; animation: none !important; }
}

@media print {
  .qm-r, .qm-hl, .qm-line-i, .qm-zoom, .qm-px { opacity: 1 !important; transform: none !important; scale: none !important; translate: none !important; }
}

/* ---------- Above the fold is never faded in (LCP, 20261022) ---------- */
html.qm-motion-ready .qac-overview-hero img,
html.qm-motion-ready .qac-overview-hero h1,
html.qm-motion-ready .qac-overview-hero h2,
html.qm-motion-ready .qac-overview-hero > div:last-child,
html.qm-motion-ready.qmc-on .qmc-hero-box img,
html.qm-motion-ready[data-qma-item] .qma-hero .qma-in,
html.qm-motion-ready .qm-hero-media { opacity: 1 !important; animation: none !important; }

/* ---------- Empty controls: never show a blank button ---------- */
:is(button, a.elementor-button, .elementor-button-wrapper a, a[class*="btn"], a[class*="button"]):not([aria-label]):not([title]):not(:has(img, svg, i, video, canvas, [class*="icon"])):empty,
.elementor-button-wrapper:has(> a .elementor-button-text:empty):not(:has(svg, i, img)) { display: none !important; }

/* case-detail hero legibility: soft scrim behind title block (no layout change) */
#tpl-case .tpl-hero .tpl-hero-in::before{content:"";position:absolute;inset:-18% -12%;z-index:-1;pointer-events:none;
  background:radial-gradient(closest-side,rgba(0,0,0,.42),rgba(0,0,0,.22) 55%,rgba(0,0,0,0) 100%)}
#tpl-case .tpl-hero .tpl-h1,#tpl-case .tpl-hero .tpl-hero-in{text-shadow:0 1px 2px rgba(0,0,0,.35),0 2px 28px rgba(0,0,0,.4)}
