/* =====================================================================
   MOTION  (loads last; driven by assets/js/fx.js, theme.js and elementor-bridge.js)
   Classes on <html>
     .fx-pre     set in <head> when the visitor allows motion and this isn't the Elementor editor.
                 Fade-up blocks start hidden and name lists start on one line from the first paint (no flash, no jump).
     .fx-ready   fx.js ran. If it never runs, the safety net below shows everything after 3.5 s.
     .fx-on      motion is running
     .fx-paused  the visitor pressed "Pause animations" in the footer: looping motion holds still
   Reduced motion: nothing moves and nothing is hidden. The orbit stands still, rotating words show as a list,
   name lists wrap. The full list of animations and where each one runs is in the README.
   ===================================================================== */

/* ---------- Fade-up on scroll ---------- */
.fx-pre .reveal{opacity:0;transform:translateY(28px)}
.fx-on .reveal{transition:opacity .8s var(--ease),transform .8s var(--ease)}
.fx-pre .reveal.is-in,.fx-ready:not(.fx-on) .reveal{opacity:1;transform:none}
.fx-pre:not(.fx-ready) .reveal{animation:fxShow 0s 3.5s forwards}
@keyframes fxShow{to{opacity:1;transform:none}}
/* The first block of every page is never hidden: it's what a visitor sees first, and the moment Google times as the page
   loading (Largest Contentful Paint). Fading it in after the scripts run cost 3-5 seconds on a mid-range phone. */
.fx-pre main>.elementor>.e-con:first-child .reveal,.fx-pre main>.elementor>.elementor-section:first-child .reveal,
.fx-pre main>:not(.elementor):first-child .reveal{opacity:1;transform:none;animation:none;transition:none}

/* ---------- 3D card tilt, cursor glow, magnetic buttons (mouse only; fx.js) ---------- */
.fx-on [data-tilt]{transform-style:preserve-3d}
.fx-on [data-magnetic]{transition:background-color .2s,color .2s,border-color .2s,transform .25s var(--ease)}

/* ---------- Reading-progress bar under the header (theme.js) ---------- */
.progress{position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--ink-bright);transform-origin:0 50%;transform:scaleX(0);pointer-events:none}

/* ---------- Rotating words: "Software for Logistics → Healthcare → …" ---------- */
.rot>span{color:var(--accent-text)}
html:not(.fx-pre) .rot>span:not(:last-child)::after,.fx-ready:not(.fx-on) .rot>span:not(:last-child)::after{content:", "}
.fx-pre .rot{display:inline-grid;overflow:hidden;vertical-align:bottom}
.fx-pre .rot>span{grid-area:1/1;white-space:nowrap;opacity:0;transform:translateY(110%)}
.fx-pre .rot>span.is-on{opacity:1;transform:none}
.fx-pre .rot>span.is-prev{transform:translateY(-110%)}
.fx-on .rot>span{transition:transform .6s var(--ease),opacity .6s}
.fx-ready:not(.fx-on) .rot{display:inline}
.fx-ready:not(.fx-on) .rot>span{opacity:1;transform:none}
/* Elementor writes the words as plain text; until fx.js turns them into the rotator they keep their place, unseen */
.fx-pre:not(.fx-ready) .st-rotate{display:inline-block;width:14ch;white-space:nowrap;overflow:hidden;vertical-align:bottom;visibility:hidden;animation:fxPlain 0s 3.5s forwards}
@keyframes fxPlain{to{visibility:visible;width:auto;white-space:normal}}

