/* Intro: full-screen "Студия Пи". The П is the logo: its top-right pixel turns green, breaks off
   to its logo position, then opens as a window onto the site. Logo units: П is 48x48, pixel 12x12.
   Timeline: letters 0.2–2s, turns green 2s, trembling 2.6–3.5s, snap-off 3.5s, window 4.3–5.65s. */
html.px-intro-on{overflow:hidden}
.px-intro{position:fixed;inset:0;z-index:100;display:grid;place-items:center;overflow:hidden;background:#fff;color:#19221f;pointer-events:none;
 animation:px-intro-bg 0s 4.3s forwards,px-intro-bail .01s 6.3s forwards}
html.px-intro-on .px-intro{pointer-events:auto;cursor:pointer}
html.px-intro-off .px-intro{display:none}
/* A faint pixel grid breathes in behind the name. */
.px-intro::before{content:"";position:absolute;inset:-64px;opacity:0;
 background:linear-gradient(#19221f0d 1px,transparent 1px) 0 0/48px 48px,linear-gradient(90deg,#19221f0d 1px,transparent 1px) 0 0/48px 48px;
 -webkit-mask:radial-gradient(closest-side,#000 30%,transparent);mask:radial-gradient(closest-side,#000 30%,transparent);
 animation:px-intro-grid 3.6s ease .1s forwards}
.px-intro-lock{position:relative;z-index:1;margin:0;font-family:Rounded,Arial,sans-serif;font-size:min(18.5vw,70vh);line-height:.9;letter-spacing:-.05em;white-space:nowrap}
.px-intro-lock>span{display:block}
/* "ПИ" is drawn with the logo wordmark glyphs: 40 units tall, 9 units apart. */
.px-intro-lock>.px-intro-word{display:flex;align-items:flex-end;gap:.1575em}
.px-intro-word svg{display:block;width:calc(var(--w)/40*.7em);height:.7em;fill:currentColor}
.px-intro-small{font-size:clamp(13px,1.4vw,22px);letter-spacing:.18em;text-transform:uppercase;color:#8a8a8a;margin:0 0 min(3.2vw,12vh)}
.px-intro-lock i{display:inline-block;font-style:normal;opacity:0;transform:translateY(55%) scale(.92);filter:blur(12px);
 animation:px-intro-rise 1.1s cubic-bezier(.16,1,.3,1) calc(.2s + var(--i)*.07s) forwards,px-intro-away .8s cubic-bezier(.55,0,.75,.2) calc(4.3s + var(--i)*.03s) forwards}
/* The П is the logo mark: 48x48 with a stroke of 12; its 12x12 corner is the pixel. */
.px-intro-p{position:relative;display:block;width:.7em;height:.7em;animation:px-intro-strain .9s linear 2.6s,px-intro-jolt .45s ease-out 3.5s}
.px-intro-p u{position:absolute;background:#19221f}
.px-intro-p .l{left:0;top:0;width:25%;height:100%}
.px-intro-p .t{left:0;top:0;width:75%;height:25%}
.px-intro-p .r{left:75%;top:25%;width:25%;height:75%;animation:px-intro-leg .5s cubic-bezier(.34,1.56,.64,1) 3.5s forwards}
.px-intro-p .px-intro-dot{left:75%;top:0;width:25%;height:25%;z-index:1;
 animation:px-intro-green .6s ease 2s forwards,px-intro-tremble .9s linear 2.6s,px-intro-break .55s ease-out 3.5s forwards,px-intro-hide 0s 4.3s forwards}
/* Debris that flies off where the pixel breaks away. */
.px-intro-p>b{position:absolute;left:84%;top:9%;width:7%;height:7%;background:#19221f;opacity:0;
 animation:px-intro-bit .9s cubic-bezier(.1,.9,.3,1) 3.52s}
.px-intro-p>b:nth-of-type(odd){background:#c6f54e}
.px-intro-p>b:nth-of-type(1){--x:.34em;--y:-.3em;--r:140deg}
.px-intro-p>b:nth-of-type(2){--x:.22em;--y:-.46em;--r:-90deg;width:5%;height:5%}
.px-intro-p>b:nth-of-type(3){--x:.44em;--y:-.08em;--r:200deg}
.px-intro-p>b:nth-of-type(4){--x:.06em;--y:-.4em;--r:-160deg;width:5%;height:5%}
.px-intro-p>b:nth-of-type(5){--x:.38em;--y:.14em;--r:80deg;width:4%;height:4%}
.px-intro-p>b:nth-of-type(6){--x:-.08em;--y:-.26em;--r:120deg;width:4%;height:4%}
/* The window: JS places it over the broken-off pixel as the opening starts. */
.px-intro-win{position:absolute;left:0;top:0;width:24px;height:24px;background:#c6f54e;box-shadow:0 0 0 300vmax #fff;visibility:hidden;
 animation:px-intro-open 1.35s cubic-bezier(.76,0,.18,1) 4.3s forwards}
@keyframes px-intro-grid{0%{opacity:0;transform:scale(1.08)}40%{opacity:1}100%{opacity:.7;transform:none}}
@keyframes px-intro-rise{to{opacity:1;transform:none;filter:none}}
@keyframes px-intro-away{from{opacity:1;transform:none;filter:none}to{opacity:0;filter:blur(8px);
 transform:translate(calc((var(--i) - 6)*.07em),-.2em) rotate(calc((var(--i) - 6)*4deg)) scale(.9)}}
@keyframes px-intro-green{0%{background:#19221f;box-shadow:0 0 0 rgba(198,245,78,0)}45%{background:#c6f54e;transform:scale(1.12)}100%{background:#c6f54e;transform:none;box-shadow:0 0 .12em rgba(198,245,78,.45)}}
@keyframes px-intro-jolt{0%,100%{transform:none}20%{transform:translate(-.025em,.02em) rotate(-1.2deg)}45%{transform:translate(.018em,-.01em) rotate(.8deg)}70%{transform:translate(-.008em,0)}}
/* Trembling grows until the pixel snaps off. */
@keyframes px-intro-tremble{0%{transform:none;box-shadow:0 0 .12em rgba(198,245,78,.45)}
 8%{transform:translate(2%,-1%) rotate(1deg)}16%{transform:translate(-2%,1%) rotate(-1deg)}24%{transform:translate(3%,0) rotate(2deg)}
 32%{transform:translate(-3%,-2%) rotate(-2deg)}40%{transform:translate(4%,1%) rotate(3deg)}48%{transform:translate(-5%,-2%) rotate(-3deg)}
 56%{transform:translate(6%,-1%) rotate(4deg)}64%{transform:translate(-6%,-4%) rotate(-5deg)}72%{transform:translate(8%,-2%) rotate(6deg)}
 80%{transform:translate(-8%,-5%) rotate(-7deg)}88%{transform:translate(9%,-4%) rotate(8deg)}
 100%{transform:translate(-4%,-8%) rotate(-6deg) scale(1.06);box-shadow:0 0 .45em .06em rgba(198,245,78,.85)}}
/* The whole П shakes harder as the pixel pulls away. */
@keyframes px-intro-strain{0%,100%{transform:none}10%{transform:translate(.004em,0)}20%{transform:translate(-.005em,.002em) rotate(-.3deg)}
 30%{transform:translate(.007em,-.002em) rotate(.4deg)}40%{transform:translate(-.009em,.003em) rotate(-.5deg)}50%{transform:translate(.011em,-.003em) rotate(.6deg)}
 60%{transform:translate(-.013em,.004em) rotate(-.8deg)}70%{transform:translate(.016em,-.004em) rotate(.9deg)}80%{transform:translate(-.018em,.005em) rotate(-1.1deg)}
 90%{transform:translate(.02em,-.006em) rotate(1.2deg)}}
@keyframes px-intro-break{0%{background:#c6f54e;transform:translate(-4%,-8%) rotate(-6deg) scale(1.06);box-shadow:0 0 .45em .06em rgba(198,245,78,.85)}
 18%{background:#c6f54e;transform:translate(40%,-100%) rotate(-20deg) scale(1.18)}
 55%{background:#c6f54e;transform:translate(31%,-60%) rotate(5deg)}
 78%{background:#c6f54e;transform:translate(34.5%,-69%) rotate(-1.5deg)}
 100%{background:#c6f54e;transform:translate(33.33%,-66.67%);box-shadow:0 0 0 rgba(198,245,78,0)}}
@keyframes px-intro-bit{0%{opacity:1;transform:none}100%{opacity:0;transform:translate(var(--x),var(--y)) rotate(var(--r)) scale(.6)}}
@keyframes px-intro-leg{to{top:33.33%;height:66.67%}}
@keyframes px-intro-hide{to{visibility:hidden}}
@keyframes px-intro-open{0%{visibility:visible;transform:scale(1);background:#c6f54e}16%{transform:scale(.78);background:#c6f54e}40%{background:rgba(198,245,78,0)}
 100%{visibility:visible;transform:scale(var(--open,160));background:rgba(198,245,78,0)}}
@keyframes px-intro-bg{to{background:transparent}}
@keyframes px-intro-bail{to{visibility:hidden;pointer-events:none}}
.px-intro.is-skip{transition:opacity .3s;opacity:0}

/* The hero starts rising while the window opens. */
html.px-intro-on .px-hero.is-ready h1{animation-delay:4.55s}
html.px-intro-on .px-hero.is-ready p{animation-delay:4.65s}

/* Scroll reveals, only when JS is running. */
html.px-motion [data-reveal]{opacity:0;translate:0 48px;
 transition:opacity .8s ease calc(var(--d,0)*90ms),translate 1s cubic-bezier(.16,1,.3,1) calc(var(--d,0)*90ms),background-color .35s,color .35s}
html.px-motion [data-reveal].is-in{opacity:1;translate:none}
html.px-motion .px-words>span{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.08em;margin-bottom:-.08em}
html.px-motion .px-words>span>span{display:inline-block;translate:0 110%;transition:translate .9s cubic-bezier(.16,1,.3,1) calc(var(--w)*70ms)}
html.px-motion .px-words.is-in>span>span{translate:none}
/* Work cards: the frame opens smoothly and the screenshot settles from a slight zoom once it is decoded. */
html.px-motion .px-card[data-reveal] .px-frame{clip-path:inset(10% 8% 10% 8% round 28px);transition:clip-path 1.1s cubic-bezier(.16,1,.3,1) calc(var(--d,0)*120ms + .1s)}
html.px-motion .px-card[data-reveal].is-in .px-frame{clip-path:inset(0 round 28px)}
html.px-motion .px-card[data-reveal] img{scale:1.14;opacity:0;transition:transform .8s cubic-bezier(.2,.7,.2,1),scale 1.5s cubic-bezier(.16,1,.3,1) calc(var(--d,0)*120ms + .1s),opacity .7s ease calc(var(--d,0)*120ms + .15s)}
html.px-motion .px-card.is-poster[data-reveal] img{transition:transform 6s cubic-bezier(.22,.61,.36,1),scale 1.5s cubic-bezier(.16,1,.3,1) calc(var(--d,0)*120ms + .1s),opacity .7s ease calc(var(--d,0)*120ms + .15s)}
html.px-motion .px-card[data-reveal].is-in img{scale:1;opacity:1}
html.px-motion .px-card[data-reveal] p{opacity:0;translate:0 12px;transition:opacity .7s ease calc(var(--d,0)*120ms + .45s),translate .9s cubic-bezier(.16,1,.3,1) calc(var(--d,0)*120ms + .45s)}
html.px-motion .px-card[data-reveal].is-in p{opacity:1;translate:none}
/* A soft shimmer in the empty frame while the screenshot is still loading. */
html.px-motion .px-card[data-reveal]:not(.is-in) .px-frame::before{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,.06) 50%,transparent 70%) -100% 0/200% 100%;animation:px-shimmer 1.4s linear infinite}
@keyframes px-shimmer{to{background-position:100% 0}}

@media(prefers-reduced-motion:reduce){
.px-intro{display:none}
html.px-motion [data-reveal],html.px-motion .px-words>span>span{opacity:1;translate:none;transition:none}
html.px-motion .px-card[data-reveal] .px-frame{clip-path:none;transition:none}
html.px-motion .px-card[data-reveal] img,html.px-motion .px-card[data-reveal] p{scale:1;opacity:1;translate:none}
}
