From 2800c84699d2dbd9a4ecde0ca5d2e332849fd21d Mon Sep 17 00:00:00 2001 From: BFlat Date: Mon, 2 Feb 2026 23:45:26 +0700 Subject: [PATCH] Feature/purchase onboarding flow (#1027) --- frontend/apps/artcraft-website/_redirects | 8 + .../public/images/buy-credits.png | Bin 0 -> 29542 bytes .../public/images/try-download.png | Bin 0 -> 28642 bytes .../apps/artcraft-website/src/app/app.tsx | 6 + .../src/components/landing-action-buttons.tsx | 54 ++ .../pricing-table/pricing-table.tsx | 123 ++-- .../src/pages/checkout/cancel.tsx | 55 +- .../src/pages/checkout/success.tsx | 54 +- .../src/pages/landing2/landing2.tsx | 665 +++++++++--------- .../src/pages/onboarding/index.tsx | 1 + .../src/pages/onboarding/onboarding.tsx | 512 ++++++++++++++ frontend/apps/artcraft-website/src/styles.css | 49 ++ frontend/libs/api/src/lib/BillingApi.ts | 145 ++++ frontend/libs/api/src/lib/UsersApi.ts | 121 +++- 14 files changed, 1425 insertions(+), 368 deletions(-) create mode 100644 frontend/apps/artcraft-website/public/images/buy-credits.png create mode 100644 frontend/apps/artcraft-website/public/images/try-download.png create mode 100644 frontend/apps/artcraft-website/src/components/landing-action-buttons.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/onboarding/index.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/onboarding/onboarding.tsx diff --git a/frontend/apps/artcraft-website/_redirects b/frontend/apps/artcraft-website/_redirects index 8498c25070..532126700a 100644 --- a/frontend/apps/artcraft-website/_redirects +++ b/frontend/apps/artcraft-website/_redirects @@ -2,6 +2,14 @@ /checkout_cancel/ /index.html 200 /checkout_cancel/* /index.html 200 +/onboarding /index.html 200 +/onboarding/ /index.html 200 +/onboarding/* /index.html 200 + +/portal_closed /index.html 200 +/portal_closed/ /index.html 200 +/portal_closed/* /index.html 200 + /checkout_success /index.html 200 /checkout_success/ /index.html 200 /checkout_success/* /index.html 200 diff --git a/frontend/apps/artcraft-website/public/images/buy-credits.png b/frontend/apps/artcraft-website/public/images/buy-credits.png new file mode 100644 index 0000000000000000000000000000000000000000..f6bd102d2802aee76bce616b386bc45b6de0faa2 GIT binary patch literal 29542 zcmcF~g;N|)v^BE8qQTugxVtS9LU4k!xVuYm4-!1MYjB6)t^pQzcX#*4@B7}r@T#V3 zYPxEsZ_Au}Zr{`4N($1bNQ6jGP*A8cUnNzbpr8{z%2y!#M@`}`R@BE0(c!C>GZYjq z&3^@2Muqy~qY~O#MOqxH5<-0V@c=Lf$%CMvYGROI4B?=loStPQL8>0mr-`~ORxs{DG<$}hZ$#G38Bx!a@VyNb0EGU3cl9B`0t5MWfvqw! zSu;?19#`eCZ1#%g>ej+S>QY&%FC$>53^a6;l)xSUh}Zywa@5O&v)3*e*I(Y927jo= z%IPGb3y~sy8`py&41LE)0s!QI$<>C-3vU&P1tJ^03f~wQEE?TR z_VGDNXaE7l1#MZwOF<=eTW6L9%JE5PSw?oaTEct#mdT%`N5>2YPbdgQ8=LCYCuS>= zp%9o5M2>jPeN91wEb4?Sc){sJ#`iC2kv`2VcgnV3fADl*MT!-qVWfAj|D1C3YlJv` zlA9BI5d=Cl=Ae}_u=Y`QLZ%D;9S>s9T!9tm`E*_^px=wGs>?#{!*|i0{H(B zP^z_NRtBt%flg~6!@ytEU<*KbW}_j*Q3RI@;&!3^6E`D25Lz4{PK$ve-PM3Nw%DNR zPu>Y*u_yioU3J+Y^Rym=c1Fl0cuY%rpbD$4Vs}g$@~9xHJ%A6 z_gweoB1rC*PNW!$g_j75!+<5LZ5bpR{> zRaVZi^>jx$9THlUd*~RF3H_g{9*q;K|q)F-^ z2;Ik^7zWT#Co%HJADR^-fdxlS?=5wIHCS;FOCD<}Vv$+qk^d-%$1~M5!bY!~2$7DhgBt_)LUo`tFI`2r0Sbx;>@bNjR$o0p;#8H8{(m~m-rf5}N@HEa zJL8rdkRuPvZhlfktYhKWKL|tn-u+H~?G*oR*!{;(YF$JEGjQnTSX3U`5L%`RAZp#g z;=OtV-Fy(y9E$T!qjWq+!%EjH!|i65;Q`w7=DUD!BnZW8<^_xM_n8f1)TS?R`(0#|^pE1_ zKLj6_wPefqT1W#k@FvWi;>ZuoL5xFaZXqQ_z9Gn)VKnn#^Gi#I+do3hzO)27M*NUN z{^6AC+9mbHj)LaT3XX&dqsZcTX+MXgnz415-rxA|r^jvBkNL?EAnzT$Ydhg!J|)g( zV6};$mk?sB#4v9lp(<)=0419Qs?*ed3wdBrV@p^1BN#MhMx<%L1!Yu$U`C$h+X0un zB;hAN0Pk78H0+v@Wbf#ZXq&Vn6S?^7yto+ptZuR=eg&T)gQNTL-ef3+KW-BNDS-m5 zGtUnb!W^WXdleXvRy;GoYiMa1^NCIhLCsuCJo6_OJ)!JF#l;GXyqq>6Tq4B80`C0M zEQh!veFc@Md%seQy6MfEB{`Z$8kh>RE-e%-m}^s%kEQV(}A8#SHzsTk)@k@sp_2tu=m}f?9PZ9b3Jb| zU;hI_WPzXXn!jl$)(rRxy|}Yk`rXLv{hH&(d%w0sjphA3jC>z;MlO`R?Z?n}P+o2V zC9(<*`yrcm53zB{bzkEB1k&JDnG?c|z~JlzZ%G;4d225OV=T27yvB=6$(_BEYjo;2K-;fW@YJ;kRi;Yb+X~L56WbuY(apRk;M65HM z6|DqjOvb4;2Z6bOwLkTN_2oZ9w`&@d6zz=N)C;WSf5WaqZco#5jW3TJ-3@N_kT|8f z8{PH#v~d&nKJv_mpj`dX7Qy|7Oj=`SmQuJ9LotUQIf=g(jQU1M$mILOfbr2#Re#gV zW-0Cea15JP0>#&8+=Y`V@(!6Uu#ZZ*1%c!qemC~7M6B)k)WEs8U@Z`|#S3+hB5)tn z>$ZFTMtqie;girQyrX&ao$#w2x|F3C+L?XhS}j`+A>p6Yl806AEX0J7cmy|1NfrRT zTqvUQ(UPQn7#Rs0cPJJ%WEed#Ta{B6Wl|*y0AVK$?m!x@ z-Qk%?WZUmm!gSV2TD4jzv>dJc9dQfI!i7po1S)XkoFi1oINo?V?rOh7m{>=wa-=w! z*??IK{_D?cXx4&Xx;^HP|04vfn!`q*U95Xvl<-S_t*==U){c%J633X4@f?DG|H-=H z=UA-;_8CB0)W%861G*S`-;cA9W;vU2#7J17-NjudNPG0-Z%g(-1O(D6lQ=~{ZH{TkHdyc*|56XCqoS~R({X6_*7yh8+i`Eaig z7(?iRjvg=Y;!Rx&F)PZ)ieO0>TkPg9orT;x`%$4bbz{bMsmT)fNukh|K zklLWK9aDD2RnIJRcE2yvP5|W7G@N}KqyWtxT__Kr9`llEPt`e@FxIxgL=TPLjiw2# zgn@n$9FJd%^3<3b=CZpstT>cyIYkX!<+SBo3~a7%VI?Tg{mcanKteA}*tWP@hmEe3$-=all;p(;sId4U|8tsh*qtvO z&QYiW8;bP78XZt$D%R7-()>%vIRVbc%}h~adN^E;@HkZaq%EhKA~T~tT8_TbF%dk7 z;za4BD|bQsWR|fZfH46Q)WOU6`<1bwER*Yd#!Kef-(TB3{w3&*zM>5VS{o*d8Vb0Q zniN0|AQ&m3n=biQqCffb_zvAEa?6qPMD^#fS{2AJv459y;b)X7^DTkABMl3yLdS+_ zc`SOOhp%O*2A{S3ST5;>2#9aKNu%$)Y&z^wCfLHCKdAOJ(~wAFas8dLe?Vx-5`i&wOoP(cMcVw=%;C*_zJQYec|%CNQt=g=VbII6 za<~*)iaD-REeWAeR!Axm#{t8{Vrm?kH7tjpEHF48e!pWA3!%y}Rwk>EaZ9cmh{8Q9 zULLKp#$V~?ghX?`i(4g;?l#ux`(cJ5FCKD6ekF;`-j13k*Ng0rNFt$^Q*1>dQ zJk3U1oeT~!5JjF?%DH6Y1rd|cdYp1=7%t;oV%H;kXnM8=0jA$nZ3UFpR9>b1G%)OAsE0=$TQ7t=AKf?MS82`}m`ShpTRaTq71cF!i z9J|b?zy3kN8=NF-!)0PNc79AMdZmRa)%B0GAYHOj$G5U#_u`}EG8)W*bO2p=Z2K?G=oiG@y%DG~EZ9sygmwdYz- zvcV|Dd%yo(83^NuxZQA$P0j}i;RTXYVbJZWF66UBZ^qAe!FtF`A!lt{l}}}EFTUQ| z$VTW4c&Ua;&^V}w{t)*_!_!t-P{NTVWs7@m3ImF8u3Axr~V5{BaZk!jzv;&+ST*iN<3k{s5+Z%d1~ zs8|xt7y!p#5}e5h3LZF30q$>=&W>mmSeu}AXAVQ>v=Bi$?=!JuSw!v9mNKC-ryr(l z%~J>P{ZLEoXy}z~W1jo-V|@Fk0dcvo*&ZW!48ndgeM3XtYO@>AbXCgx^)v)5=?@es zW+D+o1cdk(uELk;DY}Wz4pw=B2-^O8-mm0`?OI&G&?okK2R94mA4Cv1L=Mc2Z`Z{E z&+_3c&;Wi}_|I}ribriwxfowl9n^8`QtPm3gLo%13&r?3u zq0afs^35&~-g0VQN6*?Zy1-cLl8~dEyF$-msz$pzma!$%$imYpjqb1LZy~~T2a=N- z@8g~70=1Xr3iN|l#p948zjNY|HEe(TS`1h|8)%{YuKCA0XR|%1D}Nio;!0q7D;nrT zF>y7{ur{yN^DGc^fj9`#yCsIXX7iIYVh33zbr+>(Zh#qXhdda?Hj_nl`Q3q$)sRZsYE96 z>;;uvw($aPR14M>*qp6oK-2k`+4M}|LE27ODCimL2P$4Zs;6lKJLy%w1?xor&{!VZ<{+3;fc82sw>{#g$a0meAwUxc21q8Y;} z>w64%J6GJxE`hNZYfGMid07l%v2|UAY>uKO&b#tl8|+z0VfzCrYF;FK(r_6Dgbt#f z5rpu4k2awpz#}Zkqw5HljZ`Fy&7U+n+fe zoafqcTuxOMyxcl)=*s}CMxwAv@ z+#L;b;&x3V6Y)<4casSZN;&wAVE3ORn1?)pK~-t3gb=K(FD{qc8E-?H*tA3ZU6j=2 z4Yi(*=(LK0cm!9UqjrceVoh9P_ejV6iGhK=4~lnReDM#yLB(J+V)Ok;f;S1?gg}2fqblR$UipH4;UhZr@I}Q%2h~pC zt%m%c+l>hGSC3%ps?8}sqnM;m-_@^fdsJVZo0Hh|t{Jnk{}pyh2Jx5$_qd-GU^I00Ta(sN%&aM^hwM$?W3>o-WoiYtY$X;8+6rKE zOs=NW?oX~O(l@~IAm=02?Nz%3MT#xnh>%?s!_QlI?B~12EAq(>Zu!@LHhJhphHCkm zyZ$Wa+r3+Q6CGh+*_h@1X@2qaJ96}h(=6s9CVB!DP!3}isU6~4NB(Qw8MU`Ei9}#C z4zxWtYHA;I`svlkIpIayp_<_u<-Uli1LYZJDF=}$DxJ$-#FlqfV)mhf^o`Gd7L`zXCx3+8ToFE#f$? zGFrzz;lY@&VF^zIGHQ}ZvoVJVQ)rJ-ZQzK|s<@n(K;`DPQi z1MWRTMqVpPKs}@Su-}ngrP8@jVl2>J(kwGJ(XH$qWO1c132ao`plD;2rt*+QP3jDo ziW)};d0r}|WF$LLs8aFU=XQ3&9Iz7fT)?4CpRA2kKL`{jk+&q`QTNa@AczNIF)R~H zG9$gex}FJY)CRutj1@b<-T#5-y$F==@0?jWYe2jvF}RmxK@mlMq8#uzMLC90WNn7S zW;wCYDWG23mbdb?yrw#PwEhj6rFt6*We~5!O!W@gBeh+p=Sg@W(hiYlc~q#x@uh>? zY+)D)x<*FA6Ag53e)n16Z<+P+3Rc$ad2&%0cJW>9=HINiM@Z@rw}t}22S}$OzDrGa zbxj5qicDzBzB^S$Tm(iI+A`_0rwF{%b>01x&9`%cdQ{tV<`ZH=t_fu4VRWf55Ue;C zZd`Yde_1wPY#BwT%l{=As=9cU=q^#x%<{#R`WFN8R8Tu zx@stE?iNtzd^uY=e?1Q;I0oW#EHm)eT&CAK3vY$b4jwYo(VK>g?5CqEo~OBKu&KUZ zENr#ciu#E7V?x5of3OAlF}gP)qV4o_J@Xs{U2E}GGWKf*Q53_bD;%A-@)dr#I;U#Z zg!Mb>u)s9V3R8sx_iSYR8f!1vYtEVIc+8564zz~bmL4B2?TD8~m?z2(zSE#2`C%My z_}ni^$6}0|xl7on#O(UmOQIa!`2J>7M2WSe=sQd`I<}0q_mi{ScqBCF_~q@QU20C* zy>ENC!6Hca%&Bl?KGp@v=mLvnkJl>DIgY-xMACkC@5g-QHycB$4FR9#T}$Ny%qxm8 zb~3gMx$pur1RqeYs9pfaLkQw`by{xcmNxgTh3;zh$L2NRa;gF52P@#9JX&${1RwmG z92Q-(^=4vgoTPrj({JB=ey!}|z@up^&Uq<`DtihnUm6cA z`63!*AupnL@}i6k9m5OYm^Li;{EZb3%1uEtLD}K*30?^O!r<(PN&qae>dhGL*?t4C z+k8Vjysk_Ac~aXcalr+fddLBuJ0TK5094YIulBe|H4#kwz_oxvsXBM-9^X0$0ZReY z6j*MJJ?01|Y8p48D>E*>9d+jJt^_ciOE6yF%^hLFBk+|SESE9YkQ)zoB8SFNQDM%= zv5?l!q1G~J^#16RnHTj^osl^!h$<)YB$@aYnV+e!x5)HPzsa4GOk#lo6R=%tP3Pz5 zv+Sne;RPzM2P%yC0IgiLVkQMX^*2l=&G?g3VPn(cp`PRjY)vAjmcO0GIhS$P zp^5rd=;B-BMp15+;jslqKnX?vD{UQ637P8<@?vGEKK!v}uCm>LSEeO%dgL5yd@AqQ z)0z6EIujY9Lw@iirwX}J)&#lWyD><9VL>6sgKK;32=*(fxp8w8TvOw$@hyCRGzPTu zKe@ji6CJmeKZ)faMlyxL;>+$NM6ia$L;IwKKpIV2$6TFBOskQR__W6?4fILZI>4=_ z#2Pe94CwXsJn60DToZnH0D{UKwoCMm{oV?QC-_C+K33k#Vq$o*C`RhtaZV^&j}tXn z3u1q-kd*Yc#WQGnmx#7WSuxktOtxej%gf7uw#%;hK)T;HFikh}phtOASMu-?g3b6% zUk1`+0bqjL{z4OblP-JhbA9^c&7*KWoBv;%ket*J<0hVpR3Gl&EI`6Htwjy`35=C? zB=sGF8OcNivZMmOB)QU2c!WVjIf-(FM6}>c=<$Z|pE#iiW#vS;@&Sy=l{hClBi4+n z51OKXxlxj%r$O&oLQ5U;$v)OXpb^p5M|V){CNdJ%_~Zv?9cP$FBb8-EtNi>uG{MW^ z=w$bNOrXYm(Hc4FZm_H_!vcfh*j32pg(f3syrGkPY}nOfUB({2QdmGwR@HG*goRhJ`Nx~%+S2V!n0vh*CbltXh&K*w`jS@Pa$6{ z9b+&>vW?S&6qa8m@T#SEv#_a?KqM%^Y zX6579e6rfwlu)n0;!ExobLP{GEq&Uz*F2JS45K?G`!=ijp>_t)YR^ag^JQvj~qx2!^Y(S6+0`0 zDzi)H&f`Fykf|#Y7(E^{TvD=rxX_DOatq#0s;}IDgY(h!Vdd}ZD?F8b!&0^lpJyr#|D`Np&q-g} zJ|O^Z&rUqUN;_~8MyC1#!L>>QM1FbnFN}Z+L?M|NrSV6?h`j55#9gbCYs~1(?b{l{ zO%rb-C4i*}@|$a6j2@zs(ylVKhfICY95#zlaf$+Lu+BdDi8@@;^Ei|aC?1u?vzTfh zO=L&M_D6q){Hz&(pEZYVbMuwJWp{s+EFKYNkZ=8AXxe!?yh{M_BNfcF+(Ns9sMqAFJ<@~6Yq@=VDC}>nIGb^j&yt7H9 z4zYN7TiLU?>))!f`_F_buldS>FDyfFK_jkP+}|Lh5j_9`4sg903j^Q78eaOt{4sdP z-b4koF?7g~@v0sI%Ld)rNryYU3b~S|X55d(sIhb_qMlct+pY&8Olbx0#91x- zlJ3Ns0hRtF`Tc9&smBg#WcVct3<69bHwHKP(1*$(rTIyHi&DgDxGhs5#Tx?0N-e2f z&8(Gsx?Hb*b!wisHIi_X_Gijs?(eGPlAsJ0SvZ0jY}&z>gp(%QQg#on&)++Pb4Fzd z*BRUblsGrw1_VI53?OSJ+<|$yBOe2X3D{&WLXxG+eJ7xs%3Co8cDu^fD>V z4YySupOZMULl&R;q*Jj&ZGCWqv-BcegKvOW zlTb8um6nbY56`=oTbrLB3(yHW0u#h(Y{rky^x-Q0|4P6Fqh}*l#Q_QV9DSNN9|_e0 zynTZP&e*&<16-x-eJbGQEda}bh%1exI8FV8^1bXEW?$P_sRG<%tpTkrN%QrR-v(f0 zD-n{y*wk%V1L6qcTCYs}=G zZ7b?D&aZ}97N$T6d@ETA_quduVbLaSU7E(gKH5n|xS_Bh#n=X4)|m8%8mRJlewo;q{FY(n19!yYHkfts&_v~xn^+r z%-vZt7LlLSGoW4o2AA_}H-lMln(XeHAUbdD&}o0$ z+!GyM|6paW>~H7x;tN8kAQozgj*JN1Y{zG}TJ3HnMO9zao79D;)c)eSXSP=UbZAZz z3H9W5Gh_y#ABbkdd5kGq zu|P6s(c7Sfy;mTX$#d=EV@MPdQ?z@_g35K(<8#isFvX1?!PD!^5=$}qPLCsWaCq~~ zQL6#dQt${_P!J}4ySP6dSM!UPWsqwRG6pU$z+|B-xmx*Z_Z7}zbDyE(XXGp%G&y}b zEYDKSh=3h2OCTdaJfb<#+r5O98kLwexO~!Q@eUbp4KD%e1B9B;)544F6Oij%|MrYm z`z$H~HA4`k;8?cL#(E^B@x&1b6fV+wyk72L1P7axEQ-4zpIPKkPOQ@gHtVC)k%QNp z8{E#VyQUU7lGV!wjz)+22dY@)9xSj?HC2BQM#$O@9ur6Hk|fnCtX#@59Qo#Kpbxi^@8FSEbmQn@T2;Z0vDI99m+u?^*a^}SWM914V{dZ~1xZE&p* z9yfqPI3H2Ioo__nncs)O@x&IWNTp-$C$=5aYGYnb`&=0!@*cKy2k!Y+de(p{J4H?l zrFU|%^aYWOyU>jjOpZ>RxO+&nzx3Jedx<;xIz>7IJcD-CSSGpS+|FoxkkqT-DD4PO zAXt+njBT@QO=RL8twDm5W=;uAm}ITv6ij5DiLUxO-fyBQ@NP)65=kPhC5hRm(S3nPvnaaNBKTlPF5o~>R`|B0mWr@j(N%?r=TJE?fL85u_md8Y^- zQ(EMnTPzuHfxAv+8FhLR9c&c;kJh-M{tFHUq1Nko1Jbd&ZXa+oHPt{TKSJSbQGqbM zd4h*H4=$2_L`^bh>GtzepftSxzhK6@Vd-DW6+&K#t~Dlz^fh;$`-1t zIi3wZ^>~3VPizhW7;@BB)h`Q=-sqLHCyW;Hgll}q(TijXIptWy(sbKqZ#4SnqqDBH zmL9C-??OM;3ng8fG;eY({rJtzL@G-*;5QqGJfX`Y&H^_LL}w z;C2I%u}pS)=-v@eU)yMnDwItpsh`}Ik+H{vq5LXFI~ZnEmrv6(EU&o_#zc+qnw$>4 ze`mU}WShzDSc(&?ak)6L9{3VWV*FR%blEqTtg@a1K;VQ@MtU(6(p@W#yZY~^rw&zq z`EZt2w6~U9p%gvQNy0nRc5uH)vjJ+9K`mZr$i1w1LvM)IsLxy6hGsx&ge(WOZ$}2I zH+fi+-*~AdvPe2}o4=;Pq)HP#d*W_JhCXewJ^D{V1gA;=9sob1M{YIh(>?XR?K_iW z(LViix@CC?ck`($#EIv@DEkI%{aB+4W%+Ol4TRR{z%YD^Tdoz-1}PGX@P@2zh!6i! zt08l66k*tLf(EfTg?fMTFgcj|U<&fegpuD8SJH*oi2A9Ei*lT1 z7e*nXuxO<;6Wbhc_xo{&;dl(1H&_IhIjPnuJ?09?PCPuOH#9+0^pp@t=a`C_&-91v zs-4juz6IVIqTJJkQT|~2G|{%tr<2h*vPmX24vNtVVDQUYeq`@dt61B_i6HB3u$Cc|uOrZ^7)J6v4yw zdl?t0=jygHBgohl+s?>vQtSK~-br%RI1CD$Ll^*l_YXxw&jr@!u{;H5;VIJ+jEE5@ zDmU5!XluI4YAiyxA{wIW-)ej+pj@~}F{NwqkJQC#lKf^>>OdeLlvsIx2RZQS*nbi% zfvpz{)ET-;sAzCv-WP*Z+c>9g3TO)@bkrV;$=usJ_;70@jA{Rvv%OmPug1P9=tp6G zwYIshE&EZ?Tk2?fhr@dEGYLuH;v|h!%7_B!boK$tSs1?wYpn2Qx?5M(B&hW2&~af_ zHkxL_stw5LlxhLSfSx{GOV@GEu5p@|_98)cMZ`sa1xEnEQVtvc&kJEX7xm>%8tTL} zOU>4}QEl0H;?{w1na@~H-T;h6Ju?C@{-stfMYnF*cc$VhlEvXGB}(dT2wmg)(BaPTnKMf8w`4NX5rBfmy80`-V6y#HZ@D}fF;ghLj->q$*heL-esA1}5HB+<>C9(9zhC6VPu zWfuK1t5I7pzmkuWp@eMbxD-RB!xxb<>$HN1+4@F2cTMK%^yYi9KM!Tk0}BAfLVp0V z=SYCb2Vb2DmU{WLd^)IAk6!sXKFLpZEZOBRC3saZW#xHOQmi^KjMl9p|67yz1Jkvc zNIr4KN(|vj7xK86MkX}Ihk!YtCpZZCu)(g%8OPN`s~cHfGh=$OrQ&e;j{Z@RW?>Go zGB=>3WAocuff<$R0go$02k_Ot8B^`u>vWbwC<-F}k-7d5=P&_#t%Zl2*^u*_X9Dj- zAQy6jMRXKBLf8XlwSO%T+S>(GaRa)4Pgu2j>&IiRt>^6xT970Y8EVv#tK~|NfIhUM zNLa`WZ(94|3Cj>sN^E?>ZXS)TzD52Ao5#@(_tEH4tJF5wH4%1Y4|x)OGm+J}FH+|? zktCErr;hFkgAH*DOOTW`reO{pjMPL-FD+n!XC;|RR+BbsUVUy!z1LNbBSbVbOOcuW zQXyv8bhtOp9s%@0l|GgQvl3Rq?2J@4cP0F_c1Vug*G}gWKozGY4Y(ts3iHVtSL^Is z(M2FV@`va=l-^=*tNM`Yt>F2R2kn`uHB-CWt#N}JM~tBwhni?2Ie>h~0V)LX=8K}` zV=~u@duCnDONZQBVPj`iP(xXaROS{F4!&x&h5s~LN&~JlVdw@WkV8l;8!;x|i5_>5 zC;36zhyLj8w&m$>?5=F>2d+DZcYQ?wfWQ>ApRhXR_o)pp`H!ui?|)*p?=~9(f_fyO z^vf@V$G-@=ry*xt3#0*nz`!Omq_3OkF1^hm+IpiCezkZVX2fmh7TLF8s55{L-$VSQ zh!Sd)+dRo!4qHuckWozi%(tR4dIm##=d|sB+-BewdgK=lxSe@D$6YFtr#qIbNJ}jC zsROk9+^Lz~qyudi%o5cdHBHSHP6h_6c;G0lpI_%w>A$DSfxrQzOzHwyn21qT!tPv& zeQkVY&ycS>zrX&t#hD!_h>0)Qs@XCKTHE+e3a*qFh^MwBn`XJQx=$-&o<9qrq{Nm8 z6AMS6s;3U$l6FN%d{fdM$sR}P{n##6s0QLpG8ne%QcBheBlhF`PDYR}VgrCY4|R6S z#Q1%WQtCGh3iZL>eFYcALlY1P3x>7XV2al$4Q8s`Ks7pPHZ}suX=q<%CF%LX!-1#q zANDlpff0)nCW@H3rzQA<3HPM%{=Al)*bP3@96u~7vsaz;<-RY*(m{S=2G$M^N-5o6 z3pC9Cs^nfo-l#py;tLAEc(?iVIW-GOvfLw{9UdLsT;C$&$@V?L>jqKNa?r}@C{JPI z;}@d_11@44YfEePqo|?4^L=GX)#P91GG4dcy7IlH4qUgbYNg0BDxYSq_aw&s5)=&?#|6r-e>l3TUv3J zJ_shU1BuM|yU%w67aKVz3EkJ4mb8IJ|1N)R(L#H+Ubao{#0Du-slu^L8)<77)nCD1 zJ7*5-{zO$&l_>&|KSkMD+VN{^scUs?mEw$S_o$8T**kT3pFYl$!lWv;CeO)M&02X4 znV$t1qU@z+kZ}dtGVMqIaw-1My||Zmz@9zMB>#!9KWwut{B61g+ncy89i_}nhgBCS zcV_(8e)8n^zqUl_Ph{_*VOeAvdhI9U!zD7GJKj1lDV=+U0P7$wsC5TZ{F%ce??S88 zue6Emv)r>2i?fJn6@)z0)CKXTDJw582_%L6yU%THK4!xO@eDPZOQsy@YG&URYs5EM z?-EC(;*^y^H8nNRJKD@|&~NZ1$tz4a;iGy^T4kCHSG@Iyi!})U^zBI9aU&Z*C z-BM6i9)}l)Tj%7E;03z7BEo)g)$O2p$^Ft~3XNtF26+CQ!m8a_qV&|&b^mVe2H87L z1VPKZdtO$IZrMkE>S2T9PPm5Ga8W)iZKVkO1vCp7r+UBN=rmJE=Q-XvObF>Ci#s?z zW~3EC_%8Ls)HbGhd17wLmyL~@{wDqg?z)SEfX*HIb}%UWb7{K5l9@obd%9-|tppC> z0p4G3Z|vclPi}4n^i{(jQ0|544iW*n2K-lQ6*hbnbV5utqZ+`$X4IHGIspb^rb%a2 zOa>O_00gbJf_zH`jkf3~H~@+K^Mtjl@_Vx~0wpE=@3psyg~_h~Y2Jqf>jXo&$XvJ= z@0XnR@1H`^VB0Mpo|ez?^_|Gr9Vc@hEeDg|eU9r|Z+<+rr1C0wF;LQTb>N3qv4O@u zy!UlD_fJWDZN}j1Y-$>sA5nTqDc;j0^Ta1dhnEo%5rN7SpEJ}!+$aNfrAEUggaStt zUDAjZnapBxU~;p9F3eBDj^(hEo;h{PL+yjMSkuX!quCbNnPM;OVxwSkTnu3;>X3oC zFG>&enz}liy_n(Xc_?tKHF%SjZ9`G%LkQ@O+TqYkxnm1R9F)bLqrytxHBgleCrvU? zj+T#d8stB<6sar0Kc*)bCrAw2OCOTIUDNA(pt;+neYI;uC?#Y7;SehRG7=`I zG^?7cR0qa>2F)+Z75P%4gvA~l9zk1WQD(U+^$$u&d^gsSvg9wjxV}b1LHX_GMo5q_ zi~{!vH}e~gb6*Z2Pq_wO0^xUZ;-q44+uaM1lEyUD{8}0`lD?=CtEz;D0Uxn|Ti9y5 z59_r&H={uVL_HKvY?71owa5@22@3#X0pQA;ek&kGQzNqTyByHK zGiBmC#qNH81E2nM54twe;puw3le;i=N|AFW9d}>34f-RbUexk}68p)}eD=C_4DCt79 zGCO1&2tR(toL5$sCeqOiDk4Pz=|u1mxn_99)qWJF{=$+P>=&~z01lZV84Qieyoe}i zD=0DfKm_@u-pZYd}sqXO-vf05|W-gyaj! zoA28O-MzU_mL zNLwq*QhUouwQ6#O-y^1=q)n8Qg%)QWEg7wbc-o{ZQ{D( zPQR{NMy=O;cMsoJH2+iy!WkN55po}{?Gni9J-JQCkjbYD(zLbJbL=QGz6%7b$kDau z^YhB<5|9v*(Bce-eeXmr?xb-&!4E@<2n}umOuoN8*XS`N4#ayEuRJ}m4mQQaNzNou zo;~D(t!yZn_FDn#mmNqKP9ag9?OPFs5%M< zR6SzI$sYkqqN|{Wy!u|__WrX@`f-@1E%L^0e(bl$nsvY5`;7KpeYser7hw31DQy@C zR-&Y$+MS)9g@4*xZ2};~zi2h-0ZLkF^w~6*UF# zFj5-#EY2nI_=$>&HYdll1veRBS1=1;Ic`1E2PJk;a!xm2r)S!iYu3H=b9d_2ZH4T= zHSg7R`aVt;{vB^UJxbSjZ*40-8jM+cJ$dwNe_f%Ax|KhFb$eR%YujBUTC=jV3QOm9 zS06pXDI2h|ZYUa>pvQ16_IumKQ_@jG;5E@hfct}NxIed=qsR4WW}1aNyW}&6{iEH8 zhS3%Oy~Ukh2bJ~t7cumm6^`S9&sZY-x7|N8p6sFV_^5&cUIZhX=!>a=G|Ns`u>tXA z|Csl)U@4$%yg0+VgY@J-bvU0tKi}%K{#oHNcdw<{!SS)Fcx=>7+Tt~v?TwuOHHIIF!;Zcq)Fn^PACm2N=Xmz4e|2uy z%d-RSx%houkNSdP@$KzscbmV)pk>Q-xz9Zl|ncvN>%gz|3?AgK>y#HIbkjkrQO6GY_diOKU=I*$5 zd{N_XXV)9}o%>IsP05O!?6|DiYRcR4A#b7nr(XP*8cIAuRuaG}kNv!LiC*%$SWY^@YE{>)6@&c#bc9mVZwf zStC{XwkJ^rw*so~^ye}{5=%VNMaR_``OK-K? zKctYt>bAkid-#60DN@O=W^4Kb3dD6c`S&92TO)t!)?44B1Vvw$pZ;Xo9orlz9i1J9+BMlIBGH9 z*h8@Qr(wkH{$21H9g7UL`%0+}zi)KB)fZ+iGDM*cV{PT)?x!ak?q8zi#Uql2-pb$z z^bggql0O{xS6}a^{p>+zVqv@4S&fw}{U2>N2m3#~mSAsI6aL7nH2iJk4W<1ot-&)l z<4+2amKHYgFlcD3_MLtW+^gA`DMqNP&)x4XkRv z!7Z*z{q$GQnGx^+KyNRE^_KG8>7m@4wii8JY_N^7m}?_AWoBk>VP3a+{&0=T0g0xr za22K%4Q#)<3#3fGURdlc?We9s9G$i9$Bmx%cZX-oC;$zd`Z+skR}>deR;e9tX~8=+uV-uf)OMoS>2)7bhP&!E z@8d2+NWcge!iY5cA!&j5ZauvEsVqnYdhLny3;^Rk-8LW(ku`86F zS;#PJ&-MFbTsi>A=3A3p3hGSW^opmVIhm6()6tuvdc_&IChWk2+Sx7@NX zmM}Y&qgY{OV_ChV7Qwv8WL~nxQZo`rM+^AzR`s&7va))OzHhrcZ-{d)mLK($C#m8^n9`F3@Q#NU_k%GYC^Gltp+Ms|1nSb5pj32H_e|d} zUnvQ%qm{)c4gkG1)$Lnt1~nmpRZziG;U)y+8x)iKxn)cS3|N2@|DvvfVvNuQ=w_q4 z?{`RA(Qmcs@OY9rNl7UmofPeT2dLkqGMm2qA5^P%=e)#6mgD{Qhh{%ckE`GOZuk?C z&)3OH;A4Tzw!v6J!41IHg~6icUS?p$KQs&iW1$7l*Q zP@nhUrgXw&iZwT$4=b#w3VN*k?yvUgl4S-Fz;~NxU>%)#58~B!WGLj7Q{@vp zTx3lvWS}b)4&g}@`f#xQ>W7=4lZ0^5^#m|o$bgB~VS~yd0E5BV|G4?`f9+NT76d zH?8mtFE8A=g!FnR)2g&c`k&G0z=ip|qh!q&0pBIYwvtO@0o1X#7;)T;FcSxQIm#@6SRt1{1JM@u=~sNvD<7TR*kfIRsL11{f3E-2GL$Uv zaI#kTepkZt6%qz6z8G0Y@-DspB0x(-L`>X03C4&al`gAw`gx>L51aT0PyKDE9+ z&SDIj@|*SGjWjo9ZK3w3Xz*z0ersOGFji;fQ*(iFKO6s&GV*0g5R)O3fzUy&Tvr&t zEa3gz#~KPRjhgi5d zdYy*`;$|ocUpr(lUsPCC(7k%@Anea1aYU#@1e>rOqCUvs3*ZN#eE@cyWCwwlaMLN2=LoMOw#=bh+a9S%E@9WO|^e90ojmr@< zG`Y5*ITHl>9Ssb~80r|cGRmnl-79R|yW0bZB;U00iP?Gy`}RhL>@KCKyuba1;0%e} zuKJ_(cjRJLJ6j-U(%5ZJtNW&8BKOb1q2pEbWEY%Vxm*EbDpN297)pQ}fcy?VFr5)& zsC6fbWjZ;mH4F=}I|%tI4RD*X)rTRF`=557@`51S#gjR26_ef# z_T7!V@9&*>`Uj*Ym2;EGRNBekEBv&CDNH9Vd!gAfJ9AW8*pSfB0i(9vB)qM}Esn6z zk%-5%oR+z?gwJvYI=n%q(eZl zqMmlb-PK9%>(TV!#(JRnfv@KTbf$^htBvsFr z+V=(r1~Q(Jl4$|Y4^|r>6rwhP?;$_E-zSKcjh*d#KeGbM`s?x{QJpRav&AWWt;8U@ zdr55O>E6i!ipHRFa8!xw;nC5@`sJ#Kh?tg=;#O|;jg0{3?t<2@Hg0r(x)fJlTKDfr zFJM!f$wzMYB0r>k+Yfm(;&6J#>o)1Wvan*f&UqepbNa{q?{%+!FsJ3Hf*7i=`Qv%& zdQV3>Oqw41{E#KYY+STwpl{%>TEH|VQ3WFvBnDjq;dHGDVW2b?p4`c)Ms1-l zB=T|#NZ#{nJ$(6v3^YoDL&kXj`6)u-qyav@%JZJ3-%dlQ=H}uSz29yGKD;G;8IhMikT;KM+ccl%F)9?Xt@D|dOq4}+CFj@F)K*pN z{uBzwZXU|N^F49li*OG3H;1MBG1{VG?%lc;nDz0nkQL&6*eMbIF6l$$mQu!v)W_uZ zdBTgXMMc7pf4lBgf-*dU9?jZrenHos!rL9YPI6_GcLTai?_ex6;Bg>_oEVNE+u>uI zwh2oAGQEdV3xLz3aq`vBb|b(6a%&;sN#}R@^rDsf%KNfE3&`GR^6D?Z zkq&lw$|9`C@mV56L_+$+I)Ks^!B@^y8${?!IJS*UCmSOBg3uFhq`??oC8qPs-y<3+QdpEW7o!Jf)b-?kwB zHXa+dA-7LEvja@GDK8nk0c}sY9xun%M_6hDW}`LGv+Q)0_d4@(P_G;%2zCdz@ZA4( zI$MXS#gq~cy_7*EQMPVUuw9@cW?CX*tk0W^BgB)2*)F@NFX-eX1&H-)Fs+mpeG&8)M z0q2$kCV6Ott%tf#n=@czkDCgaN=7^N-@iU4a0w8aV}FGk3DyOavq~fnP0Z!6@8ym` z|Il}pJ$e~`%*-{o>_1f~QPOic`-^8b7@O_0`L8>JRdns~cp=x*ao5+C>Ht5JTB1$( z$NbWf&5;@K1C=QQgB`N+nNVXZ#Jn>nRigE!TM*(k?@<}>;Id$K0)A#V=}q5CP9}f8 zS&1)+%got;6`sR4oe=iIm5x;o!Hd?3Dog!iGYX{3@p%pPapC2>SZ-d7##e67YQH=; zYu{wW5QcYS$+ihN{DnXeSo>jLa`-B!6!N+_dhh>R=jxf2ctelFbJ*!73O!}l9G<3F?v63= z<}_NRtIE#7+iP`lwb}l~WpVKZ((c5{?~n2206CvL1c$QlvsAxwI{V&!*;3hUNm%NB zZr9sh=ty=7yu0(^l4?J!6S&!AIcgO6dO4nYz=CGXV>>hA0`$8%$G0%U8IU1rL%W=y zyGV;5m;9ZS!PIt<^P=l7!+5hHqt`0+6bcpoacDjiRf!Mg^Iy=s>L|a->n{s_h~!Z> zQtO4h0aWTVWK?jbr#7sNefEDflRsaC5$AMRJ_`;!C@avY=LUlAMv}uZcFAT>+K(~( z{jBi=yV$n=?mk{lB~0(FAj>K$e|YDSYR*|OpLBg3j_!OS;$jP=$nr}nv_)lv4`wd9 zo}aqdVBX`y46}B{U#z@|d2v6d`u#ZC=5J=zcYT6Q6iv2XkLm(NudrWVB10F)vNK)QD+D3Vv!odK zZ=HWOqg6x$Pr_M$*fT8~sUr`GeTSR0zt|zdl+u!lRnFyiQPb3Xq%mcmbuE!?KdXP( z@FHaR8SO4_lu8tMmVpNa@^GIeK|9}$a#=9|bw9S&QEJ|f#}3eTaOmKOd}A)V2QbD+ z&q&1vBCLugHeCfl&s&VWtOh><2r-FN$*@2B^!I(;DK&I^(}L{m(EUMBxd_J@RAH~* zpWrH`DP>nrRMb@0Fnpa_$1qw+T{NoiJRYQSNp!IRK>oPgtk!nE%sk5NU{B&MkXBA* zeTDh;IfcXRG-XA-8X##-K;2g%2F^zaUBl?;H(oM9NHZ>NCiZa(+K5JP?2lcP=H3_z8;I@2Py)1Ji9wKcZYBt_pF1+nz~gN z>pdrP(32w_E)EZuApZB0wWlL1&8(K%igOj2K*;$%v16Mc*B5Gga9yV_Pr$R*{V)F) z5W{%wf1sWKOzQSEGyoL&d86yK4NhmsOaU}&7@zWXFpdlb)72S4DWNC{4vPw zbeXQG1d1*$&8@vnw?loe%uTk++b=rLMk;}TyFZ2u4-PzBzbt_RBv_;q4UNa?A#ixa zIG=k{7g9L}(5c)?@>(1x<2uQ6#~5XExIBWcr)9`p7Gz-{)E#X3(>WZ``TK(~`vG8W}+m+vC%4?+pryC-(>u$wMs5n{(}jDI^pQX* z06&@Z_uVhZIOcp)g5|MB!apV|DpQ5pcB4XdNCcb-`b^msGudNbA0u&6s~F5+w_Eb7 zOFm!XyaY$`oiY-QpnzWOZ|umS57AX6{z_qZ7%T=Jy%}~Fgehr!wM}&^Uf(D4PiN^+ z?$056syV>r$`)A-&5u+V1Lw<3Yo)U4Au$;Q+`JCQx69b+OId-Z?i*JcH0=iWi>bl? z-1)Bdoxy}Sz%_gzcDo^J0b!=daz|aUUZCrA#b|)ri&G$PSlB8L!SV8O7(>0`Ib%(E zMgHE_*4PpDed?;y_xJA``zYe+cs>y7dsFJ<;1_tFqz4qaFAYDBK#xpq@Mw0K_(7gX za-X{aPVhXmmerEFyRYSSY(3kMaqQZEp6~K5X{nHGzX!?8lPb+KAJdFFiTG^p=1>91 z_=mtbv0vnLKPO#J6=INYlrJB&UsvF59@KtlHAJ88W;b+^anM3)Xgo4`J|w){$+=h! zk_diNCKbH9&aHi24gNpB6I9W6()bPtczT)VtX{rL+bEE59*;S3)O1!>faDv_r%Qq7&(`3L zF?`3iH5poR;MyzuiIZ{b5cckV1BG1{j?Tz$M7evV{}lpH|sdonHn>rLJZ7na2;=~+H!Akr5e zvd7!Lj}T>2WbBc~z~LpKlO!8PYXWCySwz3v^TEq)u<=jMSgFn0OW4*iAR}aHYH8}O zUxv7uNmt0}m8$vGMSA_}-eg^E`kjqWFqxe31(uAy(JW3F@ST{vYeRMw#pPZe8|tnv zBiO=hnVH9#rxsQ|?a;;q(@Swp74fEyv1Z%TWij!it4nLQxecD@VykcWBqt@O^6(yA z|A4w)CIgzz`KNSO5Ale~QOS}sm||lh$=oO}%v~gm{KElae~Ow4c)Hp^&wNhN)SPxeWPr`loQT3Q3i#x=Rm)D4`*vpgPzscyjR^MeTx&#jBamLdVg@m1bOR z)TE?BC7{!XDTQyA6Y}jM{M>u@Eg@-hdN`J&H;l^SDxMgp>#dWLRDX6suF_iv2s>tU z&VyWp#9P4iE-}az3>#5w9uXdf8C}e;h)Y>|ehnD%E-2yYvKwNJZYv_>c5v|D>L@Y# z9{JC-7G0d_uTlnq8v}l?8wdQ?AD-w`M4tLqH1Vz`a2PTfuNRL|WPN!?%eq{a&#mtWZaEshu;~i6FXAf)|a5@ELoz~{H))A7mK42AuHNlQs zVRK>^%*t<;u8Yn$9^I0fM$$jz_d|gn|MNZ%MQmOBvUFO$7ESYddJw)9ag;B~uwZ0} znAzH|l$AqL94w|*Hei&{loFD%V15~kn`a~>E|-Ll4WU|LpTJN#jE_7&Kh7xHP2mu~ z)!_{48yKv%c{+iiTJI5ax6IGU=6@B_6GR;U#;*-lsXl&^?N|4&uW4=Us4`vLIP(oO zp`IDJE;#O)?JvzFjv`ic95b&833~DGBSeqgL~|95RB?`vukGVCJY~)y`HZ#3{Fxp5 z9bIQN)6prFWMFS>Ci=~-<>759J+q{?s$MKwSgM~oOU9mmtSXfjxKwnwG*vmMOyuiv z95RjdQ9ckU){znf*HmAa>@eNYC3RK5wK=t!jfz#;pk_ zwHp?vAtNKUd1?mhM(bIklopEEOj@j=6E(_15SC2sCkwM3Gixj5{aFm2jQ*IigLHi8 zh_YhFq12@R;nFWBKp@r0uUx=O>lYUj(|=A2=4&!p4``V=Pdw51K?}%zEbwO`TIHjf zU$2PiRC1|DI|P!w4^;v~q;!}<`s;yWW;((;^8MBv*x`N%_G@Xgi6Y(wlNeyfH;Dyu zQ4*JT={g%10U^7+x5vqWfwa>br0qnTHC>3xA#_dw8{|E^DEfAIlk5)iIbVuM8&X5N z3*9`^Kv%3n46?}Alwdz;GmvB&4KidvXl-VtdQkgATJ>wR2_qW$N`+MLGi3pl4)+2# zw#nR*zdN*!Toei(&}kQl_0jrf_@&x_UdKxgTO+B5YR7CqQZmG-(|MRio;=j>f+iXM zkEJT6hMZAx(_d-HEJ3t+G^z2nrf0KKWpi@qu2*YxJoR+++ToJ8iDdOa zZ_L}FG1FAEtA{&eOy6Nt(C`K_PI|0hjFEA+(b>GPPg!{ln>H_31akf(oYI(EZFku} zgM3x$5Sj2&YC1Zm=*ak-cNjwPHqjR=bbz?0M}mUg8&^RwlGdnRxyZ@RY9O9?kXnjX z0%LVNk_QKCtW`>8bLdwg8v{R9faeR*!0KST_d$)(j1}|(-n)uH-@QLY!35+(2FDmA zKH$|oyp40&d;mq?N;F}E{%vjeM0_)k56)1CZahVS`e}1%bH}aFDgm5co;$0WMFMuG z2E&Q0jcR?tExy&iWD7Bj-%hzree7XYv+$eyXa>e8pghKm!0HepBQ(`~K4AxeX>GxO z2K&92PQsl@kjBME-BugKEiOZXYAt40jeqiyDmH!Ok zBCM&a|7Fc3`Qs0&yE}2)YmU_;Y{&Rqdjb2y<0c=Q6K&A?h#lI>(C~ z-T_Ir*K?7;#zyynXzJ~t$B>q^e`2{UWH_r@HPst!HwWu<`gdWvl(TKecEr(oiB%bA z>`|!MVd!eWA$#)}v)jh!!YL$*sSof$DtzBL)8&h=Yi`O>Zc}}thl_+MY)rRNwM=8| z7dmXBain82boJD}BB3Ku_ADS2aS#$j?r-hUSeQ{3MmQB@OgA5;s}`7qAcO_Kr`*Eq z{hCsOLt?&A=Axvh7ggelVPVT0Qw11ctOhJOZglR5b;ovf^6aL9*KoHFb`T_GgYkD@ zMbDqfnjn9&8Sw&5ggOeMbTZ{eM zcx2;{jS;m=NoO~O8EuKu}xw{^gpzA`6L?zqVImzBw zSxMK?(9*!o(^PyHzHy8eap17;ln>ogNd3H^4=fIJSC!4HE2$7+;9`?W?N7;(XN(yQ&IMV{tt;|}` zFWT+EG)_+*MWXCa*xSB&{Wus0&1*kDWV??4ZXrBIQWzJe?Y%!k@XT8A8p&`zo?+dNIpS5y zDP1I1x0=j!Im5va30QssfH2Pbc7N#XujifEd}<9r)G&o%E*m`{vLzMvvN!OySU0#3 zzJv_21-&B=Uw%7ZcD}YL;2U}Nj?fjDnw9L5ihR=Q3m~tIqNp?jyg}9xAgi;}8LU@o z0|Rse1BRf>zoUh(J3*06rjFK5m~u26=UfdkEo%xBN`la zFf#=Wv^2CfmS)PT%gY(oy96)(9pO9`qs5LhhuKPi6zS~F(2qYq!9AsA2xRV7`|4+w z*OR~u!FdmJxpxrW1)_7pLe>dhBc2BMpl~epkHMT3H>y70-07 z1CDr8ZM7r&#&-8;V70ypJ&wNR*R-Zqwkax9dJ+f{h>FrEjA@BAV3l-MXTKL|-(gaI z?yV`$n85xRrPpeXpQBaxiALKYfIzUna~2Tn6b2BLhqeEJnl^%Y#iF*v~l8 zH#RohEsT}MUiv|O6Uo@TK2^7(>Phpuq z)9S^ntZ6gKL>mb8^Xpf|PFzSw1>KL6CpRV`k!kbyy@;RQ)t7us$IQVRB4HRU0 zcUy5-&(5dArDghMaJo6@L@2bi)U?GL63EIb%VCcVTHS|XE_D*{0{n&3vx-%<)ReLY zuo~E@9~f_vyj_xOLDgulu&=FSex^~TjEog4$|S;f3U&r|j=+4Jj=ha?=C;(Nru_xZ z3iJ6+1#Mny7lt4YL{TV5=7t!d4H zsV*sZMO?|J0cRK+oekDM3iSw45zDrIJ`Af4reF(t&ziPb>#gU$uK!2Y>uK+@1b&bu-C3H_wajch%*P+e}*F z_!A3N+KnOtmf^mEM@#G^UQ$Etkt8{c9+%@HiW4pB-4_D=M*AH+G^E;Pp~IZR;W04h zjg`M8zXEEk>-?xF`ELrzi0}~M#q%sYrBeHwzlJau50AL4Gn>1whq#mt4LNwH+Ny&zjVUEW2qW!E48BAD3EkD$EfNR&|6mL-jgy zUiH*Bd36pr-%!`&02vho(vJw&=-)p#fX6dY>_%)`nqpK5FDyUn~aoH(6`+|NXr32#Ti?v3hsNR?9SG;1+ebd$8JT< z@3=csaAryhS}&gMptr{hfLkqG!a5gpen=aC_>4 zgjW6_=|}378yd*bo(T*+jw280w#ggndS;wiUwr>2(c9t|CJU9N9bk`KT1} z)$Z%GVaLyVoN4Wpl#Z+URbt-2=d(ep03o-C7lXl{lSOv4O6|KdggUaFyT-*BY75S$;f3mBSn18 z1+AcA^RVlT>!$tvRQ+xELZT!rX}ZeeJagwm6I9FqGWtk8b@pUdHuIy;Lp%z+tiX_Q!E?tFYUZtCGX;Ygkq% z1%J7~WPypv$Qe0qv|Q+G_|ee3*nG6Azq%S*jh$H5vATAq@JfRuE-oL&cb$3ba8~!# zOga=RzgQ8Od_0s%@KiWk3JBEpr~E8OtQpBZtHotxIWm_vlqVZjvl7h^h3b2MD$?-wvQC~Q zqIRp)n;&MYf55mwLQb5E%Q-#>I48#~L$$YYsQ$`0MP-iab7~rv5Ney)Wgze664C1tt5M>@TGox>ZdmQ{md6Y}G?8p-*Q>0ourPR{ zf>OgX-gWFyv$$)l>*13mB|9BkOi3JzX;k7gHrtueb6Z75MXG7ZPk!%h^HvTvXG51? zpCf2ty2Ztr@Nl_g!uVD_@QU}=rOk9~&LM^B-_t7A!Dpi8_FRt1$N4th>%fju)kpHB z=d(Cwj!+dXQ~B*|HJ6g#g3!zGq3h>s1pUlAG+|*Qj`Fce*GZ6YF7$D}N#!2uM-Kp$ ziApK77Aeas={LBFORJVZt&J2a<-i-MrOXV1ZDtoW$$cS9G>?MFO1fQbm|OW+D8@E6 zWot^Fe(IBim&WQuN`lEbRBCt9~-si;ZaH}OJ9Fi55vN7k zu6{r{B0fITz2px)tpJYz1q+3;tu^OkV{>!3kM}TvQ>%)UmY!DSn8D{6)zy|&)_;>< zQX+TW&9ZR=bp5fEX8tfiuZ%S6a;6dv63y{z2Kkp7F*ap(30Pf7vn8`Y-Z^fqV}q3y z^9^HzSZOmuJGW5~Sv`G#rn-In+^P(hiRs90#NpxLKQSm_)PrLo>&JEDblhAl0yjw#x&#QwUnab;$(+e>6gqnGH6m_mEgIp zMxr9W;6397Xx*gHg|H$&jCX9cK}q<%s{DpWM#%xL%h+u0&GpEvq9y%PFyjv6eFu1> z^LTHPB}pBI0W~q zXin}+s;t-%PM=m6JWKveQk{yO&C!ZGQ>?K-V&Lge`3^kV6CJX=T?H{pZx8G@pSE!; zn4sP1=Y_baUW6N4yG&x&u$3a@BJK%+sRF)9l5K`51e2J9+wz{|e7HEVL6K8sa z;^C#Nq?VM7Xra{lW!?MpX2fP)jErUE=Qoilld*1~LjK|60~&M z@cu|%-p_>9i>^15bfBb~zPgssSN|T83@=-ry63e*nH9+0*vTj|N~3;;56qq_JfbZv zqHALB9C=wSMZD*I@F?;j>XI$$2mkzLSiDbF>o?B-%-17SVsdqy+ius*Wa1C-a#=)Q zho4y?SI;$QcM6uQYUliQm2C}W?g~l@X8h!e??Z@3#Dr^2bK%P8R36YvemfmkktHuk zYe}1aw(P8XRcvi)DXL2BSk%xrOjYsB85)IN_Jg4>=S^=8u|JpIQz^v5$mzd)k{imx z1dseZo@D%?i94AldgDpT?8D;6e^Lys7Si+B9@;QMs1i1-a-)M(d%vsY5Q8pbkmC{< zVQ|IOZVD|=S3n1?X8d$e8Sq8o13_<)#G69&B*|uY4$zeapYuPzskoP|!JVQ`IJ=Mt zkHG6oRdsE0Gv7EhJ1vjedq`;m>3PM+K8pW)qrj?w!Qv~$&B~HmUF3NG_+0BmdR>9$ z^e^T!=CF6gIu>ARnvh^T^gVP(T+_d-?WPe3?%2t!#W??bo)DGCdEtKUf+^`w(Uiyb z-gdC=-;+4V`|5@K9}DFKToQG5P3LFK(sx&#IA)P3kD5NtjK-|Mir~bDp!ZRs!mvzp zT1zL0R^Or`zF%-njrjP#*}Cw5uPNgHfAarx1|}$=7+%EVP$92XjQ6&fALOKzC2PKY G5BeYS`sdC7 literal 0 HcmV?d00001 diff --git a/frontend/apps/artcraft-website/public/images/try-download.png b/frontend/apps/artcraft-website/public/images/try-download.png new file mode 100644 index 0000000000000000000000000000000000000000..9130f225c40cd772fdacea6be255f058be08e2af GIT binary patch literal 28642 zcmeEt1ykKz)Gida;#S|4#nNwOOfL4b}sL|bAQG6%_Nga zCdusVy>|9mk3=XdN}(WrLxg~UK#`FaSA~FpZ2sIO;9)#-SrFC2&AaJPu z+aYCCDX%^+Lb|9*i9*y)6CQt_KwF3?h(JIz#38*I!$3edxXXx(sCz)3=fL?896XQY zB{7aQn(1wCq*?%NEfQp~Sm7Chx><^vqeYMMzA)J#FflO^Q8p_hhNRbzM?)b5$eYLK ztY*Ywj%aqZQt5%HY&OB$ok_llEoY1)emy?XO06ZMmzTNMf~XLIr11Z{{g3Mb{kd>R z5j1F#&@WDydx1|9SX|H|X#3-oo&e`nxR6Ufj6^()ub+W2nlBC=t|SStkjIFUP_fgn zV+vfdtRRCAL?&0BeG|sPieJ|@au4;Fx$d=_(<&Lhs=Ia(M}uyk{3Cn@XWBGkJ~BiT zdh^5TrZ>4tO?5~AeSFwcD8~imcK-jq-5dsHim#f3)AJ-4y~JX=`Sx^mhSAN;`eEC^ zn}LrP1@hNtbm{|@XS)V;P015zkIs(g?cR7_M^B|R63y%j?}H zdRT=*(%c+|5>^`nL+t2Jef(khA6gwz)yb#7P(vL5?;+-bz7#y=(UcoUo%(8D`RQ^# zHPu8(;97?;IZD3Y^(~Fi#fhy=me9Y>5W8>x=H%+?Dy!si)5%^Abjyf^qr@0n-Pe(lEys^yL7J z9>sh!MpYS_mQ?y1w1F#)@1@1tXdP)hEMOLJoD>Yu1a^McoQN}C4uy1$S z;+HsnF>*{SsvLq^NCfhWqNkpoUP;XcjtGqM@^@1$HxE}2;4f@>jCMvj>ZCBUX!(Xp za#2$|b`AeS?Xl}gmI^JZV#+MunBnlNax`A=v!gjCyWwd2Bn~nj7OMP-`7wB0rUEZvrL(IPzf12uq!gyTR9Xsxt%d4s;i1YAh z(xlB2EEH3Gs6ml6%pPdE-)mDb(HZGn2O~xlloe28kh5V^{z zsb*wkp%I+UiPv=a>CsYTv4Y_KwQsVr5u~jLy!-mR8VE zute}dEWQw{`I?K+D?d3ee|1Gq#en76>c;9Utx#95WzEvMZ*gPS_vCrChkTnr-7jCh z2veg-&mGgpRrG6sYAb6Sms2$n?|wpH@j>IK=I0~8XW(FTISniito+E#vuIs2hx`jM zT-+d*&Q6G-hC#|tN$9tD5n8R1QP_3`&8@EeHuW@jyak(80QH>&>uxwF_{(s(RwyIG z8W#RHA{HtabpTLa)K%T3sOQ3Rw?Pb;Rr72)hhKCpJrQwIvGj7BL_@v#aWwTPB_2wX zIaP|DRHhJ}1|y4Ewl5#SoYl#vr<-}Ix2~6|gq=s+Ui)+F)z0qRLMe}S1%@s#a9oZ- zG$<&jQdDES!a1aH8_*<=qDgNWBpTSCEGrQ@XW1++ApyGp)XQ%u+9Jj&Nt7Ba=he+x z?+g;%&rm?AK@kyQm9vsr%dLz&Njj!rv#;UT+8S^3x*w1Kqc6v0nx%6*+rVS`?XJcS z@~}2mIcrE?OKZiabm0pJ{%)np^&T4=Z3BDz#ynGOR8%P{33tPqB}*njR`j_+3zLE} zjKMF`(Rf%Gh2N{u4Lk>pH<<~0Qs0wd#!1D|5s9`W>t$@20e6=5Y%I+#<|&Ss0*}I0 z5*475+TC!wW?nc&Q7(O6LY#Dps>Ts>JUU7N4UlXX(p&K~NsWq68sqlxCj%dfmb^fP4H97aqoYGWdz zW7xiJ;BtZ3b!<7SD5*F~#J;B~FwzMsP*Dy|slYP)3zjPX)zF{cQ#;1%zpZat)pOqr zyaf$-1BrFLf6iQ+PW{VtXUPj_xZeFn>J5!sV;Mi60 z_ap>W3^fta2rCI;W^*V8CIDf=9}0rTlFo!RF|!JXavKyxRlL9hS?pB_)&y-cgk;!A zd@TSxRUzIGPDHdTUo)shSk)4d`I^&`t7R_bK1JQj8P+>wKq5?dvW-NeQhD9vnDe8} zcc$THejH`$UO^9J6Qv}o!{8($yH`3~LSs%%6(&__a<8Dk6g{D?=~w!~y(d_^fO|Zr z5J4&i(LC#gU{)OxUJswb$i~A^*zWXWP;w|BIWbT|J|GxD;JwWTb#QQ~o{!Dcsf_zK zYoWT9GmD%NPjGb8Al@l`2Lta(C4LgMMYL=Vb&71UH;{0($#(!0SM|W|@|XbGc)d6B zZ~OM+ymu;x{ewEQk*0jfn$D$Jp==={j)+gT_wnKN(qXOZwr+QKcdMXpyum4=!HNfS zq{JcyuSJ{9fK7``ZPfNBR8b9)sCoh97!3CnZxY)c2cLOSy6l_IS~yJDr02EWXop=d$`5srHWROmWA_b^8pd( zDiPN*q?i+Ox*X;)HOTiC!UDY<;WC*e7* zbA^}poiN)?=sGCcg_MLbiX)q7ZKBg8q#)EcCLh8kFi4|#!=K^0xGlE3pb4++l6u- zF$4RTNtz!fRq%7j$og)s!WYNR?Ih{;N=rIAUUWEG%Em)?bugje@?*X^Ez-iMwS@%^IHsKTHGbbs6)e zm49!GdGEfq5RkF(KsM6Egjs5^zp81f4f_Pz2`@aLC4?jDc)WKF4#_!mDGvHnzdn*! z!go^1gWuOLcXqn`R_0n9@-``>QbnqHf&1ZSlOc0Xm0m>^O*M^O59Qb84UnHnw~25X z#Z36AKANIP7!;x#i`2|BlU~N%)z4h4I;U6X9KdDQY45ibVuL zJq?3@d91|eUqvHvpp_NQ@>ZMiU3*!oF&b!mNF}D8zljX1Z;kb=NJ|2B~?wBncp(W ze8n?!t_Ax+B%mY_J=gm#ou9`bVK+CF$xI%oMDiqjq)Eh>^O)jbT=5B>Rx61Cp2nFm zB0eCl?HllvF+!aGHX(0E$vj#*3_=FNHLHV+o)-~AU4|6!!3Jy%N=GQosrepq)7a!# z+l5hRT0|;c08yff5a7&{-XV{MMH$u)C6(U;A~wM=Ia*!C>*(H+4hacU6`wV8#;-CV zlBCE<$bh77%HVVZsyK&aoBTC)g*JT;q1SLVwSijd>ykR;2o4Dj%Hc_GRB;5|R2MY# z?21dO0_1-x|1=Y~G>aFfMED~p_l+I}+to#mO~bPmQBc=9n2$bxFkGmZi$m4}5IorMZ8WP<|iPnyAmD=(`fN=@Sg zsMEt#Eg?qN|9&j<|MhpTYh>-=aO~2U_e=pJ_<>uEb|lPWMv}C&z+sh+G>DZh!HmZN2`^l8%5EPr@ z=@Al=teP@`sJCmP<_6gE*}Ms!XqM1C85W~mB%NDdEv%=10dK!rnW+zs>bR7FfhS99 zcs9)g9*z#XFD?hzC03EzzAkD~u1#}oKbU_t;y(~DFNcx_Ave$BH9AZvK21cXJzRV^ zxtoR4Q(jeCsga3fj1DGc7Jv$HBxzzp;QVix-|i};e%`FoT|Ff!*`mXR_iVa1ANhMR z-G*NZDJJDg#St^*_&f$@k?&!t3`tEO_3|}dqgnQ4a{geti-k)Qbb3tW11sTU5&G4t zz)8gt6%d>f9J8zy(IrA^8&(!QynCR{v#OFYsiCaM=ONud@OYbur4fJ4<3`RgFktpN zlV;A4k0wZvPbo5Kllvp&e3jOm7Em2#9iy)I!kTU=ggW-6}Ka!Gi@`q6B>GP7G2tpsV4Lo2?pyhu7Z@;77@Wi^cn{RQOD zB2(1D0=NA#sq|}7q{_qqCqYdat*)k#PODOBvLyQ=2N7IWI%Vc!GgoUAK7-OYo^fgY zY&>^{xVjumXdx@5I1jJ;zO+jj6?3l2_)*)@pJb2w^6>il=-Hnsl@r^>DXaKg)KrO} ztaXVPJCtY+DKS-jjL{+I=NQPXs07H`F$%E~4swWUtW94EgWB`EpeVPy~E6XFp#VmO4Ub>gPJ$#I=#mCrIS zaU6bM;DSP9Tdu*w#xChPZVzz}A0%IG^c*?7xg4KKxOWHdK6u9Yef+seE?>l_^m9FW zB71UNq5*y8p+^ti4khW_==TGyS@}5;rdy7;_gCvAMliDCALu2sc9)?fK%bqvX}zjR z)(m$0@#u&`{7fs`v%0C-Y2w$|9e_o&*L22&2)0|x5sl{Wv`!)DiakHWsj|kAVTv% zTgcfjc4%K^CRN>Ctz9S2o|9;#hK2yZF)8Nev`|o--#`>e64e z#29Y#$&;W1*Gxhc)o5-z2|6@PlgC@E2}axmD%JtjojUX zy^eB@PgX!ihEr9tWdf>A7%Q3I3mJ)|Z2VPAZ*ZHiP^L)0$4C@ly3jQEq9`UFOi#`u zNC%i-jo1san9TLFh?mEaX9OkJt1p|6i!{;EVtI>c*3aTta)6lg67Z$@RjH7INQV!+ z3Jc3E7eY~Xl5=b7zM^R8=Vj)0ajTb@m?o1Sl1b&1Uf7pgt=3;`C>Yu6wjY}c8;iwH zz#?YCei71tp3cP_QB;}ylQ*PI=A2j{rGgdjkw_T$r+r5dH4{c_pzYdpcZXpo;P>y} zm^QuJ%-!ZjQLU*g-4ryK6rC;)Q>|rj(o;_l6D^k{?;Xu29eFd69p~GfV1Ads(XUh{ zR>EZ^O?x%&A9g;EdC$fx+w59iw>eRk65)Zhv{e{mL0^nNCSjsqYoU5JUWh(_k&O|! zSf;yfS)Cao955Jokd5vey919x#+baR+bwt|rY2+@Uy z>0rG9a9d1B$&oRtvgj0Fu|DabM6}`eHEWRW9`DBb%vg%ElU~yp1O{)s(=PS;`cz0_ z{H!>(fm)b+s7hfLrCl-VHUzCLS~qfh{49hN8>JUBCi@Oib2V;03dz8P=_=Y zX4I5iE?8Sd-ip2-=KsT7tAWkIYR`UqH9N1ZVzjKGqLQOO(Wag;lS{pmkR+v)lgVo; zi)1Rmm71n;w%yxpIh7mtko=h&r)3-eu+$P_-FtZ@Zr|(P;(H+Sxr>mp$BGh1n;evv zCY0>wu9iM|{sF#(d72{egQ21-`z^Wg^R&aRs>jD|ON>}?%`^f1^fZ(Q$sr9QALOZL^vojY@r-@m(B@*J|t6AwD zsjI}KvJvWH8m3hIkDCrhf0HcApH~b~xVD_3Y((&pVY!`>ix<;GxlCE2@r4knl`@bs zoOI4&nq4`XlJXg<7>=R5QP=R($cNxFEOjr~x!r2<7;%u;IoLS}fAHRq75Ij=Ca0bN zpRlYX>-QCI+GsV@8|BgS3+Z?nsd?!$5+k#!0R%E=*!UZ~lbTT)o0VL%(WAttM;De& z>(vJ0I0^tY2GblJ{Eb*w+Io>obr=@#`VUdbu;4O4iKOhoU-W{6g2d|TXv)KPh3N3F zsEDfLR3-`B!?V`RAokX5P9RV-Pr#|PrKWr0r={KU$}&fDgaqUb3=&6@npCL)Eic7akcC9vU;pz}-O5fdf>z9_$NP^eoaQqt$A9*&i&|I; z-R>r_fZb|6f9=leqW&L>xn01u7Oo%Q^SavsQH^=igOU4}!^8Z*nU%WL)>q}e0i{jw z=zHtVD?Ej8VrZ!sUS6u$X4KtF%;^fF|53_JiuJ)l@9S+{*;F1!Uiav~Q^7EB&okuY ztbEAEWe1Gvo>~E@CR7s|W{xG`y0GIxm)qlr^k_P_DT)1^v_v#HH3JcIME+OKD-guB z$Yr@ww{}-i(ctU8>pt{vvkNs6eeV}{c$6GrMmk-R?C@w{G3a~ICmP$VB_$q~fWD)x zW>9D2U?o(;byRZ5=|Z*G$id|6M(nsU9g0)kN%|$8n@NQ@51oXeMEuyrq2tiYP4}jG zH9ehq_$IP`FLv71Q zdMYk{)e-=*D92p`*A>Gud;#yiYMX_Hd5)HtC07lN`|adl zEH{7&z$B*ur!cT+?NX9!3q^xTB>vygi>GURl?;0?t2^s3_ zZ7nV7Yieq8k_Egb(^)8J!b0IzIN6(l?CLA9l%7Y!2U=LPi-E2M1e21$4N^a9{*yz?6NEqXu+xjsVilZ{gADsTRNM-QoMUT>+C+ z4+WF{;;P1fMB8p>!d>Br8`@8H3dQu~jzj*M{BOfE+dB7?{>1)(GT>f>vZpo#-G}Sd z9poHpr{Aw*wbHrhbQKtamF)MEy_N%&1{DMMtzM6lqw6B#=-7zjlW2|ycylZcYVT%R z7c*G9W6)|9y|wttw63s>xT;fFyBc_GC9nH-*l6d8k%_`(Flk2c#UEh|L4}}a>u&M~ z?gtS2PS*r$aF7gr|yb#*MvWp=EK&3bUVK^BR} zb>=C6srw*xNU3Wt|U|_T%OjVVHdl)@q z!0ooYpZB(h%8-`x^l%6HiBt!&R>RmW9z~xs>a!!^cbiYE%t*6?$UF74?P*nOK60eGl#;|OXT`^$Bh_V?8i)r zPZD$K!RD4%Tc36Vwz7((-{?d&K@$c>(%;fNK@|*ca43)3CHOce4tfl$V1v`{-F1sg zZ~J`(6a4%*NM)LI;d|4Ai(`4Xg-@wTD}jYTzAj7^@rzl8vOL*XUEYFQg<6m7C__5EzU%TZciR-)54*_WWd1Spb)5EvP>^BbZ_VY;E$K7P3h5tvSG-X6Z zdF8J;3MmnFWp?(A%-_~c!d>JEelP9ji^Ua5zaf{!bLnGqQCDXY=d%IL}I7WFH+~ks42EfA< zq3(yp)YfL9a*mVqjf>vn1|1g*{_0pQ8g))h(Pq|p;zIQZ=cW#LX%`#w#jvnIkN5H@h`9EUE!S0 zCgJ_(>qV`^jKNGP>Gs2EmIF6{cU5HCvwTnLwcEdKit~7y@a5c~Zo!P`d2PNvcDmc8 zi%A%fNa^EsZhiq&boTN?RA$aC9}VO&?^ z|9sAbaypUrcJre53%9I3!ni=~GRtQ{plD=I2=zTtGpD7dK7l8RxqreLP4wKqu^8Pd9{;}5` z1lE^=%@L}7C+hCGVbB~@T>rYTfg)5NG624aDRf-B*=hLx@aX1^ ztaqH08gzGCmFE*wJ=5)}KAtvI6-5NK;vn>1VmEk?e|I8wIcsq?vgU&Ac3zZcaF3Pa ztbieK9x!&d+;O>jzrKtD`XMLO=&SLP(2|U<-e^D2UU$#+VX~_>SwV%Am(KOLR|MXA zzUbjXWc^nX?c5b{rY9NW`De-7(DSq1VB^0;n7H-W++GC`FN6K@NS}AGzFeoE3bl5B zykd6pfruxB-ttp_5=QQSR4wyfAqDU^zy$K_^J)8U$C)13jFlT+Sz!Vak%~P z_;;fL2ezX<+f)Ew?pIche0-Kk9xCE!W)R2|ec$)iqgi%*z|RdvLf|Mk|LX}{LnZ+& z9Cwc$V~?k~Ffw*wn1d;cg3e9?>5y=}i#Fe(ZIy%4I(uDtEr+4AB!W!K8` zyY>-7?QaQ$TCa^bnQ0^tL|)A2FKzk?%(_QAK3c5uwAs{5eH28Za{Q zgfc0l*ezKx435Z1`sMLfxlV7DbCE3|C}^0Blc9*6g2nlEq2=#!r+qqh-#h93auIeh z=G|FcS$(C{>vaGk0c&YPMUdvX?=87cWplYqCy0%>+io@cM(ySoMEl$LuFsLCA*)>c z-Av#Tavf-_s>}71%POe(+v`yCv3Gb0%88AM%H#wO+gwa%@cY?HdPy2MtKV3vhLrZr zu4;RnIff6JBqS_zRytx6Zu{?FEnm8S0A4@C?o(R%ZlaC2-tFJD*CNqs=)G~$3ch{q zeSgn++qTE&Of9B)1`jN(oil09qZ5)aFE&#p=ly;6u;CzZ{jk1NwWI&>=>Ew`_-^n1?LYVT zJHO{c-6tuR%Sub-_k9RHO)elqA3@F8?6L9QBAY#yZb89n5Rv>dSikRm*>fE5dUMgi zCS8fF)9rO{wCwjju-v>DY;}T8XP{Q5^lAm1eyY-N#y$?Uzib3XjPehJ9(r+WdJvKq zkyoFe4>Mi%-0#jPVrS1o29o-bh3>-crM?bDDZRB8x7~$Zjiwh@tSwOEs;tE=jy8ZD1ilG2Yi`@NecPg6bClCuo3d!Lx~zJ>@rW~`t8{_7jlr9KCfyX5lr->th`qSxbJ5DiBc zofo0?`OLI-+)(#!_sV{fa4kzM%RtNxW}V=sBo!tXVnNIBnNSi3NaI z!6Bg>?wenkNeeR!QbFwXe(XK%IfOkyRbX- z3N>~56n*lPU-HzZNJeln*vSUAxaQHa1W;H^F;Q{2X{p&U(h*T0>gX7?XesZ#2x|qCpM1^GEv-b(9?syGMt%OXC<`~mxEQ$q+u6`fEi0{9S zEc(Q?gPAOvUHhi4_T~(()=qvLCEsDu>*T<58M(8a3AN`bkfKKoPUcgFkhFNOJ}^-l z;t-)jMHtIm&1J?dcVDlxB7SuIRYIN2WVIQ7&8yZm@+cqm*h*}7&*AlYnc&i@?%)#O zrM}D5!|fu)iQ*OdcsgC#cx+nYBfMteBNYo|RM0eg8-3Dtlie>DHkSr^m3o;?4`%D_ z2Z$)^X$=fpE~v4IvtxRY z7H2KTM&*fU5~WR+eLFvLo{CF(~vBuI-CBDEZUIrO#00)R#Hz6w`tUc~8 z{X+w1dP451)lYg}F9WKE6+$u}tU)jnqs3n zE1H^`9tKcv@{&iX0%imr-=ZWlt4UdG9PIVkAZiyH`1xKmI)Yv5w37tLFp4kp1$Rtshj*JY3;Nqq!kHir> zC@9KPn+roJ=JI|;G><>;>GHIjcdH;34jjx@5x94ZbL=8yp-A{ijIOWce=?3cP(g7f{!E(zy;9Vyms} z-nffQ#8jKjOvm?ZE3;Oy@=1GL$|J>n8JQSQ`$02DPr=+Tu^aZd32{#?pCDED$@s~X zthqEGYi`xPRfl)!IHEE~57p10q{i8mOOlMBRKA1BT}4~o@g$c7)!&4XowKL@1-JK` zkntoN6%`eVbNgn`Ri@2|+XCRUz0xJM@LkHECTYyHlHp_=d>i$+{a4AU?`4#1G-dLt zezs6J!)0mJCQ@#ibJO`>Vc2l=H_X@GnI2_HaS6(8mk|LO)rMef;HNaWZ5Eolf)Byd zT?nxPf6Vc8D~gPj7sF)FqyW^D%B0QzooB=EX_CzP{*^?9oh??s)gwTFojf}^>1J#l*&u1T8%h!1OREB8*5TZ?y=Bv?kagl2hX>IXXDYIMWOl%1i z<(#bG(b2-dE49q^-kaRm7|a2=`EOihNLcZ4gT1DdGP87xrZv*IsA;G|%!Z>A@y>^X zYfeG-nikZOI}eNJap!`~?osUpG*`?a+P?PFd?#6)Y@6qW<`x)843YoFHob-B5`6vuVB0x+&35tC^Q> zsONR{`y7aA<9-Aw3XF+~yWqOiJVxG`Q+j%Og2&RSlAMq(^L`N1TkUN-%vQPI?6IKM z3qE!qS2i~j6U(u00{(*=S;2Dn!o*hxk12@u#qB06siaEF?*W)jPx%rcwDo+(wL`KA zp2&N1Ru}gWUl^@cDHu`A<~FtHVb!v*8Gie_2KGK_S~Buq&^KD>_B!YDF3_5+pTuXa z#(%-lg&nomcbzI4QOea9@*Pg*BkB6rr}L>aHAyn13z0^^_9D{I)`lmFj<0#U?ai-Q zfM}}CgOs~8fVLav#7h%^{ZF1l&mV~sA+dPOR#qYQ8h7UXFGXX8sm;^=sA(d%y`-Qe z_u}a27f;e*I3B~))2dS1R{g~#!GA@8o{^F3>AeHVs@tEU^9@k9&s`N8-!nqv5xMA# z3AEgK#LGhJAN$jO8;j}6TH8wf?w1Y!fRfj7EM1d%=w^jn-s&nvFp z_l0-V0|Cc4+I1Y@Q5c2ppLLO4D2za44auE!4wnm4Hb03}aPvb6N-_7D;sEuFP^Z@X zC6Pzcw%w+zP#PG^_thb77JsF5zEiJt_Oz;}xR?Gty`~L(Jf`7V;8_<_lep8CoBR00 zAw>4?;xFvvpW+02=h!wg@K?hl{6?F@=_$`6l8Fzq&ub&=85} zY~1P;Y*t9;5RYYI}S5);j+yr-3cAO6Zu(_`d zSzMfwvA+w4;aT?$u-to^?^ZgwNOT#rM)|b-uP+kH<46B&jrav`Z9IxT1UuFLd=d2k zH$DE5ccKdp4e5U)I21W(r*8v15PHjbN6}KrqmuFvY%7Y;1}pTqIL`|XDBkXHeO$Zfgr2SYTZ7l@TL8W^ zbZQc{k4@N*-SrFg2|WixS%x7|a0dq*!^)wgV{AzS&S|mPzKgE;uQdLz$1`IcpVjZb z3$C+rU-0kVojrGg<*k3{!OX>`mPK{bnLHM|XL-@Yc^R0bDB%i9@>=%moeA?fOCqAG zUxJ5%`?+9FNjU{!ahN&~0#o{2)%1!4#L*e)>*kNa4v|J)6ew|f#O zH<}=oXbzlVWKL7O2C@vAPuq^A23oj$!Yqv4Ta9c+9_e8^8g(qj?{EvW^fm1)LRIWt z(gx+(u^!0@dpwhJ=JXRqjvPLH=c}sBVP4;`9L<=ySUJE&ls0Ndb;mapFjvWlh>xd2FW2CT(;r|eoXZyY3E}V$NpTq5p37! z-ORpKa1WOAJ;r;3dYYT6&*a^GoK>YF%%_aejbnfW*h&i^KvIR+(q{2x z{YEvFLC%(}fz_Bh8M;bpX~%MSY3Z^oy16~8+Zt5o)H1L_U4K(qtB6^rgtc-2IBv@_ zG052l&3#a%7ac*!pSUosKM;9?i9-*!3_i~m|nd8O>0S79GymCnG zxr}Q)U;^LY_%n5bYtxHJh|gWC;h^zDkqK~@GMnrLmB8bGmYXLY;X zec~lY=<>q$l3kCHY^L|-td%B?(5T&WD|Kp)1tBr>#ad3Rb1o5|1asA%m41PZjfQG) zq$i$*o`Rd26R}#80WXFqK0O=4X)c1);zI1ZCUe{}mUf?Pl(4wYk$qI3ZN5VE>dAd* zWO)4OudDocM;T$#Rk|wMC7S1j_~K0K@Hl#G!jz$8TqpT^JfE&`5#d?TD9 zb`eud?mh%wh1fuDMDi1|Ip2|zkDFK`aqGBjcjvV!lQtwt!kf;b6uTL;{>c za$v3U+2a$#izmYrpeQsaEltCC#fT{EaXv=|au`Tq*R)m<8>_f($()%^b}Vgb&@`XF zk{1~hm2x0I-9tylg2M=?TCzN|#fDS9kNg=zDM)WT*uL&!_e1cLr{O%Nw=qdvTHce2 zC4nV!h5Bke5ISfTaii2Twez-40{*z^SmCmThQ=@b>NDN>Lu=Hby6 z4j>Z2Di;;YkK!?;Mlc&x|6<$-PijcsxF(u~KSG0PTV$5c)e>0HgndGAa{S3|Sf6Xz z_&@y{SMoy~Ds`ch2|*X^WR=Nax0?%_4l=YUlaRMC}uBOGr$9*@l)qKj^$p^FVDYJX{I1wR4eMN{ui>ONkE3;FEdfa7-&j!VH+ z`6b=hoZx!=_4T`}DJ=qFM#Nub{`cI{P{nANBuJ5@Fm}vGbn_Uc?G-T2)G-z?wA_^G zwftIZ8U{Lg2`sER-|_^2gKKQ&vrB6*u)YL?EX!D?-6EX@IXQ@En3yP)@yzArCa$!U zSeco6q`bTs9ZZ^}cA|gDO-0C41G5vMBBtEZV}#elXXng=g)_3HiHJtSNr-+HMN1Y{ zbPueK4;}_a#SuAtML>-b)b+T_(y|ASL(tiEC6FC$Bcn8MwT$|O*Hn#U*r zGg;23OSg4?>+5y`8itw;T>Rwh-l9PJi?wmqSuO(c1_Tx~EG+oB0;iuKHxXYKBJp5} zU-IAJi>v+WDTB{rhWj*d$w62R7wht{%xtMT`Hb=QbFIq9a~Wqte0VB}k(9;0$XO?= zmevp@jCjRZ?zuQk#DOKU@hX!X>D|bjP{+P7oLMMeN$Ab?qe4SpV9Tp2g3R17On2$< z0+LxDa#2kF78ZQ2#P28^C@5oAGAgOx3HFwXnN%~xNpMNB?*651w}H=wn?_*rLiUEy zKb^VkV%rDhxpmVK(W*>5Pcm~i=v*<<241gjmr6N28fpeQP@e{dbY^pYWpc#*XsSVN zv)|f6`Kp!LbJkWip~4k}iK5eC=rYc6l#SCX9^@U94XN;c4 z;3m24Gqd@41oY8GVDFS83(v?UCBN~VRQ&mk2Edkxk|39rkFY{A^@U+&m1r7!^&Kp#1ysse zlL3F7)qT}a#6u*SI4J0-;g^@zPz(&HrDf$IB=W!T$`hes;X$A0oTC-Ohmxw0QaEpY z&RG1hy;5vx5y^{)_R?_rRsAbttBBfgp4LUPvt;pM@lx3m485wJt<|}0!z3PZfr5?> z5%9yrL~xr*o~H z*$OM`%BG}-==}g3H)}+yG=_Ej`wBrVUqvNkmJE6Nh&Y+>re7@@FAZQ3=mSxc{-1FOO@#w1Ks(sDp@Q#eV*og4FnShQN`1tyyjkSKO;Chhu) zGE~m-5$5a-$H>vIpL&Kl+vpUj>LCc-{MsCVC9Gr@d%AV35N>bAN z!k&hbrj`PUyyWapWlQNdOv*IP(JxSi3R|g;owhL|l6h*Jrt2 z1Ha;Z>4PzfGS_JH1#|)ut{acJYfkfU^6lBm%govgL3(QHE-F?=>X3%o-njopEtn!5!{c!OKNnncqohTzXuv zDJ~shh9y>l#hYQ!ZESGuNYYebX;mM!frZ8KZWV#s^Uh4e)wVh0xf@j5!6ILw3S`4c zP5wW{m* zC@6Sf@2L}Pp8Hf>+B^SiWqai|e39MC=;qxCv4;VXs<=9p{eWbC!aTL>^iL6eJYp6c z(j)?BJ3Tu$TU*<79d~LIrf+YVbOc_PbCP7%&zdjNjXMxW8<{wpIKK|iXdRw)rg_jt zR`96uX$?-6&X-w>5)uTBI^V(&`R`LISM3%N?Ki27nm^w=mY2(YvS6ZNrD0|(r}{X8 zWfgPb^l|wUWopt-662>Y7#X-QmiQ&AQti8{p1&aE{kvpx^7wVYqu?|(3k(=?w^$0B zNGoiP&^{Zq6VK21iBnGZMi3K|F~WDo8ZfX|&$!5F zA~X{;A7?Ss(lWX>X6$<;1&IHePwNO`h23vw(MOB>&?*#YB@bqw+ z#emSa{FZT1$xqEJX+so0tT6w50|_Gj8^_dA2v8vB$SEkX7Qi%$5KbcceR8NSg(`h5 zRGpPnZnE~9DjBK&iB?5K!Ks9kNMhd>@m7x8u`--SKnnfQa&vIfZnpCBc1aDl9CxcB z5)y;Sat#L*@J9P|e^U!Oz=fkf7hcqb(urEvY=yUck2oOuugU^u^iJB_oZR-&h#ouZ zZSjleK!CL9wQJWqp(M=_vP3t8!F%#T0XtAu5T@sU2nnk9*g!b4wOJYkBJ5Bexy&#% z(M<{Fg4sZYCxipVSea^=n6s*55je{ziCuJLpuXL6zl|S)r@*nq5yi8{1K;hX1^6tD z&f2l1mq}m$+&0l{pr_n(OBDkA|C*=A%Y2UtrvsD>oXy@lF2!mNpC*7@P6*u$N>N_K zQb$1We4x~U6x)wd&RKTu7|XjRJ_cSLA^{wGqi~u^03NjLn10@CES`yNLi|)*%c=fE zr2pLtWvO@G>x7_G0T1M-GoKESTe{1+*PU2W2|0yW3}&r(BWs)M-(lH3F_P@h@)kg| z!0^k@LmAK8hDgE?Nu6x2>w$~xG-?EZ|HeoyJCxM)`G$^`vMx(5`yBq6-Tn@#Z~QpL zICOMmp54id)xCcQi|KLk5I~ixi0C1`f}PH7v)-lgU&U72xX0V5Fv5S;f~3Q zu7pfc28XcXY{~kL9Bd}q;$lvs4S;GOfAYr>OUIY+SbK7Rqy;_$Ju5r=l=mDzhg$hb z!##;eaE3KD0}->v2jb~Z2jOHSVwlci#BacYr?`+LpjOq;Gv=Q(!_pr-k#s_@LX{xJKc>7^6|B@A*_UQQ3% zUU(Hw#w><8#xYDVqcn+U%sKilqZ_*|xhMS%NQ~mh2vf6rm1x$Mz*&FE*v*movB{cZ z6!0)etiKAY$RgEEU_*Esa>s%@P>f@hGEf)o-{PE$oin}5J@jbBS9+T8k!X#gbfqCa zZsf>AADS0a0dfyl(a4cD>LDd}h7kfj&y(FCA41X3XOhG9%=amMm^qQtKDIYs_UeKLz>qgK+@XuV+P+u5GKVkk z*u{JD`L~#ukH?9TB&064escEjcW>p4M=&DG)v%WtPseyGFO`thU+?=D#;_&6Vo;*S z9M8LyWuqJ$34M+mRedhQkC&Y44|OE^1|95k-HjNI;F{&*O9<^7Y#eSP$?aZD|4`Vw znws<4qNUsh@+9&xEzB?hNNJ8PDbiu9+1Nsv-->zY+jwHmlNnk5Z_N$f#@;`t=-ulE zb%cMoo1XiL2>F=+Y){5s%rtnl@1Sg*>v{Kz)`oV<+HFwC7_Ir>HL8E|nf|+M9 z65#eDM0@hQWAl;0P5sqcAeU^yJO|!)mULB0ojyl`98;0;F@uDW$V5Izo{(T(5XV5* z=uH}NNA+-UakMYdZRCdohs{89X&?==Phpj^8=UDtUz_y=cr5JFXjs2KdDqeGe!?ZP zAM&S5fvuTFaAd0Ewc3C!9zHqK^zr%q0PGXWhdW4<@NJv4=EIfGK}8(<${kIl(a{0( z@=-&#%84yx-6-dm8-jQ0)yME;6x_&%!UItL0=EZ&)J}}n9-qn zQH7tS3?SVapV3zGHUjHZ%yVan@TEaJY5Fj;*mI$rdL zuB!6UYA~g+UuRB7{D&iJ8{}MU;uUCcNu=qz8m=tJ-WM}iwqtx>;|nwj44us|KJlKK zb{nlntXApSdqj$8Z9Od>7z;V=INCG&VmCXYN#F`}GaK#ioISfZJ(YjPh?gY}j!PCr zmkzwV(F?||ibCB~!P*pOV9~p>tCAk;0>@gzM6hcQ0oitjbC^eIE;#^m-UYGz#HLR~ z2RIA}Ch5S#f;r!fv$rIa%hWXBIW*2)gg6sFao<#W#3T7`fL}WhHlX8&E^p~e`9`@z zXCp_4q{%N4-unq!2j;fGR2ZsptaT5sf~V-fx6gCGU8 z(HgxnP|#*Ra+J3smoVi`u6N8yeLpIqshJ=H*4xQ$qm~3JDUOZ-iC@x7(%WPwQks2O z#zLmPm?5sofQjY{OTic78L*pd;+lEkK*6S#WSH!Z;?cz1yFr#rE|)~2)RFS3?`%J9OND-Jr+Ptp=^gOhv|~9Ew>syY++podC|eR~ z%WBa%30#vrfoX#tgGc7!-cVonH8B}Q2}50iQwq1Hf5vFWOU7G&3V1m!MjrQsnI@6 z6c1{T!6bDGWomUWk3zs02anrhS;N-1o!IdU_)T_T-WXX>IB>KcqI=3AuJL>$0RhM< z`_vZ=avA>}M`ki$`^~R&_l8>i@5CuWP-A-F=KI~qP#eF=%HZ`(S77*zbXqr-rPBaa z-(J^|q&OaItah>s|5Il+bI3Eik?Nr|VbVUncN_zB*d)vn8Yc^En&j{k%P&+S9Jc_e zNmeWou`*^QGm?aYpt^i-b~_9Ht)IA+2i)q^@Q1IVNF|uzxNzAVa72d2H?}Yy5Z#R* zL#sm2>{zCipgr?G5{4;fG)RWQ|6vFpzSxPjWHV<{e!-6wi`<|hg%}5q{CsS zqFctAT3rP6`L!rRCxAxz02E*=&#uiy@^~7|F_)|D-v|KagpRz$A?`|d;Iux zK`MCWUuIz7j@NQz!j(nO&DKfh3_R8D!M6Ox)QKic=Y@5`%`yHr-y1)>!FQ-5Scod7 z86h~edai6P0c>NY@5}ZQKg0XPrEwZ)LrEdQ=ueBDzE2{ou(awmiP#FM{Ohz^t5Kr; zM}{~WQIz?Jq*hvnTH0AcUT;<%2PVh*a2rjH171d~f3xoYxOfbE6w`&DRCzN~94! z!5G|EN!u3A`~EMe#^oaU*xRnf4$uw+G2j3p`wKIFPpa_#I@aS+ymH5%o3;hnN3G69ZK)&QV!uIutr<#(-2fT865EJlBW}CmGK94GcJo$j56@AKOP%HD z;8_=+F+A2(^opTbi1znEDnsAf0S@ZN?hXp?Gb6yzB0^XEA?9P6Q6(Kjgek5o_C!*m zyEAqe1@M`=#`9fe4=DZo=M7;=C7M0UjnjhraKlRv#K7Y%OUPNU?@`VBqSaSlI?bfc zXd1`UN>XNrq_f;xVhY}eS#}r2lHmwyQ++(SQYK=c$B+d^0z10lFiew=|K-T+@oiW#Kh50kQRrm`iGFKP0E_u4OK$3Em73S~Li zt92An>hy?EZz+`GqtUHPT6WP3<&7VQ&|`zo?LaGu9dw)=ltCKr2hq9azA5Munta3F znZQjfP&}$^sy)sEcw|ELdC=90!aIcBQU<+4f9F2H2~?VT1zK@U!FWWvK@8V6+E^IW zCZKBJtl%2EOW&qJ6Qc>?zf$>r=t5esOP$iKRwCma<-3{fI3e`I;Sbh z(y%Z9v&9KfK_uP)GL_vnxR~`q;Fn}iC=cljXL-HyCQdpDCD@pn-}SstHE#|0)ey2%0-;YH+w{cI+u-hf}j1 zwOJioR^b-O>i;rRaHoN59SNM(oJi!n(*)sK@D07+FZG-^GX&KkX-NKK%Dc)qd%t1S z>eHip1seJXs?$Cli6KH?Q1LA;AZyoPhTBI!syD;X^(=$In?GOHTN4S(uD$^Ga<+%+4|M`W+5_@aWa#Rze;4RFW3V8{k5$bnojB!Lp;!Kft!}r=L^Jr z8sgv{&v_Tu-0VNmk(hy2OEdQ~^t2o0R<&C~7TrYs(8ZB>06)^NZ_MCgVnH z^PSiEp*ltj*vjaA(@b~DRX@@T)V)MRyz_{ERnw7Fq&RZp_u;)^HcB?a+cL~Lp7Zcx zO(VI$P0dI_V`TA01it@1C9FcAY%Zv3sk=j~IVkQJ{#c|v5HJQrSN>k?iL$C$3Hgtm zQcRC4sJJYlKfkUfB=?ZQxfWo=jdcxFlY3-C6&J9D+UU8Vr{D7R!1TdvsNhLVZSZN^ zDO`Y-xe4{GvABV}z;N52SojtE?VMLPxCuOl{8KQXudX6^x#l&NhnO_OXaHW?WC`^! zpDyxZOzPR|opuHRCtcLgTfNUjf3eM6>$PZSx`;DV1ZCf?9*!ogB_5Di`3h=RtIb7x zXf*K@v0T1KP^s!jH=#oqIza(mv&t>0_U0#Zw9ez(W4IK3rq=}u$470C04V< z^vUBrs|-2%S|z=(QqCEdhek41ruC?)k{kPW{m11+rk=Ju6>4}y%V3J*)QW? zCbR5OQIOYL2A~Vty2Jk4tu z?Y{t3qR?Pzw+k~;%h|82*WNW6*M#cTRm>#Jm|`>ZH6uE;eRu}+v=#gl3dD2eG7Kf* z<}ARaXiIoa$!3s7aolnG*_GIFNSGS-@PQ$>DbN(juMLBUYR;@~cC7}pQv8!1VmR%M zwx-5%x*cK+pBoWdS3-lmsU_74QLbh(JP!mnTE1%r<^*{%&>xFh(L9fe=eR50v)cEM zb*Q$TchBL?8~Xj+z(w1_0*Q+m6`5p!Zj9nO5`dn;+BUKp2)6hEJ<$FeIu_zooEmVh zLf|fZJjg7v`1r=X;OJDRhvKJnlWk2u3tx(3;YcI3rFiFT~sg{3v*Qtq(%Bi zR^&yv@k$<7dwfrvqERBBG-@R>yaIn~T?x*Q@iNzXw9>=53q}N4;wxFiD@BIDzdXzZ zLt;OKS*)#F=Z0tqfD|j8f70t{2z~!AmA0E1Df4D>GINBY1XSW2i))A6>pNOP9tIMR%CVmM_m; z$%-btd76VDb%$^^el-SX4$Y5e&hPv(AWfZ^Xh-7q_Ff_TBZ(x>#1xE7`dUU94`1hK z&KNON3PJo|HS%n*FR@*S9Dyfmh0G4)u~mj_Lh&3XA73dE6@FwFaY8q5Rjd0!S^lpB zlpzT&aQ4wfuneIYDFE zcpWIkA4HI6T*8lJCt_g{8MLc1a_rg@U{I8`9jw`YG>s3GDl|{Dq>OcCo#jG*-)f-$ ztto3Xj=^BHZ_-#t4b;LhiIJvtRTr=a3Ol0QnMup!}_g5qxFG+`E*UmwF>_MyTF|8_c=vSgQ`7-1-%!#QH&k~jL4g2-m z9`-y*=gCw&lzI6qlpU@OCp!T$W*eI=u_l@>k|url@X#OBMsx>q514r&Dg zEJ46K?^HKXl|=HuvK$s8zs*) zzj!?xIKLgF{K%|Qm&nE`r~X?$=o7`OG3+l-Im&*C?nzH$OYo?WlB@pJH>@|?aeqlO z*UX8)-!`1YVfW{XC!Qad>{-o>Sx($j1CRCsDZF4ye39mahpVZxMbi9BOD%ND%;is&`@TEq}u;Qw?p#l=NIMXfKFH zL~Ubqavz|nyqa3;!k{_+GMc-e_qH&fJJse8m6rwwE#V!kd@k;IIggi3SHrNG`9f^Z zgE2xx3vX9Blvf}?b*_C!gcyPd*A9}^iGL$#ohD&axD@E(c+D*1CR>dHvhB`~C0|dk zo`n^JT?guRqVpJWz|>EHvJAgxKbKR!>5;y_0SifMCbyQL2#ANQpexnHC;ncYGh01gF^Pyi zJu*)vnady5JI9~aryO>auEz&|qOyyKxFBewxHvg>@-OEI_drUwq~>~^~|P5h1U?96C55~U!H;70iB{E=-F&`ZLk z8)4QYt?MC>*5ib(z5Vf9%;Ms%c(t%$4>Y|F6$GB1uj#DH-U0?!9a+A`MmFmhVyj)C%dJZkZ@A6H9EB z83gz6fP2sK5Z1SipQ_d1)t%9K@pAHq@O&7FGh(z^G}6cGnvk1^CMfC)Ns`~I_0Qn> z5V5^{AeO2eWBi-{&r7wRf|lK<)Ns5k(V?LT%epFbs9PuEIpGaV>XooY4Q%Fv9JrFP z!K%+H^_C^5YjAMD=pV&8JDz0(u=^fawyBJ-;I#rx>hfRGH*@cL8rFD7b~+1hx=p8t z+TO^;(IH!kPw>G_H&Vu6i6O!}R^k2bnHHbSdtuw4aU9W$$8qrk?hJ*ASLYlYxDa>5 zw^w%|tW0G=S_S$l1a!0<0~`>4%FoAi)4oe>5Yyw`Pu!>`ZOJFGSkJ2=?=UG+-;k~i zCp_fngu>pjgHu!}M!4zQY~4FP&^}v9<;3NQN6HnySSC*qLDOv?z;5JhxcU;rXQe!X z`VyONyt|;klLW7Nj&?O$8R%B$yPt{2sK6)}uXlAArT?jj^p`y3j^o8<^4mNo6<4C3 z!AADS7pCHn){*R~q~LU%MZmi4m{~eQD_;fO8eN9$#1usgnZ4!l1L{({O+%L*XMU(- z3g5|kv{r6f`jLYQ&yi}cXl1wVN9M+!QA*_mm3Hpb*6&wg?yMk{%TCH|_XxiZcJeE@ zrxo=M;Wg@5iUk9hB62YNK8EG;>EZkB`*ZvTt~v=(-vWiJfD^kqgR)0nL_p zkZr-z@ru_NE1RH*NqwfoPgTM4Tq~n~DI4V`aItVhi@hBi#2iGZU(n8zWUYrm;OcBT6y?+-JGq*!MtQi0c1uBd zaJJ+6Jo7R&cu1X73ptgXV>e2x=mKk@;UJs=5Uh|WDdqd0!AJ^EGjxcP9ULi&Qu|CG z4R~{ayAl=MGCbIu``Mq>)j>N6zdtA``VsouWs8zJw=409fXY?t^Iud4AX z))IiHisFaeUJ>MjGmLvEeJpo;egCx1Z8?7=d#)=IFpMv!Oz`~YaJg9Hkbio}FD|5! zcjnc6CuxH_Q1r>xb#o7t@w-v(SBI7DyOVfj%e(Sz9ODiqY77}Tp^;vE+AI8BO{(9Q z(t0Nf7n_MOTRiMi5af3--@pEJH(HP1FX2tKuiUI?$p($O&-fzke82?NDKbNe0rf~hbr;atN zCsWC+Z+zY;tP2ZN5dM%DL-jr~Ygd?+^jq(>?p)qd2hcu7h+gJKtW{)K&Y0=t+r1vT z!p|Dd>S^Hv*k3{0Q^rV6Fjon)qT2bJ@JZtAkT`aU$GbKH-&f>ZS=7)aLuf`3)mw6s;JE%k4PoLdAR=T;N&)w#OP2Bxb@zF8dr{=4sewS2JZ($o;l{0y^ghN_!iuw_%8c^_5O zW)0@_S#r0If%6G^BKqRfvAgH2d=#<2n}`P4d=J|a#J?8V6ZV~noPDPE>-H*`g!-Ca z2$qc)_i7DZD>S~I=)s5ftO+__e$cLpWE+Ba_I;k)3M^EfR|n)sxZCWuQ~8de%?+34 z*RKD%sN!Sh9mLMjZDEXp#?KOABTG1OA%bXQ6(Nz+t#8yM*?acR8G1eYx=~u(<_AOg zJGnGv1hwe;+%l0`{H=tj7L~I*#i&+*q%eTKMn%eVxBm9v@!DCzu6zA15R+T`?zEtp zok_))p&$Lrq3}a+>#6(Od-+#+RV12alQ$oMR8W|?~(7=@OkD0eL{SbU$y)| zq3Uf6mqYGht%S(Nw$R6uHX*%nMrlgQRU2{Ix^QfMzfrz>rK+!*1S#Z zgBusOwpKC1x6kAz??NmBdRZ~Vag-EJ4L7a(ImE8~@wBtYtU!M2XJnD|`sd%oiz2a# zXNn_~hZN%8_Ql)kMZ0uv_=cOZqv%EwY3D)CI9wgFi3^dxR^o_MZ*uUdBtU{z@}Kw0 zfF->-E*`$4c+h7;W^IxYCav-tGBusffhF>Yp(y`i9DT{UGC)GBm37{mZ9H&_Flm_ zJuEITK4G7oqRkG786glt>dDQ3DHgm1;dt8H%C-Ulh9v8ePv@19cuV?Sa+n8f8(KmD4_M!R>Au)3!Gi4u9Cm~ z5?a=MO{0zp8qQpWT~Ah^8FYqh{`|fbA$*g5Udmo5_}JSj0mdi%@HI%zb^!<>3%5Su z>dSQQN0=#tURH$*#U|ppo1|mg^qIK7;_C?ZW`cZ_vr0j|M~V7^|F*64N}1fiANeCU zNv^z_D0P@5+;P?gMhZHgl&pn_&2n~3nj~3$#;5Z1DO*KX+7Wpl$xKCr2coJ?24 zxd5u`=oiJ}u@6%|AEGBn5VOvK_{J`y|sLD$bT2Z^cw4^SeFCo6T zp!91a{lmm1N}W{X)K(64VzhT<{nx*<3uSny+Wk;_q?|)b+rt>5sWquJe0OqdDDi03 z*WF7K7u&v%Aw_{})3VtxWsl)>p)QxRUfiS-%n&$n!Kp3QLxzlVfem(-s(&4RK*m)J zLCNp*{ziNeJT_gMT9f!Hi5&Ob(9ZOxUiV0*+{J6Jj9_2lGfMQSK_gx!BtoyTlXa`R z*}BVB7f9d$xWAd8-kz5s+ygQ3cUpPNC9a`~!Uh6w0tV_%R5%^8sKk(Co-wuW0p_YI zh_ZpsDBKd#VedzB?1WsNe3-x_7l{a_e9h7~^Sm$8iqGGlt^avszZ9Vx)N(PqaMr7@ zO=X#HkQY&tEZHrixl*G)+W+!H#S)8XdW<^&A^oP$jkK46_AzEl@BF0w)YEHOm!{=~ zICSXqNi&7<3dU;9(1(*>6f@W4;Ry-~zW1Xib)m$UKXd|?e4PB2GTF<&-iT`Jvpv*i zk{Z^~_!qb8rnRTcbJ9j`X?FW!Td(pNX{GthuZ!o~ZnwoJu&ywOrd^ zs4-9%E;VWMFBpmdPgt95SCDxLvvU#q(vI_k34+H|b6%|%K5$Z5g{*ileKLTh)g7X$ zaeV4Sbcf+Z0DM`O!p7{`2pzkKIe`IwY{As^Rg!vWN+Aux_vwa9P-9zKBEIGSO`dOJ zO_H{Sc>8OGRf<&)kvg<4il%eFE(QE!0cP^vzrO7z?&KNUa>Ow7G+fY=7iPeAUkb>7 zEhm%rK_5IJKc?&LW644M;FmKtGyrq(2e3SJ$ey*o^&4s6zTS>RML9~zi2thob@{QJ z?^i8GJjd7%L2ZElGp`x>Ul$^lGIMjM^))%rker&eg`Q#$&Kx!$jLO@!n`7UO3HHN%kyu8FXzl{q1#S0>}%$S7~r22>)V_{^XS^S*pGVmnskC0w#|S5TjsJ7 zdsat!u1NBK0cmSQR=x)G)H&%po}tX~>L+`qdbzG^D`g*4CLBcEY+ z@8m2%Wum>X-79PRfbd%kN-NqTV&YO`gs%Ub&jcrV^EuUUbxvKdz_UvihMW_E7Axwm z|A?63KEq=Y`lsv#8Ec{Yc)KZrOA2f8*PjkKKGgmh;F^wFUb%h-ic9-);qV zwG)zFi}@rUmX4-@Mva;+} /> } /> } /> + } /> } /> } /> {/* Redirects for underscore-based URLs (legacy Stripe config) */} @@ -50,6 +52,10 @@ export function App() { path="/checkout_cancel" element={} /> + } + /> ); diff --git a/frontend/apps/artcraft-website/src/components/landing-action-buttons.tsx b/frontend/apps/artcraft-website/src/components/landing-action-buttons.tsx new file mode 100644 index 0000000000..dba0ba073a --- /dev/null +++ b/frontend/apps/artcraft-website/src/components/landing-action-buttons.tsx @@ -0,0 +1,54 @@ +import { Button } from "@storyteller/ui-button"; +import { isMobile, isMacOs } from "react-device-detect"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faWindows, faApple } from "@fortawesome/free-brands-svg-icons"; +import { faRocket } from "@fortawesome/pro-solid-svg-icons"; +import { DOWNLOAD_LINKS } from "../config/downloads"; + +interface LandingActionButtonsProps { + onDownloadClick?: (e: React.MouseEvent) => void; + className?: string; +} + +export const LandingActionButtons = ({ + onDownloadClick, + className, +}: LandingActionButtonsProps) => { + const MAC_LINK = DOWNLOAD_LINKS.MACOS; + const WINDOWS_LINK = DOWNLOAD_LINKS.WINDOWS; + const downloadUrl = isMacOs ? MAC_LINK : WINDOWS_LINK; + + return ( +
+ {isMobile ? ( + + ) : ( + <> + + + + )} +
+ ); +}; diff --git a/frontend/apps/artcraft-website/src/components/pricing-table/pricing-table.tsx b/frontend/apps/artcraft-website/src/components/pricing-table/pricing-table.tsx index 40d66e3599..5f3b85f285 100644 --- a/frontend/apps/artcraft-website/src/components/pricing-table/pricing-table.tsx +++ b/frontend/apps/artcraft-website/src/components/pricing-table/pricing-table.tsx @@ -8,12 +8,7 @@ import { import { twMerge } from "tailwind-merge"; import { useState, useEffect } from "react"; import { TabSelector } from "@storyteller/ui-tab-selector"; -import { - UsersApi, - BillingApi, - UserInfo, - StorytellerApiHostStore, -} from "@storyteller/api"; +import { UsersApi, BillingApi, UserInfo } from "@storyteller/api"; import { useNavigate } from "react-router-dom"; const billingTabs = [ @@ -54,6 +49,7 @@ const PricingTable = ({ const [activePlanSlug, setActivePlanSlug] = useState(null); const [isLoading, setIsLoading] = useState(true); const [processingPlan, setProcessingPlan] = useState(null); + const [isCancelling, setIsCancelling] = useState(false); // Fetch user session and subscriptions on mount useEffect(() => { @@ -172,12 +168,6 @@ const PricingTable = ({ return; } - // Not logged in - redirect to signup - if (!user) { - navigate("/signup"); - return; - } - // Set loading state for this plan setProcessingPlan(planSlug); @@ -185,41 +175,59 @@ const PricingTable = ({ const cadence = isYearly ? "yearly" : "monthly"; const apiPlanSlug = PLAN_SLUG_MAP[planSlug] || planSlug; - // Determine if we need checkout (new subscription) or portal (switch plan) - const hasActiveSub = activePlanSlug && activePlanSlug !== "free"; - - const endpoint = hasActiveSub - ? "/v1/stripe_artcraft/portal/switch_plan" - : "/v1/stripe_artcraft/checkout/subscription"; - - const apiHost = - StorytellerApiHostStore.getInstance().getApiSchemeAndHost(); - const response = await fetch(`${apiHost}${endpoint}`, { - method: "POST", - headers: { - Accept: "application/json", - "Content-Type": "application/json", - }, - credentials: "include", - body: JSON.stringify({ + // Not logged in - use user_signup_subscription_checkout + if (!user) { + const billingApi = new BillingApi(); + const response = await billingApi.UserSignupSubscriptionCheckout({ plan: apiPlanSlug, cadence: cadence, - }), - }); + }); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); + if (!response.success || !response.data) { + throw new Error( + response.errorMessage || "Failed to initiate checkout", + ); + } + + // Redirect to Stripe + window.location.href = response.data.stripeCheckoutRedirectUrl; + return; } - const data = await response.json(); + // Logged in - determine if we need checkout (new subscription) or portal (switch plan) + const hasActiveSub = activePlanSlug && activePlanSlug !== "free"; + const billingApi = new BillingApi(); - // Redirect to Stripe - const redirectUrl = - data.stripe_checkout_redirect_url || data.stripe_portal_url; - if (redirectUrl) { - window.location.href = redirectUrl; + if (hasActiveSub) { + // User has active subscription - switch plan via portal + const response = await billingApi.SwitchPlan({ + plan: apiPlanSlug, + cadence: cadence, + }); + + if (!response.success || !response.data) { + throw new Error( + response.errorMessage || "Failed to initiate plan switch", + ); + } + + // Redirect to Stripe Portal + window.location.href = response.data.stripePortalUrl; } else { - console.error("No redirect URL returned from API"); + // User logged in but no active subscription - checkout + const response = await billingApi.SubscriptionCheckout({ + plan: apiPlanSlug, + cadence: cadence, + }); + + if (!response.success || !response.data) { + throw new Error( + response.errorMessage || "Failed to initiate checkout", + ); + } + + // Redirect to Stripe Checkout + window.location.href = response.data.stripeCheckoutRedirectUrl; } } catch (error) { console.error("Error initiating checkout:", error); @@ -228,6 +236,28 @@ const PricingTable = ({ } }; + const handleCancelPlan = async () => { + setIsCancelling(true); + try { + const billingApi = new BillingApi(); + // Access general portal where user can cancel + const response = await billingApi.GetPortalUrl(); + + if (!response.success || !response.data) { + throw new Error( + response.errorMessage || "Failed to access subscription management", + ); + } + + // Redirect to Stripe Portal where user can cancel + window.location.href = response.data.stripePortalUrl; + } catch (error) { + console.error("Error accessing subscription management:", error); + } finally { + setIsCancelling(false); + } + }; + const formatPrice = (plan: SubscriptionPlanDetails) => { if (plan.monthlyPrice === 0) { return { current: 0, original: null }; @@ -386,6 +416,19 @@ const PricingTable = ({ ); })} + + {/* Manage Plan Button - Only shown if user has active subscription */} + {activePlanSlug && activePlanSlug !== "free" && ( +
+ +
+ )} ); }; diff --git a/frontend/apps/artcraft-website/src/pages/checkout/cancel.tsx b/frontend/apps/artcraft-website/src/pages/checkout/cancel.tsx index 95a0b9ef9d..4c812ab148 100644 --- a/frontend/apps/artcraft-website/src/pages/checkout/cancel.tsx +++ b/frontend/apps/artcraft-website/src/pages/checkout/cancel.tsx @@ -2,11 +2,64 @@ import { faXmarkCircle } from "@fortawesome/pro-solid-svg-icons"; import { faDiscord } from "@fortawesome/free-brands-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button } from "@storyteller/ui-button"; -import { Link } from "react-router-dom"; +import { Link, useSearchParams } from "react-router-dom"; import { SOCIAL_LINKS } from "../../config/links"; import Seo from "../../components/seo"; +import { useEffect, useState } from "react"; +import { UsersApi } from "@storyteller/api"; const CheckoutCancel = () => { + const [searchParams] = useSearchParams(); + const skipOnboarding = searchParams.get("skip_onboarding") === "true"; + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const checkOnboarding = async () => { + // Skip onboarding check if we already went through it + if (skipOnboarding) { + setIsLoading(false); + return; + } + + try { + const usersApi = new UsersApi(); + const sessionResponse = await usersApi.GetSession(); + + if (sessionResponse.success && sessionResponse.data?.loggedIn) { + const onboarding = sessionResponse.data.onboarding; + + // If onboarding is undefined or has any required fields not set, redirect to onboarding + if ( + !onboarding || + onboarding.password_not_set || + onboarding.email_not_set || + onboarding.email_not_confirmed + ) { + // Redirect to onboarding - it will add skip_onboarding=true after username step + window.location.href = + "/onboarding?redirect_to=" + + encodeURIComponent("/checkout/cancel"); + return; + } + } + } catch (error) { + console.error("Error checking onboarding status:", error); + } finally { + setIsLoading(false); + } + }; + + checkOnboarding(); + }, [skipOnboarding]); + + if (isLoading) { + return ( +
+
+
+ ); + } + return (
{ + const [searchParams] = useSearchParams(); const downloadUrl = isMacOs ? DOWNLOAD_LINKS.MACOS : DOWNLOAD_LINKS.WINDOWS; + const [isCheckingOnboarding, setIsCheckingOnboarding] = useState(true); + + useEffect(() => { + const checkOnboarding = async () => { + // If coming from completed onboarding, skip the check + if (searchParams.get("onboarding_complete") === "true") { + setIsCheckingOnboarding(false); + return; + } + + try { + const usersApi = new UsersApi(); + const sessionResponse = await usersApi.GetSession(); + + if (sessionResponse.success && sessionResponse.data?.loggedIn) { + const onboarding = sessionResponse.data.onboarding; + + // If onboarding is undefined or has any required fields not set, redirect to onboarding + // This handles the case where the backend hasn't populated onboarding data yet + if ( + !onboarding || + onboarding.password_not_set || + onboarding.email_not_set || + onboarding.email_not_confirmed + ) { + // Use window.location for a hard redirect to ensure it works + // Do NOT set isCheckingOnboarding to false - keep showing loading spinner + window.location.href = "/onboarding"; + return; + } + } + } catch (error) { + console.error("Error checking onboarding status:", error); + } + + // Only set loading to false if we're actually staying on this page + setIsCheckingOnboarding(false); + }; + + checkOnboarding(); + }, [searchParams]); + + if (isCheckingOnboarding) { + return ( +
+
+
+ ); + } return (
diff --git a/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx b/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx index 5d2836a2cc..5f03c0dbd2 100644 --- a/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx +++ b/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx @@ -1,7 +1,7 @@ import { DiscordButton } from "../../components/discord-button"; import { Button } from "@storyteller/ui-button"; -import { isMobile, isMacOs } from "react-device-detect"; -import { faWindows, faApple, faGithub } from "@fortawesome/free-brands-svg-icons"; +import { isMobile } from "react-device-detect"; +import { faGithub } from "@fortawesome/free-brands-svg-icons"; import { faVolumeMute, faVolumeHigh, @@ -23,19 +23,18 @@ import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import ModelBadgeGrid from "../../components/model-badge-grid"; import Seo from "../../components/seo"; -import { DOWNLOAD_LINKS } from "../../config/downloads"; + import { OwnershipComparison } from "../../components/ownership-comparison/ownership-comparison"; import { DownloadModal } from "../../components/download-modal"; + import { UsersApi } from "@storyteller/api"; +import { LandingActionButtons } from "../../components/landing-action-buttons"; gsap.registerPlugin(ScrollTrigger); //const HERO_VIDEO_URL = "https://pub-f7441936e5804042a1ea2bdc92e4dc71.r2.dev/artcraft_commercial.mp4"; -const HERO_VIDEO_URL = "https://pub-f7441936e5804042a1ea2bdc92e4dc71.r2.dev/artcraft_website_v2.mp4"; - -// Versions and links are now centralized in downloads config - BFlat -const MAC_LINK = DOWNLOAD_LINKS.MACOS; -const WINDOWS_LINK = DOWNLOAD_LINKS.WINDOWS; +const HERO_VIDEO_URL = + "https://pub-f7441936e5804042a1ea2bdc92e4dc71.r2.dev/artcraft_website_v2.mp4"; const Landing = () => { const videos = [ @@ -58,26 +57,24 @@ const Landing = () => { const [isLoggedIn, setIsLoggedIn] = useState(false); const videoRef = useRef(null); - const downloadUrl = isMacOs ? MAC_LINK : WINDOWS_LINK; - useEffect(() => { const checkSession = async () => { - const api = new UsersApi(); - const response = await api.GetSession(); - if (response.success && response.data?.loggedIn) { - setIsLoggedIn(true); - } + const api = new UsersApi(); + const response = await api.GetSession(); + if (response.success && response.data?.loggedIn) { + setIsLoggedIn(true); + } }; checkSession(); }, []); const onDownloadClick = (e: React.MouseEvent) => { if (isLoggedIn) { - return; + return; } - + setShowDownloadModal(true); - + localStorage.setItem("artcraft_download_initiated", "true"); }; @@ -85,45 +82,52 @@ const Landing = () => { { icon: faMapMarkerAlt, title: "Image to Location", - description: "Placing virtual actors into physical environments establishes single-location consistency. You can film multiple shots within a room without having things disappear.", - src: "/videos/features/WorldLabs_Demo_2.webm" + description: + "Placing virtual actors into physical environments establishes single-location consistency. You can film multiple shots within a room without having things disappear.", + src: "/videos/features/WorldLabs_Demo_2.webm", }, { icon: faCube, title: "3D Image Compositing", - description: "Use images (backdrops, foreground elements, props, etc.) in scenes with depth and blend them naturally together. Just a couple of images usually leads to great compositions.", - src: "/videos/features/Panel.webm" + description: + "Use images (backdrops, foreground elements, props, etc.) in scenes with depth and blend them naturally together. Just a couple of images usually leads to great compositions.", + src: "/videos/features/Panel.webm", }, { icon: faLayerGroup, title: "2D Image Compositing", - description: "Use images, background removal, layers, and simple drawing tools to precisely compose a scene.", - src: "/videos/features/Editor.webm" + description: + "Use images, background removal, layers, and simple drawing tools to precisely compose a scene.", + src: "/videos/features/Editor.webm", }, { icon: faShapes, title: "Image to 3D Mesh", - description: "It's almost impossible to lay out complicated objects or block complicated scenes; turning images into 3D helps position elements exactingly and intentionally.", - src: "/videos/features/Make_3D.webm" + description: + "It's almost impossible to lay out complicated objects or block complicated scenes; turning images into 3D helps position elements exactingly and intentionally.", + src: "/videos/features/Make_3D.webm", }, { icon: faTools, title: "Mixed Asset Crafting", - description: "You can use image cutouts, worlds, and simple 3D meshes all together to precisely and intentionally lay out your scenes.", - src: "/videos/features/Mixed.webm" + description: + "You can use image cutouts, worlds, and simple 3D meshes all together to precisely and intentionally lay out your scenes.", + src: "/videos/features/Mixed.webm", }, { icon: faUser, title: "Character Posing", - description: "You can dynamically pose your characters to achieve the precise character, scene, and camera blocking before calling \"action\".", - src: "/videos/features/Pose_Second_Version.webm" + description: + 'You can dynamically pose your characters to achieve the precise character, scene, and camera blocking before calling "action".', + src: "/videos/features/Pose_Second_Version.webm", }, { icon: faEraser, title: "Background Removal", - description: "Instantly remove backgrounds from images to create assets for your scenes. Clean, precise, and ready for compositing.", - src: "/videos/features/Background.webm" - } + description: + "Instantly remove backgrounds from images to create assets for your scenes. Clean, precise, and ready for compositing.", + src: "/videos/features/Background.webm", + }, ]; // Refs for GSAP animations @@ -142,9 +146,9 @@ const Landing = () => { // ONLY on non-mobile devices to ensure performance and prevent content loading issues if (!isMobile) { const elements = gsap.utils.toArray("[data-animate]"); - + gsap.set(elements, { autoAlpha: 0, y: 20 }); - + elements.forEach((el) => { gsap.to(el, { autoAlpha: 1, @@ -155,7 +159,7 @@ const Landing = () => { trigger: el, start: "top 90%", toggleActions: "play none none none", - } + }, }); }); } @@ -171,13 +175,13 @@ const Landing = () => { pinSpacing: false, invalidateOnRefresh: true, }); - + featureRefs.current.forEach((el, index) => { if (!el) return; ScrollTrigger.create({ trigger: el, start: "top 40%", - end: "bottom 40%", + end: "bottom 40%", onEnter: () => setActiveFeature(index), onEnterBack: () => setActiveFeature(index), }); @@ -211,15 +215,17 @@ const Landing = () => { // GSAP animation for mobile media and description useEffect(() => { if (mobileMediaRef.current) { - gsap.fromTo(mobileMediaRef.current, + gsap.fromTo( + mobileMediaRef.current, { opacity: 0 }, - { opacity: 1, duration: 0.4, ease: "power2.out" } + { opacity: 1, duration: 0.4, ease: "power2.out" }, ); } if (mobileDescRef.current) { - gsap.fromTo(mobileDescRef.current, + gsap.fromTo( + mobileDescRef.current, { opacity: 0, y: 10 }, - { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" } + { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" }, ); } }, [activeFeature]); @@ -236,7 +242,10 @@ const Landing = () => { }; return ( -
+
{ {/* CTA Buttons */}
- {isMobile ? ( - - ) : ( - - )} - Try Free + + Buy Credits + Try Download
{/* Glassy Video Mockup */} @@ -313,21 +319,18 @@ const Landing = () => { onMouseEnter={() => setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} > - + ))} +
+ + {/* Mobile Media Preview */} +
+
+
+ + {/* Mobile Description */}
-

- Advanced Crafting Features -

-

- We're Pulling You
Out of Prompting -

-

- Text prompting is neat, but artists crave control. -

- -
- -

- Before you type "rotate arm thirty degrees", try ArtCraft and let our advanced - toolset help you achieve consistency and repeatability. -

- -
- -

- ArtCraft is the control that mere words cannot buy. +

+ {features[activeFeature].title} +

+

+ {features[activeFeature].description}

-
+
-
- {/* Mobile Layout */} -
- {/* Mobile Navigation (Tabs) */} -
+ {/* Desktop Sticky Scroll Layout */} + {!isMobile && ( +
+ {/* Left Column: Scrolling Text */} +
{features.map((feature, index) => ( - +
+
+ +
+

+ {feature.title} +

+

+ {feature.description} +

+
+
))}
- {/* Mobile Media Preview */} -
-
-
- - {/* Mobile Description */} -
-

- {features[activeFeature].title} -

-

- {features[activeFeature].description} -

-
-
- - {/* Desktop Sticky Scroll Layout */} - {!isMobile && ( -
- {/* Left Column: Scrolling Text */} -
+ {/* Right Column: Sticky Image */} +
+
{features.map((feature, index) => (
{ featureRefs.current[index] = el; }} - className="min-h-[80vh] flex flex-col justify-center pr-8 xl:pr-16" + ref={(el) => { + cardRefs.current[index] = el; + }} + className="absolute inset-0 w-full h-full bg-[#050505] shadow-2xl origin-bottom" + style={{ + zIndex: index, + transform: + index === 0 ? "translateY(0%)" : "translateY(110%)", + }} > -
-
- -
-

- {feature.title} -

-

- {feature.description} -

-
+
- {/* Right Column: Sticky Image */} -
-
- {features.map((feature, index) => ( -
{ cardRefs.current[index] = el; }} - className="absolute inset-0 w-full h-full bg-[#050505] shadow-2xl origin-bottom" - style={{ zIndex: index, transform: index === 0 ? 'translateY(0%)' : 'translateY(110%)' }} - > -
- )} -
+
+ )} +
@@ -546,16 +571,11 @@ const Landing = () => { {/* Gradient Orbs for Section */}
-
+
{/* Bento Grid Container */}
{/* Reason #1 - Large Box */} -
+
{
{/* Reason #2 - Medium Box */} -
+

Desktop App @@ -623,18 +641,16 @@ const Landing = () => {

{/* Reason #3 - Medium Box */} -
+

It's Open Source

Our desktop app's code and infrastructure are all{" "} - @@ -654,9 +670,7 @@ const Landing = () => {

{/* Reason #4 - Large Box */} -
+

@@ -679,9 +693,7 @@ const Landing = () => {

{/* Reason #5 - Full Width Box */} -
+

@@ -723,16 +735,12 @@ const Landing = () => {

-
{/* Gradient Orb for Section */}
{/* Videos Section */} -
+

Made using{" "} @@ -741,8 +749,8 @@ const Landing = () => {

- Check out the videos below! -

+ Check out the videos below! +

{videos.map((video, index) => ( @@ -750,31 +758,37 @@ const Landing = () => { key={index} className="group relative rounded-2xl bg-white/10 backdrop-blur-md p-2 sm:p-4 transition-all duration-300 hover:bg-white/20 hover:scale-[1.02] hover:shadow-2xl hover:shadow-primary/20" > -
setActiveVideo(index)}> +
setActiveVideo(index)} + > {activeVideo === index ? ( -