/* Scroll motion. Hidden states apply only once theme.js has confirmed motion is welcome,
   so without JavaScript or with reduced motion every element simply shows. */
:root{--ease:cubic-bezier(.16,.84,.24,1)}

/* Opening: lines rise out of a mask, then the supporting copy follows. */
@keyframes rise{from{opacity:0;transform:translate3d(0,26px,0)}to{opacity:1;transform:none}}
@keyframes line-up{from{transform:translate3d(0,108%,0)}to{transform:none}}
@keyframes fade{from{opacity:0}to{opacity:1}}
.hero h1>.line{display:block;overflow:hidden;padding-bottom:.08em;margin-bottom:-.08em;color:inherit;white-space:normal}
.hero h1 .accent{color:var(--accent)}
.hero h1 .line-inner{display:block}
.has-motion .hero h1 .line-inner{animation:line-up 1.1s var(--ease) .15s both}
.has-motion .hero h1>.line+.line .line-inner{animation-delay:.28s}
.has-motion .hero-description{animation:rise .9s var(--ease) .5s both}
.has-motion .hero-actions{animation:rise .9s var(--ease) .62s both}
.has-motion .ticker{animation:fade 1.2s ease .8s both}

/* Everything else rises into place as it enters the window, in a short stagger. */
.has-motion :is(
  .work-heading,.work-feature,.work-list>li,.section-kicker,.section-heading,.service-card,.process-steps li,
  .pricing-heading,.pricing-stage,.pricing-bottom,.faq-grid>div:first-child,.faq-list details,
  .contact-intro,.enquiry-form,.footer-top,.footer-columns>*,
  .breadcrumbs,.content-heading>*,.reading-copy>section,.reading-copy>.content-cta,.related-links,
  .project-heading>*,.project-page main>.project-screen,.project-story,.project-detail,.project-boundary,.project-credits,.project-cta
):not(.is-in){opacity:0;transform:translate3d(0,34px,0)}
.has-motion [data-reveal]{transition:opacity .9s var(--ease) var(--reveal-delay,0s),transform 1s var(--ease) var(--reveal-delay,0s)}
.has-motion [data-reveal].reveal-done{transition:opacity .3s ease,transform .35s var(--ease),border-color .25s ease,background-color .25s ease,box-shadow .25s ease,color .25s ease}

/* Project screenshots settle in: the page eases down from a slight zoom, the preview slides up after it. */
.work-desktop img{transform-origin:50% 0}
.has-motion .work-feature .work-desktop img{transform:scale(1.07);transition:transform 1.6s var(--ease) .1s}
.has-motion .work-feature.is-in .work-desktop img{transform:none}
.has-motion .work-feature .work-booking{opacity:0;transform:translate3d(0,46px,0);transition:opacity .9s var(--ease) .45s,transform 1.2s var(--ease) .45s}
.has-motion .work-feature.is-in .work-booking{opacity:1;transform:none}
.has-motion .work-feature .work-annotation{opacity:0;transition:opacity .8s ease 1s}
.has-motion .work-feature.is-in .work-annotation{opacity:1}

/* Process steps draw their rule from left to right. */
.process-steps li{position:relative;border-top:0}
.process-steps li:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--accent);transform-origin:left}
.has-motion .process-steps li:before{transition:transform 1.2s var(--ease) calc(var(--reveal-delay,0s) + .15s)}
.has-motion .process-steps li:not(.is-in):before{transform:scaleX(0)}

/* Pricing stages: each dot pops in, its rule draws down to the next stage, and Free rises out of a mask. */
.has-motion .pricing-stage:before{transition:transform .7s var(--ease) calc(var(--reveal-delay,0s) + .2s)}
.has-motion .pricing-stage:not(.is-in):before{transform:scale(0)}
.has-motion .pricing-stage:after{transition:transform 1.3s var(--ease) calc(var(--reveal-delay,0s) + .3s)}
.has-motion .pricing-stage:not(.is-in):after{transform:scaleY(0)}
.has-motion .pricing-stage[aria-current] .stage-price{overflow:hidden}
.has-motion .pricing-stage[aria-current] .stage-price>span{display:block;transition:transform 1.1s var(--ease) calc(var(--reveal-delay,0s) + .15s)}
.has-motion .pricing-stage[aria-current]:not(.is-in) .stage-price>span{transform:translate3d(0,108%,0)}

/* A statement that lights up word by word as it scrolls past. */
.statement{padding-top:clamp(84px,14svh,170px);padding-bottom:clamp(84px,14svh,170px)}
.statement-text{max-width:1180px;font-size:clamp(30px,4.3vw,64px);font-weight:650;letter-spacing:-.035em;line-height:1.14;text-wrap:pretty}
.statement-text .w{transition:opacity .35s ease}
.has-motion .statement-text .w{opacity:.14}
.has-motion .statement-text .w.lit{opacity:1}
.statement-text .accent{color:var(--accent)}
.statement-text .accent-2{color:var(--accent-2)}

/* A continuous ticker of what Hyperise builds. */
.ticker{position:relative;z-index:1;overflow:hidden;padding:24px 0;border-block:1px solid var(--line);-webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent)}
.ticker-track{display:flex;width:max-content;animation:ticker 42s linear infinite}
.ticker.is-paused .ticker-track{animation-play-state:paused}
.ticker-track span{display:inline-flex;align-items:center;gap:30px;padding-right:30px;font-size:clamp(20px,2.3vw,32px);font-weight:600;letter-spacing:-.02em;white-space:nowrap;color:var(--muted)}
.ticker-track span:after{content:"✦";font-size:.55em;color:var(--accent)}
@keyframes ticker{to{transform:translate3d(-50%,0,0)}}

/* Small touches: arrows nudge, cards lift, the header steps aside while reading. */
.button svg{transition:transform .3s var(--ease)}
.button:hover svg{transform:translateX(4px)}
.service-card:hover{transform:translateY(-6px);border-color:var(--accent)}
.service-card{transition:transform .35s var(--ease),border-color .25s ease}
.work-row h3,.work-row-image img,.work-row-arrow{transition:transform .4s var(--ease),color .25s ease}
.work-row:hover h3{color:var(--accent);transform:translateX(6px)}
.work-row:hover .work-row-arrow{color:var(--accent);transform:translateX(4px)}
.work-row:hover .work-row-image img{transform:scale(1.05)}
.has-motion .work-more[open] .work-more-copy{animation:rise .5s var(--ease) both}
.header{transition:transform .45s var(--ease),background-color .25s ease}
.header.is-tucked{transform:translateY(-100%)}

/* The contact section lights up briefly for anyone sent to it, so the jump feels deliberate. */
.contact{position:relative;isolation:isolate}
.contact:before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:0;transition:opacity .9s ease;background:linear-gradient(180deg,color-mix(in srgb,var(--accent-2) 32%,transparent),color-mix(in srgb,var(--accent-2) 12%,transparent) 72%);box-shadow:inset 0 2px var(--accent-2)}
.contact.is-arriving:before{opacity:1;transition:opacity .12s ease .48s}

@media(prefers-reduced-motion:reduce){
  .ticker-track{animation:none}
  .header.is-tucked{transform:none}
  .service-card:hover,.work-row:hover :is(h3,.work-row-arrow),.work-row:hover .work-row-image img{transform:none}
}
