/* =========================================================
   Prime Solutions — Motion
   Everything animated lives here, so the whole motion
   language can be read (or switched off) in one place.

   1. Tokens          2. Page transition   3. Scroll progress
   4. Reveal variants 5. Split text        6. Buttons & links
   7. Cards           8. Header & nav      9. Components
  10. Forms          11. Parallax         12. Back to top
  13. Reduced motion
   ========================================================= */

/* ---------- 1. TOKENS ---------- */
:root{
  --m-fast:.18s;
  --m-base:.32s;
  --m-slow:.6s;
  --m-slower:.9s;
  --ease-out:cubic-bezier(.22,1,.36,1);      /* settle — entrances */
  --ease-in-out:cubic-bezier(.65,0,.35,1);   /* symmetrical — moves */
  --ease-spring:cubic-bezier(.34,1.56,.64,1);/* overshoot — pops */
}

/* ---------- 2. PAGE TRANSITION ---------- */
/* First paint fades the document in; an internal link fades it out before
   the browser navigates, so pages cross-dissolve instead of flashing. */
@keyframes page-in{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
html.js body{animation:page-in .5s var(--ease-out) both}
html.is-leaving body{
  opacity:0;
  transform:translateY(-6px);
  transition:opacity .26s var(--ease-in-out),transform .26s var(--ease-in-out);
  animation:none;
}

/* ---------- 3. SCROLL PROGRESS ---------- */
.scroll-progress{
  position:fixed;top:0;left:0;height:3px;width:100%;z-index:200;
  transform:scaleX(var(--p,0));transform-origin:0 50%;
  background:var(--grad-brand);
  box-shadow:0 0 12px rgba(58,91,255,.6);
  pointer-events:none;
  will-change:transform;
}

/* ---------- 4. REVEAL VARIANTS ---------- */
/* The base .reveal (fade + rise) is in styles.css. These are directional
   alternatives selected per element with data-anim. */
.reveal[data-anim="left"]{transform:translateX(-34px)}
.reveal[data-anim="right"]{transform:translateX(34px)}
.reveal[data-anim="scale"]{transform:scale(.94)}
.reveal[data-anim="pop"]{transform:scale(.9);transition-timing-function:var(--ease-spring)}
.reveal[data-anim="blur"]{filter:blur(10px);transform:translateY(16px);transition:opacity var(--m-slower) var(--ease-out),transform var(--m-slower) var(--ease-out),filter var(--m-slower) var(--ease-out)}
.reveal[data-anim="fade"]{transform:none}
.reveal[data-anim="mask"]{clip-path:inset(0 0 100% 0);transform:none;opacity:1}
.reveal[data-anim="tilt"]{transform:perspective(900px) rotateX(9deg) translateY(28px);transform-origin:50% 100%}
.reveal.is-in{opacity:1;transform:none;filter:none;clip-path:inset(0 0 0 0)}

/* Any list/grid can stagger its children by adding data-stagger. */
[data-stagger] > .reveal{transition-delay:calc(var(--i,0) * var(--stagger-step,80ms))}

/* ---------- 5. SPLIT TEXT ---------- */
.split-text .word{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.08em;margin-bottom:-.08em}
.split-text .word > span{
  display:inline-block;
  transform:translateY(105%) rotate(4deg);
  opacity:0;
  transition:transform .8s var(--ease-out),opacity .6s var(--ease-out);
  transition-delay:calc(var(--w,0) * 55ms);
}
.split-text.is-in .word > span{transform:none;opacity:1}

/* Gradient headline keeps drifting, very slowly, so the hero never feels static. */
@keyframes grad-drift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
.gradient-text{background-size:220% 100%;animation:grad-drift 9s ease-in-out infinite}

/* ---------- 6. BUTTONS & LINKS ---------- */
.btn{overflow:hidden;isolation:isolate}
/* Light sweeps across the button on hover. */
.btn::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.28) 50%,transparent 62%);
  transform:translateX(-120%);
  transition:transform .7s var(--ease-in-out);
}
.btn:hover::before{transform:translateX(120%)}
.btn--ghost::before,.btn--soft::before{background:linear-gradient(105deg,transparent 38%,rgba(58,91,255,.16) 50%,transparent 62%)}
.btn:active{transform:translateY(1px) scale(.985)}

/* Click ripple — JS positions it at the pointer. */
.ripple{
  position:absolute;border-radius:50%;pointer-events:none;z-index:-1;
  background:rgba(255,255,255,.4);
  transform:translate(-50%,-50%) scale(0);
  animation:ripple .6s var(--ease-out) forwards;
}
.btn--ghost .ripple,.btn--soft .ripple{background:rgba(58,91,255,.22)}
@keyframes ripple{to{transform:translate(-50%,-50%) scale(1);opacity:0}}

