/* Motion for f1v3group.com. Everything here is additive: with no JavaScript, or with
   reduced motion on, the page is complete and still. The <html> element gets .js when
   the script runs, .intro while the opening plays, and .seen once it is done. */

html{scroll-behavior:smooth}

/* ---- the hero band: the lockup draws itself ---- */
.band{border:0;padding:0;position:relative}
.lockup{display:block;width:100%;height:auto;color:var(--ink);overflow:visible}
.lockup .guides{color:var(--muted);opacity:0;transition:opacity .5s ease}
.lockup .guides text{font-family:var(--sans);fill:var(--muted);stroke:none;letter-spacing:.02em}
.lockup .frame .g-unit{fill:var(--tile);stroke:none}
.lockup .frame .g-band{stroke:var(--guide)}
.lockup .guides .g-base{stroke:var(--ember);fill:var(--ember)}
.lockup .guides path.g-base{fill:none}
.lockup .guides text.g-base{stroke:none;font-weight:400}
/* the band and the two unit tiles are always on; the measurements come on hover or tap */
.band:hover .lockup .guides,.band.show .lockup .guides{opacity:1}

.tile{transform-box:fill-box;transform-origin:center}
.glyph{transform-box:fill-box;transform-origin:center bottom}

html.js.intro .lockup .g-band{stroke-dasharray:1;stroke-dashoffset:1;animation:draw 1.1s cubic-bezier(.4,0,.2,1) forwards}
html.js.intro .lockup .g-unit{opacity:0;animation:fade .5s ease .9s forwards}
html.js.intro .tile{transform:scale(0);animation:land .55s cubic-bezier(.34,1.56,.64,1) forwards;animation-delay:calc(.35s + var(--i) * .09s)}
html.js.intro .tile.ember{animation:land .6s cubic-bezier(.34,1.56,.64,1) forwards,ignite .9s ease-out forwards;animation-delay:.95s,1.0s}
html.js.intro .glyph{opacity:0;transform:translateY(14px);filter:blur(6px);animation:rise .7s cubic-bezier(.2,.7,.2,1) forwards}
html.js.intro .glyph.g-f{animation-delay:1.15s}
html.js.intro .glyph.g-v{animation-delay:1.3s}
html.js.intro .glyph.g-1,html.js.intro .glyph.g-3{transform:scale(.4) translateY(10px);animation-name:pop;animation-timing-function:cubic-bezier(.34,1.56,.64,1)}
html.js.intro .glyph.g-1{animation-delay:1.5s}
html.js.intro .glyph.g-3{animation-delay:1.65s}
html.js.intro .glyph.sc{filter:none;transform:translateY(6px);animation-duration:.5s;animation-delay:calc(1.75s + var(--i) * .06s)}

/* the headline and lede follow the lockup */
.hero h1 .w{display:inline-block}
html.js.intro .hero h1 .w{opacity:0;transform:translateY(.5em);animation:rise .7s cubic-bezier(.2,.7,.2,1) forwards;animation-delay:calc(2.05s + var(--i) * .07s)}
html.js.intro .hero > p{opacity:0;animation:fade .8s ease 2.5s forwards}
html.js.intro .top > *{opacity:0;animation:fade .8s ease 2.2s forwards}

/* the ignition ring that leaves the ember tile */
.ring{position:absolute;pointer-events:none;border:1.5px solid var(--ember);border-radius:28%;opacity:0;transform:scale(1)}
html.js.intro .ring{animation:ringout 1s ease-out 1.05s forwards}

@keyframes draw{to{stroke-dashoffset:0}}
@keyframes fade{to{opacity:1}}
@keyframes land{0%{transform:scale(0)}100%{transform:scale(1)}}
@keyframes ignite{0%{filter:brightness(1.6) saturate(1.2)}100%{filter:none}}
@keyframes rise{to{opacity:1;transform:none;filter:none}}
@keyframes pop{to{opacity:1;transform:none;filter:none}}
@keyframes ringout{0%{opacity:.9;transform:scale(1)}100%{opacity:0;transform:scale(2.6)}}

/* ---- the top bar: the compact lockup arrives once the big one has scrolled away ---- */
html.js .top{position:sticky;top:0;z-index:5;background:color-mix(in srgb,var(--paper) 86%,transparent);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
html.js .top .brand{opacity:0;transform:translateX(-10px);transition:opacity .45s ease,transform .45s ease;pointer-events:none}
html.js .top.brand-on .brand{opacity:1;transform:none;pointer-events:auto}
html.js.seen .top .brand{transition-delay:0s}

/* ---- scroll reveals ---- */
html.js .reveal{opacity:0;transform:translateY(22px);transition:opacity .7s cubic-bezier(.2,.7,.2,1),transform .7s cubic-bezier(.2,.7,.2,1);transition-delay:calc(var(--i,0) * 70ms)}
html.js .reveal.in{opacity:1;transform:none}
html.js .rule::before,html.js .rule::after{transform:scaleX(0);transform-origin:left;transition:transform .9s cubic-bezier(.2,.7,.2,1) .1s}
html.js .rule.in::before,html.js .rule.in::after{transform:scaleX(1)}
html.js .rule span{opacity:0;transition:opacity .5s ease .4s}
html.js .rule.in span{opacity:1}

/* ---- app tiles answer the pointer: a slight tilt and a paper highlight ---- */
.apps{perspective:1200px}
.app{transform-style:preserve-3d;will-change:transform;overflow:hidden}
html.js .app.reveal.in{transition:opacity .7s cubic-bezier(.2,.7,.2,1),transform .25s ease,border-color .25s ease}
html.js .app.in:hover{transform:perspective(900px) rotateX(var(--rx,0)) rotateY(var(--ry,0)) translateY(-3px)}
.app::after{content:"";position:absolute;inset:0;background:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.55),transparent 60%);opacity:0;transition:opacity .35s ease;pointer-events:none}
.app.shipped::after{background:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),rgba(244,241,236,.14),transparent 60%)}
.app.newest::after{background:radial-gradient(260px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.28),transparent 60%)}
.app:hover::after{opacity:1}
.app .site{transition:letter-spacing .25s ease}
.app:hover .site{letter-spacing:.02em}
.app .site::after{display:inline-block;margin-left:.3em;transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.app:hover .site::after{transform:translateX(5px)}
/* the ember tile keeps a slow breath, the only thing that moves when nothing else does */
html.js .app.newest.in{animation:breathe 5s ease-in-out 2s infinite}
@keyframes breathe{0%,100%{filter:brightness(1)}50%{filter:brightness(1.07)}}

/* ---- contact: the ember line thickens and the link leans toward the pointer ---- */
.contact a{display:inline-block;transition:transform .25s ease,border-color .25s ease,color .25s ease;border-bottom-width:2px}
.contact a:hover{border-bottom-width:2px;transform:translate(var(--dx,0),var(--dy,0))}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  html.js.intro .lockup .g-band,html.js.intro .lockup .g-unit,html.js.intro .tile,html.js.intro .glyph,html.js.intro .hero h1 .w,html.js.intro .hero > p,html.js.intro .top > *,html.js.intro .ring{animation:none;opacity:1;transform:none;filter:none;stroke-dashoffset:0}
  html.js .reveal{opacity:1;transform:none;transition:none}
  html.js .rule::before,html.js .rule::after{transform:none} html.js .rule span{opacity:1}
  html.js .app.in:hover{transform:none} html.js .app.newest.in{animation:none}
  html.js .top .brand{opacity:1;transform:none}
}
