/* The home page's motion layer (2 Nov 2026), paired with home-fx.js. It only adds motion states on top of
   home-story.css: colours, type and the flat look (no drop shadows) stay as they are. Everything here sits under
   .fx-on, which home-fx.js sets only when motion is allowed. */
@property --fx-a{syntax:'<angle>';inherits:false;initial-value:200deg}

/* 1. Headlines light up word by word */
.fx-lit .fx-w{display:inline-block;opacity:calc(.14 + .86 * var(--k,0));transform:translate3d(0,calc((1 - var(--k,0)) * .2em),0)}
/* Things get their own layer only while they are near the screen (.fx-near, home-fx.js): every layer on the page makes every frame slower, wherever it is. */
.fx-lit.fx-near .fx-w{will-change:opacity,transform}
/* a long sentence stays readable while it lights: it starts at 30%, not 14%, and does not rise */
/* Chrome drops a gradient clipped to text when the same element is promoted to its own layer */
.fx-lit .hs-rb.fx-w{will-change:auto}
.hs-remember .fx-lit .fx-w,.fx-lit.fx-body .fx-w{opacity:calc(.3 + .7 * var(--k,0));transform:none}

/* 2. Arrivals */
.fx-on .fx-rv{opacity:0;transform:translate3d(0,34px,0);transition:opacity .7s cubic-bezier(.2,.8,.2,1) var(--fx-d,0s),transform 1.05s cubic-bezier(.22,1.32,.36,1) var(--fx-d,0s)}
.fx-on .fx-rv.is-in{opacity:1;transform:none}
/* the people-skills points: their top rule draws across as each one arrives */
.fx-on .hs-points li{position:relative;border-top-color:transparent}
.fx-on .hs-points li::before{content:"";position:absolute;left:0;right:0;top:-1px;height:1px;background:color-mix(in srgb,var(--hs-tone,#9162de) 45%,transparent);transform:scaleX(0);transform-origin:0 50%;transition:transform 1.2s cubic-bezier(.2,.8,.2,1) calc(var(--fx-d,0s) + .15s)}
.fx-on .hs-points li.is-in::before{transform:scaleX(1)}
.fx-on .hs-points .hs-idx{transition:color .6s}

/* 3. The showreel frame grows as it comes up */
.fx-on .fx-grow{transform:scale(calc(.84 + .16 * var(--g,1)));transform-origin:50% 0;border-radius:calc(28px + 28px * (1 - var(--g,1)));will-change:transform}
/* Tied to the scroll by the browser, the same curve as above: nothing at the moment its top edge reaches the bottom of the window, full size three quarters of a window later. The growth is its own animation so it runs on the compositor; a corner radius cannot, so it has its own. */
@supports (animation-timeline:view()){
 .fx-on .fx-grow{transform:none;border-radius:28px;animation:fx-grow-size linear both,fx-grow-corners linear both;animation-timeline:view(),view();animation-range:entry 0 entry 75vh,entry 0 entry 75vh}
 @media (prefers-reduced-motion:reduce){.fx-on .fx-grow{animation:none}}
}
@keyframes fx-grow-size{from{transform:scale(.84)}to{transform:none}}
@keyframes fx-grow-corners{from{border-radius:56px}to{border-radius:28px}}

/* 4. The six businesses pan sideways while pinned (desktop) */
.fx-on .hs-biz6.fx-panning{padding-top:0;padding-bottom:0;max-width:none}
.fx-hpin{position:relative}
.fx-hpin-in{position:sticky;top:0;height:100vh;display:flex;flex-direction:column;justify-content:center;overflow:hidden;
 padding:0 max(32px,calc(50vw - 590px))}
.fx-panning .hs-bizlist{display:flex;grid-template-columns:none;gap:20px;width:max-content;margin-top:0}
.fx-panning .fx-hpin.fx-near .hs-bizlist{will-change:transform}
.fx-panning>.hs-h2{max-width:1180px;margin:0 auto;padding:120px 32px 0}
.fx-panning .hs-bizlist li{flex:none;width:430px}
.fx-panning .hs-more{margin-top:40px}
.fx-hbar{position:absolute;left:max(32px,calc(50vw - 590px));bottom:48px;width:180px;height:3px;border-radius:3px;background:color-mix(in srgb,var(--hs-tone,#24955a) 18%,transparent);overflow:hidden}
.fx-hbar i{position:absolute;inset:0;border-radius:3px;background:linear-gradient(90deg,#77b9ff,#9162de,#df559b,#efac58,#7ac563);transform:scaleX(var(--p,0));transform-origin:0 50%}

/* 5. The six visitors stack as cards (desktop): one card per row, each sticks a little lower than the last, and the
   one underneath settles back as the next lands on it. */
.fx-stacking .hs-visitors{grid-template-columns:1fr;gap:32px;padding-bottom:12vh}
.fx-stacking .hs-visitors li{position:sticky;top:calc(96px + var(--i,0) * 22px);grid-template-columns:minmax(0,4fr) minmax(0,8fr);gap:24px 64px;align-items:center;
 min-height:340px;padding:28px 56px 28px 28px;transform:scale(calc(1 - var(--cover,0) * .05));transform-origin:50% 0}
.fx-stacking .hs-visitors.fx-near li{will-change:transform}
.fx-stacking .hs-visitors li>*{opacity:calc(1 - var(--cover,0) * .55)}
.fx-stacking .hs-face{height:100%;min-height:340px;aspect-ratio:auto;border-radius:20px}
.fx-stacking .hs-visitors h4{font-size:16px}
.fx-stacking .hs-thought{font-size:clamp(38px,3.6vw,54px);margin-bottom:20px}
.fx-stacking .hs-visitors p{font-size:19px;line-height:1.62}

/* 6. The two hearts (the real mark) drift in from either side, then lean in like the corner widget, and a spark pops */
.fx-pairing .hs-pair-svg .ph1{transform:translate3d(calc((1 - var(--m,1)) * -140%),0,0) rotate(calc((1 - var(--m,1)) * -24deg));transition:transform .6s cubic-bezier(.3,1.5,.5,1)}
.fx-pairing .hs-pair-svg .ph2{transform:translate3d(calc((1 - var(--m,1)) * 320%),0,0) rotate(calc((1 - var(--m,1)) * 30deg));transition:transform .6s cubic-bezier(.3,1.5,.5,1)}
.fx-pairing .is-met .hs-pair-svg .ph1{transform:rotate(6.5deg)}
.fx-pairing .is-met .hs-pair-svg .ph2{transform:translate(-3px,-1px) rotate(-12deg)}
.fx-pairing .hs-pair-spark{opacity:0}
.fx-pairing .is-met .hs-pair-spark{animation:fx-spark 1.1s ease-out .2s both}
@keyframes fx-spark{0%{opacity:0;transform:scale(.3) rotate(-30deg)}40%{opacity:1;transform:scale(1.3) rotate(12deg)}100%{opacity:1;transform:none}}

/* 7. $20 shines once it has counted up; the checks tick in */
.fx-on .hs-amount b.fx-shine{background-image:linear-gradient(100deg,transparent 42%,rgba(255,255,255,.75) 50%,transparent 58%),linear-gradient(100deg,#4fa8ff 0%,#7066ff 20%,#b840b8 38%,#ec5f86 54%,#f08a4b 68%,#e9bf2e 82%,#5cb85c 100%);
 background-size:260% 100%,100% 100%;background-repeat:no-repeat;animation:fx-shine 5s ease-in-out 0s infinite}
@keyframes fx-shine{0%,55%{background-position:140% 0,0 0}100%{background-position:-40% 0,0 0}}
.fx-on .hs-checks li.fx-rv{transform:translate3d(-12px,0,0)}
.fx-on .hs-checks li.fx-rv.is-in{transform:none}
.fx-on .hs-checks li.fx-rv::before{transform:scale(0);transition:transform .5s cubic-bezier(.3,1.6,.5,1) calc(var(--fx-d,0s) + .25s)}
.fx-on .hs-checks li.fx-rv.is-in::before{transform:scale(1)}

/* 8. Buttons: Possible's rainbow turns on rollover, the arrow leans in */
.fx-on .hs-cta{background:linear-gradient(#fff,#fff) padding-box,conic-gradient(from var(--fx-a),#77b9ff,#9162de,#df559b,#efac58,#e3d963,#7ac563,#77b9ff) border-box;transition:transform .35s cubic-bezier(.2,.8,.2,1)}
.fx-on .hs-cta:hover{animation:fx-spin 1.4s linear infinite}
.fx-on .hs-cta span{display:inline-block;transition:transform .35s cubic-bezier(.2,.8,.2,1)}
.fx-on .hs-cta:hover span{transform:translateX(4px)}
@keyframes fx-spin{to{--fx-a:560deg}}

/* 9. Coloured backgrounds only: faint rainbow light + ripples, inside the band's background layer */
.fx-bg{position:absolute;z-index:-1;top:0;bottom:0;left:calc(50% - 50vw);right:calc(50% - 50vw);overflow:hidden;pointer-events:none}
.hs-band.is-ground>.fx-bg{top:50%}
.hs-band.is-grounded>.fx-bg{top:var(--hs-ground,0)}
.fx-bg-glow{position:absolute;left:-260px;top:-260px;width:520px;height:520px;border-radius:50%;opacity:0;transition:opacity .9s ease;
 background:radial-gradient(closest-side at 34% 40%,rgba(112,184,255,.55),transparent),radial-gradient(closest-side at 64% 34%,rgba(112,102,255,.4),transparent),radial-gradient(closest-side at 66% 64%,rgba(237,115,112,.35),transparent),radial-gradient(closest-side at 36% 66%,rgba(226,189,80,.4),transparent);filter:blur(40px)}
.fx-bg.is-lit .fx-bg-glow{opacity:.32}
.fx-ripple{position:absolute;width:360px;height:360px;margin:-180px 0 0 -180px;border-radius:50%;pointer-events:none;opacity:0;
 background:conic-gradient(from 0deg,#70b8ff,#7066ff,#b840b8,#ed7370,#e2bd50,#70b8ff);
 -webkit-mask:radial-gradient(closest-side,transparent 86%,#000 92%,transparent 100%);mask:radial-gradient(closest-side,transparent 86%,#000 92%,transparent 100%);
 animation:fx-ripple 1.6s cubic-bezier(.2,.7,.3,1) forwards}
@keyframes fx-ripple{0%{transform:scale(.08);opacity:.32}100%{transform:scale(1);opacity:0}}
@media (prefers-reduced-motion:reduce){.fx-bg{display:none}}

/* 10. The story stays pinned while each moment slides up over the last */
.fx-storying{position:relative;display:block}
.fx-story-stage{position:sticky;top:var(--hs-gut);height:calc(100vh - 2 * var(--hs-gut));border-radius:var(--hs-r);overflow:hidden;background:#1f304a}
.fx-storying .hs-frame{position:absolute;inset:0;margin:0;aspect-ratio:auto;border-radius:0;clip-path:inset(calc((1 - var(--r,1)) * 100%) 0 0 0)}
.fx-storying .hs-frame img{transform:scale(calc(1.1 - .1 * var(--r,1)));transform-origin:50% 0}
.fx-storying.fx-near .hs-frame img{will-change:transform}
.fx-storying figcaption{opacity:var(--on,1);transform:translate3d(0,calc((1 - var(--on,1)) * 48px),0)}

/* 11. The doubts follow the scroll instead of rolling on their own */
.fx-belt .hs-doubts-in{animation:none}
.fx-belt.fx-near .hs-doubts-in{will-change:transform}

/* A loop stops while it is off screen (home-fx.js): it costs as much as a visible one and nobody sees it. */
.hs-ico-paid.fx-asleep *{animation-play-state:paused}

/* The page's rehearsal of its first scroll (home-fx.js): a copy nobody can see or reach, with everything that arrives on scroll already arrived. */
.fx-rehearse{position:fixed;inset:0;z-index:2147483646;overflow:hidden;opacity:.004;pointer-events:none;contain:strict}
.fx-rehearse .hs{position:absolute;left:0;top:0;width:100%;will-change:transform}
.fx-rehearse .fx-rv,.fx-rehearse .fx-rv *,.fx-rehearse .fx-w{opacity:1!important;transition:none!important}
.fx-rehearse .hs-frame{visibility:visible!important}

/* 12. The hero (3 Nov, Eugiene: "stop the animated text fly in… just nice fade"; "should be top down"): one fade from the top
   down: "Your website.", "More possible.", the line under it, the address box, then the platforms. No nested fades.
   Earlier: "Your website." flew in from the left, "More possible." from the right, and both recoiled a touch.
   The whole line comes from the left and the tagline from twice as far right, so the tagline lands from the right
   on the same curve. */
@media (prefers-reduced-motion:no-preference){
 .hero-content{animation:none}
 .hero-content h1{animation:fx-fade .9s ease-out both}
 /* "More possible." sweeps through its rainbow once every seven seconds, then rests (Eugiene, 4 Nov; the sweep itself is in home-fx.js). The gradient holds the colours twice over two widths, so sliding it one width has no seam. */
 .hero .hero-content h1 .tagline{background-image:linear-gradient(90deg,#70b8ff 0%,#7066ff 8.33%,#b840b8 16.67%,#ed7370 25%,#e2bd50 33.33%,#8abb73 41.67%,#70b8ff 50%,#7066ff 58.33%,#b840b8 66.67%,#ed7370 75%,#e2bd50 83.33%,#8abb73 91.67%,#70b8ff 100%);background-size:200% 100%}
 .hero-content h1 .tagline{animation:fx-fade .9s ease-out .2s both}
 .hero-content .hero-message{animation:fx-fade .9s ease-out .4s both}
 .hero-content .url-form{animation:fx-fade .9s ease-out .55s both}
 .hero .hero-platforms{animation:fx-fade .9s ease-out .75s both}
 /* The address bar loads flat, then eases out into its 3D lift (3 Nov, Eugiene: "it can load flat and then animate out") */
 @media(min-width:701px){.hero-content .url-form{animation:fx-fade .9s ease-out .55s both,fx-bar-out 1s cubic-bezier(.2,.9,.3,1) 1.5s backwards}}
 @media(max-width:700px){.hero .hero-input-shell{animation:fx-bar-out 1s cubic-bezier(.2,.9,.3,1) 1.5s backwards}}
 @media(min-width:701px){.hero .url-form{transition:.5s cubic-bezier(.2,.9,.3,1);transition-property:translate,scale,box-shadow}}
 @media(max-width:700px){.hero .hero-input-shell{transition:.5s cubic-bezier(.2,.9,.3,1);transition-property:translate,scale,box-shadow}}
}
/* The address bar's resting look is the lifted, 3D one (3 Nov, Eugiene: "make that the default view"). Which element is
   the frame depends on width: the form on wider screens, the shell inside it on phones, where the button sits below.
   While the URL input has focus it goes flat again (3 Nov, Eugiene: "when you click to type your url the box retracts to
   its flat state. when you click out it again extrudes"). The phone's focus ring comes from jukebox.css. */
@keyframes fx-bar-out{from{translate:none;scale:none;box-shadow:0 0 0 0 rgba(112,102,255,0),0 0 0 0 rgba(31,48,74,0)}to{translate:0 -5px;scale:1.018;box-shadow:0 30px 50px -22px rgba(112,102,255,.5),0 12px 24px -14px rgba(31,48,74,.3)}}
@media(min-width:701px){
 .hero .url-form{translate:0 -5px;scale:1.018;box-shadow:0 30px 50px -22px rgba(112,102,255,.5),0 12px 24px -14px rgba(31,48,74,.3)}
 .hero .url-form:has(input:focus){translate:none;scale:none;box-shadow:none}
}
@media(max-width:700px){
 .hero .hero-input-shell{translate:0 -5px;scale:1.018;box-shadow:0 30px 50px -22px rgba(112,102,255,.5),0 12px 24px -14px rgba(31,48,74,.3)}
 .hero .hero-input-shell:has(input:focus){translate:none;scale:none}
}
/* The pre-rendered copy of the page fades in like the live one, from the first paint. When the app swaps it for the live
   copy it carries each animation's progress across (carryHeroMotion in app.js), so the hero fades once however late the
   scripts arrive. It used to wait 1.6 s unseen, which showed the hero twice whenever the scripts took longer: the first
   visit after every deploy (Eugiene, 4 Nov 2026). */
@keyframes fx-fade{from{opacity:0}to{opacity:1}}
@keyframes fx-fly-l{from{transform:translate3d(-38vw,0,0);opacity:0}40%{opacity:1}to{transform:none;opacity:1}}
@keyframes fx-fly-r{from{transform:translate3d(76vw,0,0)}to{transform:none}}

@media (prefers-reduced-motion:reduce){.fx-lit .fx-w{opacity:1;transform:none}.fx-on .fx-rv{opacity:1;transform:none}}
/* The compact two-hearts strip: short drifts that stay clear of the text beside or below the hearts */
.fx-pairing.hs-hstrip .hs-pair-svg .ph1{transform:translate3d(calc((1 - var(--m,1)) * -38%),0,0) rotate(calc((1 - var(--m,1)) * -16deg));opacity:calc(.35 + .65 * var(--m,1))}
.fx-pairing.hs-hstrip .hs-pair-svg .ph2{transform:translate3d(calc((1 - var(--m,1)) * 30%),calc((1 - var(--m,1)) * 80%),0) rotate(calc((1 - var(--m,1)) * 34deg));opacity:calc(.35 + .65 * var(--m,1))}
@media (max-width:720px){.fx-pairing.hs-hstrip .hs-pair-svg .ph1{transform:translate3d(calc((1 - var(--m,1)) * -70%),0,0) rotate(calc((1 - var(--m,1)) * -16deg))}.fx-pairing.hs-hstrip .hs-pair-svg .ph2{transform:translate3d(calc((1 - var(--m,1)) * 170%),calc((1 - var(--m,1)) * -40%),0) rotate(calc((1 - var(--m,1)) * 34deg))}}
.fx-pairing.hs-hstrip .is-met .hs-pair-svg .ph1{transform:rotate(6.5deg);opacity:1}
.fx-pairing.hs-hstrip .is-met .hs-pair-svg .ph2{transform:translate(-3px,-1px) rotate(-12deg);opacity:1}

/* ---- Phones: the same set pieces, sized for a phone (3 Nov) ---- */
@media (max-width:720px){
 .fx-hpin-in{height:100svh;padding:0 18px}
 .fx-panning>.hs-h2{padding:72px 18px 0}
 .fx-panning .hs-bizlist{gap:14px}
 .fx-panning .hs-bizlist li{width:min(80vw,330px)}
 .fx-panning .hs-more{margin-top:28px}
 .fx-hbar{left:18px;bottom:26px;width:140px}
 .fx-stacking .hs-visitors{gap:18px;padding-bottom:8vh}
 .fx-stacking .hs-visitors li{top:calc(64px + var(--i,0) * 12px);grid-template-columns:88px minmax(0,1fr);gap:0 14px;align-items:start;min-height:0;padding:16px 16px 18px}
 .fx-stacking .hs-face{height:auto;min-height:0;aspect-ratio:5/6;border-radius:14px}
 .fx-stacking .hs-visitors h4{font-size:12px}
 .fx-stacking .hs-thought{font-size:24px;margin-bottom:10px}
 .fx-stacking .hs-visitors p{grid-column:1/-1;font-size:15px;line-height:1.55;margin-top:12px}
 .fx-story-stage{height:calc(100svh - 2 * var(--hs-gut))}
}
/* While the business cards pan, the green ground travels with the pinned stage (so its edge never slides behind the cards) */
.fx-panning .fx-hpin-in{isolation:isolate}
.fx-panning .fx-hpin-in::before{content:"";position:absolute;z-index:-2;inset:0;background:#fff}
.fx-panning .fx-hpin-in::after{content:"";position:absolute;z-index:-1;left:0;right:0;bottom:0;top:var(--hs-stage-ground,50%);background:var(--hs-wash)}
.fx-on .hs-biz6.fx-panning{padding-left:0;padding-right:0}
@media (max-width:359px){.fx-stacking .hs-visitors li{grid-template-columns:60px minmax(0,1fr);gap:0 12px}.fx-stacking .hs-visitors h4{font-size:10.5px;letter-spacing:0}.fx-stacking .hs-thought{font-size:19px}}

/* 3 Nov (3): the second film rises in with a tilt (the A/B frame just fades in with its column) */
.fx-on .hs-ab .hs-jr.fx-rv .hs-abframe,.fx-on .hs-ab .hs-jr.fx-rv.is-in .hs-abframe{transform:none;opacity:1;transition:none}
.fx-on .hs-funnel.fx-rv{opacity:1;transform:none}
.fx-on .hs-funnel.fx-rv .hs-funnel-frame{transform:perspective(1400px) translate3d(0,90px,0) rotateX(14deg) scale(.9);opacity:0;transition:transform 1.3s cubic-bezier(.2,.9,.25,1),opacity .8s ease}
.fx-on .hs-funnel.fx-rv.is-in .hs-funnel-frame{transform:none;opacity:1}
.hs-skills>.fx-bg{top:var(--hs-ground,100%)}
.fx-panning .fx-hpin-in::before{background:var(--hs-wash)}
.fx-panning .fx-hpin-in::after{display:none}

/* Option E: the rainbow trail. Each spark is a hairline rainbow ring that opens out and fades in 0.7 s. */
.fx-spark{position:absolute;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;pointer-events:none;
 background:conic-gradient(from 0deg,#70b8ff,#7066ff,#b840b8,#ed7370,#e2bd50,#70b8ff);
 -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 1.4px),#000 calc(100% - 1.1px));mask:radial-gradient(farthest-side,transparent calc(100% - 1.4px),#000 calc(100% - 1.1px));
 animation:fx-spark-out .72s cubic-bezier(.2,.7,.3,1) forwards}
@keyframes fx-spark-out{0%{width:12px;height:12px;margin:-6px 0 0 -6px;opacity:.75}100%{width:58px;height:58px;margin:-29px 0 0 -29px;opacity:0}}
@media (prefers-reduced-motion:reduce){.fx-spark{display:none}}
.fx-bg-glow{display:none}

.fx-fade-price{opacity:0;transform:translate3d(0,10px,0);transition:opacity .9s ease,transform 1s cubic-bezier(.2,.8,.2,1)}
.fx-fade-price.is-in{opacity:1;transform:none}
/* Hero colour cycle preview (?swirl=a|b|c): the corner hazes come up to Eugiene's reference strength, clockwise from
   the purple at top left, then ease back. Nothing here applies without the address flag. */
.fx-sw{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden;--p:#e6daff;--o:#f9e4c8;--b:#d6e6ff;--g:#ddf6d6}
.fx-sw i{position:absolute;inset:0}
.fx-sw-tl{background:radial-gradient(ellipse 40% 55% at 14% 24%,var(--p),transparent 78%)}
.fx-sw-tr{background:radial-gradient(ellipse 38% 46% at 83% 13%,var(--o),transparent 80%)}
.fx-sw-br{background:radial-gradient(ellipse 35% 42% at 71% 86%,var(--b),transparent 83%)}
.fx-sw-bl{background:radial-gradient(ellipse 30% 39% at 27% 88%,var(--g),transparent 83%)}
.fx-sw-all{background:radial-gradient(ellipse 40% 55% at 14% 24%,var(--p),transparent 78%),radial-gradient(ellipse 38% 46% at 83% 13%,var(--o),transparent 80%),radial-gradient(ellipse 35% 42% at 71% 86%,var(--b),transparent 83%),radial-gradient(ellipse 30% 39% at 27% 88%,var(--g),transparent 83%)}
@media (max-width:700px){
 .fx-sw-tl{background:radial-gradient(ellipse 65% 39% at 1% 26%,var(--p),transparent 82%)}
 .fx-sw-tr{background:radial-gradient(ellipse 60% 37% at 99% 12%,var(--o),transparent 83%)}
 .fx-sw-br{background:radial-gradient(ellipse 63% 42% at 95% 90%,var(--b),transparent 86%)}
 .fx-sw-bl{background:radial-gradient(ellipse 60% 37% at 10% 94%,var(--g),transparent 86%)}
 .fx-sw-all{background:radial-gradient(ellipse 65% 39% at 1% 26%,var(--p),transparent 82%),radial-gradient(ellipse 60% 37% at 99% 12%,var(--o),transparent 83%),radial-gradient(ellipse 63% 42% at 95% 90%,var(--b),transparent 86%),radial-gradient(ellipse 60% 37% at 10% 94%,var(--g),transparent 86%)}}
/* A. Corner by corner */
.fx-sw-c{opacity:0;animation:fx-sw-swell var(--lap,16s) ease-in-out infinite}
.fx-sw-tr{animation-delay:calc(var(--lap,16s) * -.75)}.fx-sw-br{animation-delay:calc(var(--lap,16s) * -.5)}.fx-sw-bl{animation-delay:calc(var(--lap,16s) * -.25)}
@keyframes fx-sw-swell{0%{opacity:0}18%{opacity:1}42%{opacity:0}100%{opacity:0}}
/* B. Soft swirl: one blurred ring of the four colours turning clockwise, kept clear of the words */
.fx-swirl-b .fx-sw{-webkit-mask:radial-gradient(ellipse 60% 62% at 50% 46%,transparent 32%,#000 100%);mask:radial-gradient(ellipse 60% 62% at 50% 46%,transparent 32%,#000 100%);animation:fx-sw-breathe var(--lap,16s) ease-in-out infinite}
.fx-sw-ring{left:50%!important;top:50%!important;right:auto!important;bottom:auto!important;width:260%;aspect-ratio:1;margin:-130% 0 0 -130%;background:conic-gradient(from 0deg,var(--o) 0deg,var(--b) 90deg,var(--g) 180deg,var(--p) 270deg,var(--o) 360deg);filter:blur(50px);animation:fx-sw-turn calc(var(--lap,16s) * 3) linear infinite}
@keyframes fx-sw-turn{to{transform:rotate(360deg)}}
@keyframes fx-sw-breathe{0%,100%{opacity:.3}50%{opacity:1}}
/* C. Travelling light: the stronger haze shows only where a soft light passes, clockwise */
.hero.fx-swirl-c .fx-sw{-webkit-mask:radial-gradient(circle max(38vw,300px) at var(--x,14%) var(--y,24%),#000 0%,rgba(0,0,0,.5) 45%,transparent 100%);mask:radial-gradient(circle max(38vw,300px) at var(--x,14%) var(--y,24%),#000 0%,rgba(0,0,0,.5) 45%,transparent 100%)}
@media (prefers-reduced-motion:reduce){.fx-sw-c,.fx-sw-ring,.fx-swirl-b .fx-sw{animation:none}.fx-sw-c{opacity:.5}}
/* The period that points the way: it hops up out of "More possible.", falls onto the address box, and a rainbow line runs round the frame */
.fx-dot-src{transition:opacity .5s ease}
.fx-dot-src.is-out{opacity:0;transition:none}
.hero .fx-dot-svg{position:absolute;left:0;top:0;z-index:5;pointer-events:none;overflow:visible;max-width:none;margin:0;display:block}
.hero .fx-dot-svg .fx-dot{fill:#c9bd57;stroke:none;transform-box:view-box}
.hero .fx-dot-svg .fx-dot-trail{stroke:#c9bd57;stroke-linecap:round;fill:none}
/* (the glint is no longer drawn) */ .hero .fx-dot-svg .fx-dot-glint{fill:none;stroke:url(#fx-dot-rb);stroke-width:3;stroke-linecap:round;filter:drop-shadow(0 0 4px rgba(184,64,184,.35))}
/* Touchdown: the rainbow line runs round the frame. It sits inside the frame, so it moves with it. */
.hero .fx-ring-host{position:relative}
.hero .fx-ring{position:absolute;z-index:3;pointer-events:none}
.hero .fx-ring svg{display:block;width:100%;height:100%;margin:0;overflow:visible}
.hero .fx-ring-line{fill:none;stroke-width:3;stroke-linecap:round;filter:drop-shadow(0 0 3px rgba(112,102,255,.3))}

/* 3 Nov: the dark buttons get the same rainbow ring as the other buttons, cycling round them on hover */
.fx-on .hs-cta-solid{border:3px solid transparent;background:linear-gradient(#1c2742,#1c2742) padding-box,conic-gradient(from var(--fx-a),#77b9ff,#9162de,#df559b,#efac58,#e3d963,#7ac563,#77b9ff) border-box}
.fx-on .hs-cta-solid:hover{background:linear-gradient(#111a30,#111a30) padding-box,conic-gradient(from var(--fx-a),#77b9ff,#9162de,#df559b,#efac58,#e3d963,#7ac563,#77b9ff) border-box;animation:fx-spin 1.4s linear infinite}