.btn--primary{background-size:180% 180%;transition:transform .28s var(--ease),box-shadow .28s var(--ease),background-position .5s var(--ease-in-out)}
.btn--primary:hover{background-position:100% 0}

/* Inline links grow an underline from the left. */
.link-u{position:relative}
.link-u::after{
  content:"";position:absolute;left:0;bottom:-2px;height:1.5px;width:100%;
  background:currentColor;transform:scaleX(0);transform-origin:right;
  transition:transform .35s var(--ease-out);
}
.link-u:hover::after{transform:scaleX(1);transform-origin:left}

.link-arrow svg{transition:transform .3s var(--ease-spring)}
.link-arrow:hover svg{transform:translateX(2px)}

/* ---------- 7. CARDS ---------- */
/* A soft spotlight follows the pointer across the card surface. */
[data-spotlight]{position:relative;overflow:hidden}
[data-spotlight]::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),rgba(58,91,255,.13),transparent 62%);
  opacity:0;transition:opacity .4s var(--ease-out);
}
[data-spotlight]:hover::before{opacity:1}
[data-spotlight] > *{position:relative;z-index:1}
.card--feature[data-spotlight]::before{background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.18),transparent 62%)}

.card--hover:hover .icon-box{transform:scale(1.07) rotate(-4deg)}
.icon-box{transition:transform .45s var(--ease-spring),background-color .3s,color .3s}

/* Bento numbers slide in as the card lifts. */
.svc-card__num{transition:opacity .35s var(--ease-out),transform .35s var(--ease-out)}
.card--hover:hover .svc-card__num{opacity:1;transform:translateY(-2px)}
.svc-card .tags span{transition:background-color .25s,color .25s,border-color .25s,transform .25s var(--ease-out)}
.card--hover:hover .tags span{transform:translateY(-2px)}

/* Work cards: the artwork drifts, the metrics brighten. */
.work-card__visual::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,transparent 55%,rgba(10,12,16,.22));
  opacity:0;transition:opacity .45s var(--ease-out);
}
.work-card:hover .work-card__visual::after{opacity:1}
.metric b{transition:transform .35s var(--ease-spring)}
.work-card:hover .metric b{transform:translateY(-2px) scale(1.04)}

/* Pricing: the featured plan breathes on hover. */
.price-card{transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out),border-color .3s}
.price-card:hover{transform:translateY(-6px);box-shadow:var(--sh-lg);border-color:var(--brand-400)}
.price-card--featured::before{animation:badge-bob 3.4s ease-in-out infinite}
@keyframes badge-bob{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(-3px)}}

/* Testimonials: stars settle in one at a time. */
.quote__stars svg{opacity:0;transform:scale(.4) rotate(-25deg);transition:opacity .4s var(--ease-out),transform .5s var(--ease-spring)}
.quote.is-in .quote__stars svg,.reveal.is-in .quote__stars svg{opacity:1;transform:none}
.quote__stars svg:nth-child(1){transition-delay:.10s}
.quote__stars svg:nth-child(2){transition-delay:.16s}
.quote__stars svg:nth-child(3){transition-delay:.22s}
.quote__stars svg:nth-child(4){transition-delay:.28s}
.quote__stars svg:nth-child(5){transition-delay:.34s}
.quote .avatar{transition:transform .45s var(--ease-spring)}
.quote:hover .avatar{transform:scale(1.08) rotate(-5deg)}

/* Team */
.member__photo{transition:transform .5s var(--ease-out),box-shadow .5s var(--ease-out)}
.member:hover .member__photo{transform:translateY(-6px) scale(1.02);box-shadow:var(--sh-lg)}

/* Cards lean very slightly toward the pointer. JS supplies the angles.
   The transform only exists while .is-tilting is on, so the scroll-reveal
   entrance and the plain :hover lift above are left untouched otherwise.
   It sits last in this section so it outranks the hover rules on a tie. */
[data-tilt]{transform-style:preserve-3d}
[data-tilt].is-tilting{
  transform:perspective(1000px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) translateY(var(--ty,0px));
  transition:transform .14s linear,box-shadow .45s var(--ease-out);
  box-shadow:var(--sh-lg);
}

/* ---------- 8. HEADER & NAV ---------- */
.header{transition:border-color .3s,box-shadow .3s,background-color .3s,height .3s}
.header .brand__mark{transition:transform .5s var(--ease-spring)}
.brand:hover .brand__mark{transform:rotate(-8deg) scale(1.06)}

.nav a{position:relative}
.nav a::after{
  content:"";position:absolute;left:15px;right:15px;bottom:4px;height:2px;border-radius:2px;
  background:var(--grad-brand);transform:scaleX(0);transform-origin:center;
  transition:transform .35s var(--ease-out);
}
.nav a:hover::after,.nav a[aria-current="page"]::after{transform:scaleX(1)}