/* ---------- Moving name lists: the home ticker and the client list ---------- */
.fx-pre .marquee{overflow:hidden;
  -webkit-mask:linear-gradient(#000 0 0) top/100% 1px no-repeat,linear-gradient(#000 0 0) bottom/100% 1px no-repeat,linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);
  mask:linear-gradient(#000 0 0) top/100% 1px no-repeat,linear-gradient(#000 0 0) bottom/100% 1px no-repeat,linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
.fx-pre .marquee__track{flex-wrap:nowrap;width:max-content}
.fx-pre:not(.fx-ready) .marquee__track{animation:fxWrap 0s 3.5s forwards}
@keyframes fxWrap{to{flex-wrap:wrap;width:auto}}
.fx-ready:not(.fx-on) .marquee{overflow:visible;-webkit-mask:none;mask:none}
.fx-ready:not(.fx-on) .marquee__track{flex-wrap:wrap;width:auto}
/* the ticker starts after the process line, so names never slide under it */
.fx-pre main>section.st-railed>.marquee{margin-left:calc(max(0px,(100% - var(--container)) / 2) + var(--gutter) + var(--rail));margin-right:var(--gutter);padding-inline:0}
/* moving: the list is doubled (fx.js), every name gets its separator, the track slides half its width and repeats */
.marquee.is-moving .marquee__item::after{content:"";width:8px;height:8px;margin:0 clamp(12px,1.4vw,20px);border:2px solid var(--accent-line);border-radius:50%;background:none}
.marquee--plain.is-moving .marquee__item::after{width:4px;height:4px;margin:0 12px;border:0;background:var(--border-input)}
.fx-on .marquee.is-moving .marquee__track{animation:stMarquee 45s linear infinite}
.fx-on .marquee--rev.is-moving .marquee__track{animation-direction:reverse}
.fx-on .marquee.is-moving:hover .marquee__track,.fx-on .marquee.is-moving:focus-within .marquee__track,.fx-on .marquee.is-moving.fx-idle .marquee__track,.fx-on.fx-paused .marquee.is-moving .marquee__track{animation-play-state:paused}
@keyframes stMarquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}

/* ---------- 3D orbit: Why SAMTECH (Home) and the name card (About) ---------- */
.gyro{position:relative;width:100%;min-width:150px;max-width:340px;aspect-ratio:1/1;perspective:1000px;margin-inline:auto}
.st-gyro-sm .gyro{width:clamp(150px,20vw,230px)}
/* Elementor: the empty "Orbit animation" container holds the orbit's square from the first paint (the bridge fills it), so nothing jumps */
.e-con.st-gyro{aspect-ratio:1/1;width:100%;max-width:340px;margin-inline:auto}
.st-gyro-sm .e-con.st-gyro,.e-con.st-gyro-sm .e-con.st-gyro{width:clamp(150px,20vw,230px);max-width:none}
/* the core's glow sits behind the 3D rings, outside their 3D space (a shadow inside it gets cut into a square) */
.gyro::before{content:"";position:absolute;inset:24%;border-radius:50%;background:radial-gradient(circle,rgba(91,43,209,.5),rgba(91,43,209,0) 70%);pointer-events:none}
.gyro__in{position:relative;width:100%;height:100%;transform-style:preserve-3d}
.gyro__ring{position:absolute;transform-style:preserve-3d}
.gyro__ring::before{content:"";position:absolute;inset:0;border-radius:50%;border:1.5px solid var(--c)}
.gyro__ring i{position:absolute;top:-6px;left:50%;margin-left:-6px;width:12px;height:12px;border-radius:50%;background:var(--d);box-shadow:0 0 16px var(--d)}
.gyro__ring--a{inset:4%;--c:var(--accent-line);--d:var(--accent-line);transform:rotateX(68deg)}
.gyro__ring--b{inset:13%;--c:var(--border-strong);--d:var(--text);transform:rotateY(62deg)}
.gyro__ring--c{inset:22%;--c:var(--border-input);transform:rotateX(24deg) rotateY(-40deg)}
.gyro__core{position:absolute;inset:37%;border-radius:50%;background:radial-gradient(circle at 34% 28%,var(--ink-soft),var(--ink) 55%,var(--plum))}
.fx-on .gyro__ring--a{animation:stSpinA 16s linear infinite}
.fx-on .gyro__ring--b{animation:stSpinB 20s linear infinite}
.fx-on .gyro__ring--c{animation:stSpinC 26s linear infinite}
.fx-on .gyro__core{animation:stPulse 5s ease-in-out infinite}
/* it opens out once when it scrolls into view (theme.js adds .is-drawing), then spins; it tilts toward the mouse (fx.js) */
.fx-on .gyro__ring,.fx-on .gyro__core{transition:opacity .9s var(--ease),scale 1.2s var(--ease)}
.fx-on .gyro__ring--b{transition-delay:.12s}
.fx-on .gyro__ring--c{transition-delay:.24s}
.fx-on .gyro:not(.is-drawing) .gyro__ring{opacity:0;scale:.55}
.fx-on .gyro:not(.is-drawing) .gyro__core{opacity:0;scale:.3}
.fx-on .gyro::before{transition:opacity 1.2s var(--ease)}
.fx-on .gyro:not(.is-drawing)::before{opacity:0}
.fx-on .gyro.fx-idle .gyro__ring,.fx-on .gyro.fx-idle .gyro__core,.fx-on.fx-paused .gyro .gyro__ring,.fx-on.fx-paused .gyro .gyro__core{animation-play-state:paused}
@keyframes stSpinA{from{transform:rotateX(68deg) rotateZ(0)}to{transform:rotateX(68deg) rotateZ(360deg)}}
@keyframes stSpinB{from{transform:rotateY(62deg) rotateZ(0)}to{transform:rotateY(62deg) rotateZ(-360deg)}}
@keyframes stSpinC{from{transform:rotateX(24deg) rotateY(-40deg) rotateZ(0)}to{transform:rotateX(24deg) rotateY(-40deg) rotateZ(360deg)}}
@keyframes stPulse{0%,100%{transform:scale(1)}50%{transform:scale(1.07)}}

/* ---------- 1 · Page transitions (tablet and up; browsers without View Transitions simply load the page) ---------- */
@media (prefers-reduced-motion:no-preference) and (min-width:768px){
  @view-transition{navigation:auto}
  .site-header{view-transition-name:site-header}
  ::view-transition-old(root){animation:fxPageOut .26s cubic-bezier(.4,0,1,1) both}
  ::view-transition-new(root){animation:fxPageIn .42s cubic-bezier(.2,.7,.2,1) both}
}
@keyframes fxPageOut{to{opacity:0;transform:translateY(-14px)}}
@keyframes fxPageIn{from{opacity:0;transform:translateY(18px)}}

/* ---------- 2 · Colour wipe: white and violet sections grow from a rounded shape to full width (tablet and up) ---------- */
.fx-on .fx-wipe{isolation:isolate;background:transparent!important}
.fx-wipe__bg{position:absolute;inset:0;z-index:-1;background:var(--bg);border-radius:56px;transform:scale(.94,.97);transition:transform 1.1s var(--ease),border-radius 1.1s var(--ease);pointer-events:none}
.fx-in>.fx-wipe__bg{transform:none;border-radius:0}

/* ---------- 5 · Hero parallax: photo, caption chip and a violet glow at different depths (wide screens, mouse) ---------- */
.fx-on .fx-par{--mx:0;--my:0;transform-style:preserve-3d;transform:perspective(1200px) rotateY(calc(var(--mx) * 7deg)) rotateX(calc(var(--my) * -7deg))}
.fx-on .fx-par>.img-holder,.fx-on .fx-par>.st-img,.fx-on .fx-par>.elementor-widget-image{transform:translate3d(calc(var(--mx) * -12px),calc(var(--my) * -12px),0)}
.fx-on .fx-par .fx-chip{transform:translate3d(calc(var(--mx) * var(--d) * .6px),calc(var(--my) * var(--d) * .6px),calc(var(--d) * 1px))!important}
.fx-glow{position:absolute;inset:-14%;z-index:-1;border-radius:50%;pointer-events:none;background:radial-gradient(circle,rgba(143,107,255,.38),transparent 68%);filter:blur(48px);transform:translate3d(calc(var(--mx) * -70px),calc(var(--my) * -70px),-80px)}

/* ---------- 7 · Numbers strip: each number counts up in turn and its violet bar draws across (tablet and up) ---------- */
.fx-on .fx-seq>div::after{content:"";position:absolute;left:0;right:0;top:-1px;height:2px;background:var(--accent-line);transform:scaleX(0);transform-origin:0 50%;transition:transform .7s var(--ease);pointer-events:none}
.fx-on .fx-seq>div.fx-lit::after{transform:none}
.fx-on .fx-seq>div .num,.fx-on .fx-seq>div .st-stat-num{opacity:.2;transition:opacity .5s var(--ease)}
.fx-on .fx-seq>div.fx-lit .num,.fx-on .fx-seq>div.fx-lit .st-stat-num{opacity:1}

/* ---------- 10 · Case cards: the photo zooms and the result lifts (mouse) ---------- */
.card--media .img-holder,.card--media .st-img{overflow:hidden}
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .fx-on .card--media img{transition:transform .8s var(--ease)}
  .fx-on .card--media:hover img{transform:scale(1.05)}
  .fx-on .card--media .metric b,.fx-on .card--media .num{display:inline-block;transform-origin:0 100%;transition:transform .45s var(--ease),text-shadow .45s}
  .fx-on .card--media:hover .metric b,.fx-on .card--media:hover .num{transform:translateY(-4px) scale(1.14);text-shadow:0 10px 28px rgba(143,107,255,.55)}
}

/* ---------- 12 · Services deck: the cards stack as you scroll (tablet and up); on wide screens each one tilts back and dims ---------- */
.fx-on .svc-card.fx-deck{position:sticky;top:calc(96px + var(--i,0) * 12px);background:var(--bg);transform-origin:50% 0;box-shadow:0 -24px 48px -28px rgba(0,0,0,.9)}
.fx-on .svc-card.fx-deck.fx-tilt{will-change:transform}
.fx-deck__shade{position:absolute;inset:0;background:#000;opacity:0;pointer-events:none;z-index:3}
.fx-deck:not(.fx-tilt)>.fx-deck__shade{display:none}

/* ---------- 14 · Laptop frames on the Products page tilt as they scroll past (tablet and up) ---------- */
.fx-on .fx-device--3d{transform-style:preserve-3d;transition:transform .15s linear}

/* ---------- 18 · Form fields glow violet on focus (the success tick is in style.css) ---------- */
.input{transition:border-color .2s,box-shadow .25s}
.input:focus:not([aria-invalid="true"]){box-shadow:0 0 0 1px var(--focus),0 0 0 5px rgba(91,43,209,.16),0 10px 28px -14px rgba(91,43,209,.6)}

/* ---------- "Pause animations" (footer) ---------- */
.site-footer__legal{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--s2) var(--s5)}
.motion-toggle{display:inline-flex;align-items:center;min-height:44px;padding:0;border:0;background:none;color:var(--muted-2);font:500 14px/1.4 var(--font-body);text-decoration:underline;text-underline-offset:4px;cursor:pointer}
.motion-toggle:hover{color:#fff}
html:not(.fx-on) .motion-toggle,.motion-toggle[hidden]{display:none}