.icon-btn svg{transition:transform .45s var(--ease-spring),opacity .25s}
.theme-toggle:hover svg{transform:rotate(38deg)}
.theme-toggle:active svg{transform:rotate(180deg) scale(.85)}

/* Mobile menu links drop in one after another once the sheet opens. */
.mobile-nav .m-link,.mobile-nav .btn{opacity:0;transform:translateY(14px);transition:opacity .4s var(--ease-out),transform .45s var(--ease-out)}
.mobile-nav.is-open .m-link,.mobile-nav.is-open .btn{opacity:1;transform:none}
.mobile-nav.is-open .m-link:nth-child(1){transition-delay:.06s}
.mobile-nav.is-open .m-link:nth-child(2){transition-delay:.12s}
.mobile-nav.is-open .m-link:nth-child(3){transition-delay:.18s}
.mobile-nav.is-open .m-link:nth-child(4){transition-delay:.24s}
.mobile-nav.is-open .m-link:nth-child(5){transition-delay:.30s}
.mobile-nav.is-open .btn{transition-delay:.36s}
.m-link svg{transition:transform .3s var(--ease-out)}
.m-link:hover svg{transform:translateX(5px)}
.m-link:hover{color:var(--brand-500)}

/* ---------- 9. COMPONENTS ---------- */
/* Tabs: the incoming panel fades up as the pill slides. */
@keyframes panel-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
.tab-panel.is-entering{animation:panel-in .45s var(--ease-out) both}
.tab{transition:color .25s,transform .25s var(--ease-out)}
.tab:hover:not([aria-selected="true"]){transform:translateY(-1px)}

/* Accordion body slides as well as unfurls. */
.acc-panel__inner{opacity:0;transform:translateY(-8px);transition:opacity .35s var(--ease-out),transform .35s var(--ease-out)}
.acc-btn[aria-expanded="true"] + .acc-panel .acc-panel__inner{opacity:1;transform:none;transition-delay:.08s}
.acc-btn .acc-icon{transition:transform .4s var(--ease-spring),background-color .3s,color .3s,border-color .3s}
.acc-btn:hover .acc-icon{transform:scale(1.1)}
.acc-btn[aria-expanded="true"]:hover .acc-icon{transform:rotate(180deg) scale(1.1)}

/* Process steps: the dotted rail draws itself in. */
.steps::before{transform:scaleX(0);transform-origin:left;transition:transform 1.2s var(--ease-in-out)}
.steps.is-in::before{transform:scaleX(1)}
.step__dot{transition:transform .4s var(--ease-spring),background .35s,color .35s,border-color .35s,box-shadow .35s}

/* Timeline: the spine grows downward as the section arrives. */
.timeline::before{transform:scaleY(0);transform-origin:top;transition:transform 1.1s var(--ease-in-out)}
.timeline.is-in::before,.reveal.is-in .timeline::before{transform:scaleY(1)}
.timeline li::before{transform:scale(0);transition:transform .5s var(--ease-spring)}
.timeline.is-in li::before,.reveal.is-in .timeline li::before{transform:scale(1)}
.timeline.is-in li:nth-child(1)::before{transition-delay:.25s}
.timeline.is-in li:nth-child(2)::before{transition-delay:.45s}
.timeline.is-in li:nth-child(3)::before{transition-delay:.65s}
.timeline.is-in li:nth-child(4)::before{transition-delay:.85s}
.timeline.is-in li:nth-child(5)::before{transition-delay:1.05s}

/* Hero chart bars only grow once they are actually on screen. */
.chart .bar{animation-play-state:paused}
.chart.is-in .bar{animation-play-state:running}
.chart .bar{transition:filter .3s}
.chart:hover .bar.is-live{filter:brightness(1.12)}

/* KPI tiles in the hero panel lift in sequence. */
.kpi{transition:transform .4s var(--ease-out),box-shadow .4s var(--ease-out),border-color .3s}
.panel:hover .kpi{border-color:var(--line)}
.kpi:hover{transform:translateY(-3px);box-shadow:var(--sh-sm)}

/* Trust strip logos */
.logo-item{transition:opacity .25s,color .25s,transform .35s var(--ease-spring)}
.logo-item:hover{transform:translateY(-3px) scale(1.04)}

/* Chips and badges */
.chip{transition:transform .25s var(--ease-spring),background-color .25s,border-color .25s,color .25s}
.chip:hover{transform:translateY(-2px);border-color:var(--brand-400);color:var(--text)}
.badge .dot{animation:pulse-dot 2.4s ease-in-out infinite}
@keyframes pulse-dot{
  0%,100%{box-shadow:0 0 0 3px rgba(0,212,160,.2)}
  50%{box-shadow:0 0 0 6px rgba(0,212,160,.05)}
}

/* Footer */
.footer ul a{transition:color .2s,transform .25s var(--ease-out)}
.footer ul a:hover{transform:translateX(4px)}
.socials a{transition:background .3s,color .3s,border-color .3s,transform .35s var(--ease-spring)}
.socials a:hover{transform:translateY(-3px) scale(1.06)}

/* Stats band numbers get a subtle shimmer as they count. */
.stats-band .stat{transition:transform .4s var(--ease-out)}
.stats-band .stat:hover{transform:translateX(4px)}

/* Service rows */
.svc-row{transition:background-color .35s var(--ease-out)}
.svc-row:hover{background:var(--surface)}
.svc-row__idx{transition:transform .35s var(--ease-spring)}
.svc-row:hover .svc-row__idx{transform:translateX(3px)}

/* ---------- 10. FORMS ---------- */
.input,.textarea,.select{transition:border-color .22s,box-shadow .22s,background-color .22s,transform .22s var(--ease-out)}
.field:focus-within label{color:var(--brand-500)}
.field label{transition:color .22s}
.input:focus,.textarea:focus,.select:focus{transform:translateY(-1px)}

@keyframes shake{
  0%,100%{transform:translateX(0)}
  20%{transform:translateX(-6px)}
  40%{transform:translateX(5px)}
  60%{transform:translateX(-3px)}
  80%{transform:translateX(2px)}
}
.field.has-error .input,.field.has-error .textarea,.field.has-error .select{animation:shake .4s var(--ease-in-out)}
.field-error{animation:err-in .3s var(--ease-out) both}
@keyframes err-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}

.choice span{transition:background-color .2s,border-color .2s,color .2s,transform .25s var(--ease-spring)}
.choice span:hover{transform:translateY(-2px)}
.choice input:checked+span{transform:translateY(-2px)}

/* Success panel: the tick draws itself, then the copy arrives. */
.form-success.is-on{animation:panel-in .5s var(--ease-out) both}
.form-success.is-on .icon-box{animation:pop-in .55s var(--ease-spring) both}
@keyframes pop-in{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
.form-success.is-on .icon-box path{
  stroke-dasharray:26;stroke-dashoffset:26;
  animation:draw-check .5s var(--ease-out) .3s forwards;
}
@keyframes draw-check{to{stroke-dashoffset:0}}

/* Submit button spinner while a request is in flight. */
.btn.is-busy{pointer-events:none;opacity:.8}
.btn.is-busy::after{
  content:"";width:15px;height:15px;border-radius:50%;
  border:2px solid rgba(255,255,255,.35);border-top-color:#fff;
  animation:spin .7s linear infinite;
}
.btn--ghost.is-busy::after,.btn--soft.is-busy::after{border-color:var(--line);border-top-color:var(--brand-500)}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- 11. PARALLAX ---------- */
[data-parallax]{will-change:transform}

/* ---------- 12. BACK TO TOP ---------- */
.to-top{
  position:fixed;right:clamp(16px,3vw,28px);bottom:clamp(16px,3vw,28px);z-index:90;
  width:46px;height:46px;border-radius:50%;display:grid;place-items:center;
  background:var(--grad-brand);color:#fff;box-shadow:var(--sh-brand);
  opacity:0;transform:translateY(16px) scale(.8);pointer-events:none;
  transition:opacity .35s var(--ease-out),transform .45s var(--ease-spring),box-shadow .3s;
}
.to-top.is-on{opacity:1;transform:none;pointer-events:auto}
.to-top:hover{box-shadow:0 22px 46px -16px rgba(58,91,255,.7);transform:translateY(-3px)}
.to-top svg{width:19px;height:19px}

/* ---------- 13. REDUCED MOTION ---------- */
/* Everything above degrades to an instant state change. Nothing here is
   load-bearing for comprehension, so removing it costs nothing. */
@media (prefers-reduced-motion:reduce){
  html.js body,.form-success.is-on,.form-success.is-on .icon-box,.tab-panel.is-entering{animation:none!important}
  html.is-leaving body{opacity:1;transform:none}
  .split-text .word > span{transform:none;opacity:1}
  .gradient-text{animation:none}
  .badge .dot,.price-card--featured::before{animation:none}
  .scroll-progress{display:none}
  .reveal[data-anim]{transform:none!important;filter:none!important;clip-path:none!important}
  .steps::before{transform:scaleX(1)}
  .timeline::before{transform:scaleY(1)}
  .timeline li::before{transform:scale(1)}
  .quote__stars svg{opacity:1;transform:none}
  .acc-panel__inner{opacity:1;transform:none}
  .chart .bar{animation:none;transform:none}
  .btn::before{display:none}
  .to-top{transition:opacity .01ms}
  [data-tilt].is-tilting{transform:none!important;transition:none}
}
