{"release_id":"01a1c502-4ad1-0000-ec62-adc54d3c69aa","chunk_id":"01a1c502-4c44-76d1-bb96-8ff1c3fe203e","file":"K1usdk3D.mjs","mappings":"s2CAAA,UAKO,IAAAA,mBAAS,EAAK,EAEhBC,EACAC,EACAC,EAAO,EACPC,EAAW,GAEN,SAAAC,GAAO,KACVJ,EAAM,OAMP,GALJE,IAKIC,GAAYD,EAAO,IAAM,EAAG,CAC/BD,EAAS,sBAAsBG,CAAI,QAEpC,CAEM,MAAAC,EAAML,EAAO,WAAW,IAAI,MAC7BK,EAAG,aAEFC,EAAIN,EAAO,YACXO,EAAIP,EAAO,aAGbA,EAAO,QAAUM,GAAKN,EAAO,SAAWO,GAC3CP,EAAO,MAAQM,EACfN,EAAO,OAASO,GAEhBF,EAAI,UAAU,EAAG,EAAGC,EAAGC,CAAC,EAEzBF,EAAI,yBAA2B,eAEzBG,EAAIN,EAAO,IAIXO,EAAa,GACbC,EAAkC,CAAA,UAE/BC,EAAI,EAAGA,GAAKF,EAAYE,IAAK,OAC/BC,EAASD,EAAIF,EACbI,EAAID,EAASN,EAGbQ,EAAQ,KAAK,IAAIF,EAAS,EAAIJ,EAAI,GAAG,EAAI,IACzCO,GAAQ,KAAK,IAAIH,EAAS,GAAKJ,EAAI,GAAG,EAAI,GAC1CQ,GAAQ,KAAK,IAAIJ,EAAS,GAAKJ,EAAI,GAAG,EAAI,GAC1CS,GAAQ,KAAK,IAAIL,EAAS,EAAIJ,EAAI,GAAG,EAAI,IAGzCU,GAAc,KAAK,IAAIN,EAAS,KAAK,EAAE,EAEvCO,IADa,KAAQL,EAAQC,GAAQC,GAAQC,IAAS,MAC1B,GAAMC,GAAc,IAEtDR,EAAO,KAAI,CAAG,EAAAG,EAAG,EAAGN,EAAIY,GAAcZ,EAAC,CACxC,CAGAF,EAAI,UAAS,EACbA,EAAI,OAAO,EAAGE,CAAC,YACJa,KAAKV,EACfL,EAAI,OAAOe,EAAE,EAAGA,EAAE,EAAI,EAAE,EAEzBf,EAAI,OAAOC,EAAGC,CAAC,EACfF,EAAI,UAAS,EACP,MAAAgB,EAAchB,EAAI,qBAAqB,EAAGE,EAAG,EAAGA,EAAI,EAAG,EAC7Dc,EAAY,aAAa,EAAG,0BAA0B,EACtDA,EAAY,aAAa,EAAG,uBAAuB,EACnDhB,EAAI,UAAYgB,EAChBhB,EAAI,KAAI,EAGRA,EAAI,UAAS,EACbA,EAAI,OAAO,EAAGE,CAAC,EAEN,QAAAI,EAAI,EAAGA,EAAID,EAAO,OAAS,EAAGC,IAAK,OACrCW,EAAOZ,EAAOC,CAAC,EACfY,EAAOb,EAAOC,EAAI,CAAC,EACnBa,GAAOF,EAAK,EAAIC,EAAK,GAAK,EAC1BE,IAAOH,EAAK,EAAIC,EAAK,GAAK,EAChClB,EAAI,iBAAiBiB,EAAK,EAAGA,EAAK,EAAGE,EAAKC,EAAG,CAC9C,CACApB,EAAI,OAAOC,EAAGC,CAAC,EACfF,EAAI,UAAS,EAEP,MAAAqB,EAAYrB,EAAI,qBAAqB,EAAGE,EAAG,EAAGA,EAAI,GAAI,EAC5DmB,EAAU,aAAa,EAAG,0BAA0B,EACpDA,EAAU,aAAa,GAAK,yBAAyB,EACrDA,EAAU,aAAa,GAAK,0BAA0B,EACtDA,EAAU,aAAa,EAAG,uBAAuB,EACjDrB,EAAI,UAAYqB,EAChBrB,EAAI,KAAI,QAGFsB,EAAuC,CAAA,UACpChB,EAAI,EAAGA,GAAKF,EAAYE,IAAK,OAC/BC,EAASD,EAAIF,EACbI,EAAID,EAASN,EAEbQ,EAAQ,KAAK,IAAIF,EAAS,EAAIJ,EAAI,IAAM,CAAC,EAAI,GAC7CO,GAAQ,KAAK,IAAIH,EAAS,GAAKJ,EAAI,IAAM,CAAC,EAAI,IAC9CQ,GAAQ,KAAK,IAAIJ,EAAS,EAAIJ,EAAI,IAAM,EAAG,EAAI,IAE/CU,GAAc,KAAK,IAAIN,EAAS,KAAK,EAAE,EAEvCO,IADa,IAAOL,EAAQC,GAAQC,IAAS,MACjB,GAAME,GAAc,IAEtDS,EAAY,KAAI,CAAG,EAAAd,EAAG,EAAGN,EAAIY,GAAcZ,EAAC,CAC7C,CAEAF,EAAI,UAAS,EACbA,EAAI,OAAO,EAAGE,CAAC,EACN,QAAAI,EAAI,EAAGA,EAAIgB,EAAY,OAAS,EAAGhB,IAAK,OAC1CW,EAAOK,EAAYhB,CAAC,EACpBY,EAAOI,EAAYhB,EAAI,CAAC,EACxBa,GAAOF,EAAK,EAAIC,EAAK,GAAK,EAC1BE,IAAOH,EAAK,EAAIC,EAAK,GAAK,EAChClB,EAAI,iBAAiBiB,EAAK,EAAGA,EAAK,EAAGE,EAAKC,EAAG,CAC9C,CACApB,EAAI,OAAOC,EAAGC,CAAC,EACfF,EAAI,UAAS,EAEP,MAAAuB,EAAYvB,EAAI,qBAAqB,EAAGE,EAAG,EAAGA,EAAI,EAAG,EAC3DqB,EAAU,aAAa,EAAG,2BAA2B,EACrDA,EAAU,aAAa,GAAK,0BAA0B,EACtDA,EAAU,aAAa,EAAG,uBAAuB,EACjDvB,EAAI,UAAYuB,EAChBvB,EAAI,KAAI,EAGRA,EAAI,yBAA2B,cACzB,MAAAwB,EAAWxB,EAAI,qBAAqB,EAAGE,EAAG,EAAGA,EAAI,CAAC,EACxDsB,EAAS,aAAa,EAAG,0BAA0B,EACnDA,EAAS,aAAa,EAAG,uBAAuB,EAChDxB,EAAI,UAAYwB,EAChBxB,EAAI,SAAS,EAAGE,EAAI,EAAGD,EAAG,CAAC,EAE3BL,EAAS,sBAAsBG,CAAI,CACpC,CAEA0B,GAAO,IAAO,KACR/B,GAAM,GAAIgC,IAAW,OAAO,WAAW,eAAe,EAAE,QAAO,OAEpE5B,EAEE,OAAO,WAAW,eAAe,EAAE,SAAW,OAAO,WAAa,IAEhE,IAAA6B,EAAU,GACR,MAAAC,MAAe,qBAClB,CAAA,CAAAC,CAAK,IAAM,CACRA,EAAM,gBAAc,CAAKF,GAC5BA,EAAU,GACV5B,EAAI,IACO8B,EAAM,gBAAkBF,IACnCA,EAAU,GACV,qBAAqB/B,CAAM,EAE7B,EACE,CAAA,UAAW,CAAC,GAEf,OAAAgC,EAAS,QAAQjC,CAAM,EAEV,IAAA,CACZiC,EAAS,WAAU,EACnB,qBAAqBhC,CAAM,CAC5B,CACD,CAAC,MAGDkC,EAAMC,GAAA,KAAND,EAAME,GAAYrC,EAAMqC,EAAA,IAANrC,CAAM,OAAxBmC,CAAM,MAFC,2GC9KR,UAKO,IAAApC,mBAAS,EAAK,EAchBC,EACAsC,EAAa,CAAA,EACbrC,EACAC,EAAO,EACPC,EAAW,GAEN,SAAAoC,GAAc,QAErB,EAAG,GAAK,KAAK,OAAM,EAAK,GACxB,EAAG,GAAK,KAAK,OAAM,EAAK,GACxB,KAAM,EAAI,KAAK,OAAM,EAAK,EAC1B,MAAO,GAAM,KAAK,OAAM,EAAK,IAC7B,QAAS,GAAM,KAAK,OAAM,EAAK,GAC/B,SAAU,KAAK,OAAM,EAAK,KAAK,GAAK,EACpC,UAAW,KAAK,OAAM,EAAK,IAAO,IAClC,KAAM,EACN,QAAS,IAAM,KAAK,SAAW,IAEjC,CAES,SAAAC,EAASnC,EAA+BoC,EAAYC,EAAYC,EAAWC,EAAaC,EAAe,CAC/GxC,EAAI,KAAI,EACRA,EAAI,UAAUoC,EAAIC,CAAE,EACpBrC,EAAI,OAAOuC,CAAG,EAGR,MAAAE,EAAOzC,EAAI,qBAAqB,EAAG,EAAG,EAAG,EAAG,EAAGsC,EAAI,CAAC,EAC1DG,EAAK,aAAa,EAAC,qBAAuBD,EAAQ,GAAI,GAAA,EACtDC,EAAK,aAAa,EAAG,sBAAsB,EAC3CzC,EAAI,UAAYyC,EAChBzC,EAAI,SAAQ,CAAEsC,EAAI,EAAC,CAAGA,EAAI,EAAGA,EAAI,EAAGA,EAAI,CAAC,EAGzCtC,EAAI,UAAS,UACJM,EAAI,EAAGA,EAAI,EAAGA,IAAK,CACrB,MAAAoC,EAASpC,EAAI,KAAK,GAAM,EACxBqC,EAAK,KAAK,IAAID,CAAK,EAAIJ,EACvBM,EAAK,KAAK,IAAIF,CAAK,EAAIJ,EACvBO,EAAKH,EAAQ,KAAK,GAAK,EACvBI,GAAK,KAAK,IAAID,CAAE,EAAIP,EAAI,GACxBS,GAAK,KAAK,IAAIF,CAAE,EAAIP,EAAI,GAC1BhC,IAAM,EAAGN,EAAI,OAAO2C,EAAIC,CAAE,EACzB5C,EAAI,OAAO2C,EAAIC,CAAE,EACtB5C,EAAI,OAAO8C,GAAIC,EAAE,CAClB,CACA/C,EAAI,UAAS,EACbA,EAAI,UAAS,qBAAwBwC,CAAK,IAC1CxC,EAAI,KAAI,EAERA,EAAI,QAAO,CACZ,CAES,SAAAD,GAAO,KACVJ,EAAM,OAMP,GALJE,IAKIC,GAAYD,EAAO,IAAM,EAAG,CAC/BD,EAAS,sBAAsBG,CAAI,QAEpC,CAEM,MAAAC,EAAML,EAAO,WAAW,IAAI,MAC7BK,EAAG,aAEFC,EAAIN,EAAO,YACXO,EAAIP,EAAO,cACbA,EAAO,QAAUM,GAAKN,EAAO,SAAWO,KAC3CP,EAAO,MAAQM,EACfN,EAAO,OAASO,GAEjBF,EAAI,UAAU,EAAG,EAAGC,EAAGC,CAAC,EAGpB+B,EAAM,OAAS,IAAMpC,EAAO,KAAO,GACtCoC,EAAM,KAAKC,GAAK,EAGR,QAAA5B,EAAI2B,EAAM,OAAS,EAAG3B,GAAK,EAAGA,IAAK,OACrC0C,EAAIf,EAAM3B,CAAC,EACjB0C,EAAE,GAAKA,EAAE,MACTA,EAAE,UAAYA,EAAE,SAChBA,EAAE,OAEI,MAAAC,EAAWD,EAAE,KAAOA,EAAE,QACtBR,EAAQQ,EAAE,SAAW,EAAIC,IAAa,EAAIA,GAC1CC,EAAQF,EAAE,MAAQ,IAAO,EAAIC,GAAY,IAEzCE,EAAMH,EAAE,EAAI,IAAO/C,EACnBmD,EAAMJ,EAAE,EAAI,IAAO9C,EAEzBiC,EAASnC,EAAKmD,EAAIC,EAAIF,EAAOF,EAAE,SAAUR,CAAK,GAE1CQ,EAAE,MAAQA,EAAE,SAAWA,EAAE,EAAC,KAC7Bf,EAAM,OAAO3B,EAAG,CAAC,CAEnB,CAEAV,EAAS,sBAAsBG,CAAI,CACpC,CAEA0B,GAAO,IAAO,KACR/B,GAAM,GAAIgC,IAAW,OAAO,WAAW,eAAe,EAAE,QAAO,OAEpE5B,EAEE,OAAO,WAAW,eAAe,EAAE,SAAW,OAAO,WAAa,IAEhE,IAAA6B,EAAU,GACV0B,EAAS,GACP,MAAAzB,MAAe,qBAClB,CAAA,CAAAC,CAAK,IAAM,CACR,GAAAA,EAAM,gBAAc,CAAKF,EAAS,CAChC,GAAA,CAAA0B,EAAQ,CACZA,EAAS,WACA/C,EAAI,EAAGA,EAAI,EAAGA,IAAK,CACrB,MAAA0C,EAAId,EAAK,EACfc,EAAE,KAAO,KAAK,OAAM,EAAKA,EAAE,QAAU,GACrCA,EAAE,EAAI,GAAK,KAAK,OAAM,EAAK,GAC3Bf,EAAM,KAAKe,CAAC,CACb,CACD,CACArB,EAAU,GACV5B,EAAI,CACL,MAAY8B,EAAM,gBAAkBF,IACnCA,EAAU,GACV,qBAAqB/B,CAAM,EAE7B,EACE,CAAA,UAAW,CAAC,GAEf,OAAAgC,EAAS,QAAQjC,CAAM,EAEV,IAAA,CACZiC,EAAS,WAAU,EACnB,qBAAqBhC,CAAM,CAC5B,CACD,CAAC,MAGDkC,EAAMC,GAAA,KAAND,EAAME,GAAYrC,EAAMqC,EAAA,IAANrC,CAAM,OAAxBmC,CAAM,MAFC,CCjJD,MAAMwB,GAAoB,CAChC,CACC,IAAK,SACL,KAAM,UACN,KAAMC,GAAI,QAAQ,EAClB,KAAMA,GAAI,yCAAyC,CAAA,EAEpD,CACC,IAAK,WACL,KAAM,YACN,KAAMA,GAAI,UAAU,EACpB,KAAMA,GAAI,mCAAmC,CAAA,EAE9C,CACC,IAAK,QACL,KAAM,KACN,KAAMA,GAAI,OAAO,EACjB,KAAMA,GAAI,sCAAsC,CAAA,CAElD,6pDCjCA,UA8BO,MAAAC,GAAY,mBAEdC,EAAOC,GAAO,EAAK,EAGnBC,EAAQD,GAAsB,IAAI,EAClCE,EAAUF,GAAiC,IAAI,EAC/CG,EAAcH,GAAiC,IAAI,EAExC,eAAAI,GAAO,CACrBC,EAAAN,EAAO,EAAI,EACXO,GACCR,GACAF,GAAkB,IAAKvC,GAAMA,EAAE,GAAG,CAAA,QAE7BlB,GAAI,EAGVoE,EAAAJ,CAAW,GAAE,MAAK,CAAG,cAAe,EAAI,CAAA,CACzC,UAESK,EAAKC,EAAiD,GACzDV,CAAI,IACTM,EAAAN,EAAO,EAAK,EACZW,GAAoBZ,GAAWW,CAAG,EAC9BA,IAAQ,UAAQF,EAAEL,CAAO,GAAE,MAAK,CAAG,cAAe,GAAI,EAC3D,CAES,SAAAS,GAAiB,CACzBH,EAAK,QAAQ,gBAEd,UAESI,EAAWC,EAAe,CAC9BA,EAAE,SAAWA,EAAE,eAAeL,EAAK,UAAU,CAClD,UAESM,EAAMD,EAAkB,GAC5Bd,CAAI,GAAIc,EAAE,MAAQ,UAAUL,EAAK,QAAQ,CAC9C,4BAGyBM,CAAK,MAE9BC,EAAGC,GAAAC,CAAA,EACFC,EAAAC,EADDJ,CAAG,EACFK,EAAAD,EAAAD,CAAA,OAAAG,EAAAH,CAAA,KAAAA,EAAA5C,GAAA+B,EAGWH,WAAAA,CAAO,CAAA,IAJnBa,CAAG,UAAHA,EAAG,CAAA,aAmBF,IAAAO,EAAAC,GAAA,EAMCC,EAAAL,EANDG,CAAA,EAeEG,EAAGC,EAAAP,EATJK,CAAA,EAAA,CAAA,EAUEG,IADDF,CAAG,EAEDG,IADDD,CAAG,OACFC,EAAE,EAAA,IAAFA,CAAE,EACF,IAAAC,KADAD,EAAE,CAAA,OACFC,GAAC,EAAA,IAADA,EAAC,IAFFF,CAAG,EAIH,IAAAG,GAAAJ,EAJAC,EAAG,CAAA,KAIHG,GAAAxD,IAAA+B,EAGWF,YAAAA,CAAW,CAAA,IARvBsB,CAAG,EAsBH,IAAAM,KAtBAN,EAAG,CAAA,KAsBHM,GAAG,GAAA,IACInC,GAAqBvC,IAAMA,GAAE,IAAG,CAAA2E,GAAX3E,GAACT,KAAA,CAC3B,IAAAqF,GAAAC,GAAA,EASCC,GAAIhB,EATLc,EAAA,OASCE,EAAI,EAAgBC,GAAIC,GAAA,YAAO,OAAA9B,EAAAlD,EAAC,EAAC,SAAjC8E,EAAI,EACJ,IAAAG,KADAH,GAAI,CAAA,EAEHI,KADDD,EAAI,OACHC,GAAI,EAAA,IAAJA,EAAI,EACJ,IAAAC,KADAD,GAAI,CAAA,OACJC,GAAI,EAAA,IAAJA,EAAI,IAFLF,EAAI,WAAJA,GAAI,CAAA,mBAKHG,GAAIC,GAAA,OAAJD,EAAI,eAEJE,GAAIC,GAAA,OAAJD,EAAI,EAAeP,GAAIS,GAAA,CAAA,KAAA,eAAA,CAAA,IAAvBF,EAAI,OAAJA,EAAI,eAHD1C,CAAK,IAAAM,EAAKlD,EAAC,EAAC,IAAGyF,GAAAC,EAAA,EAAAD,GAAAE,GAAA,EAAA,IAdpB3B,EAAAY,EAAA,gBAAAA,GAAA,EAAA,SAAA1B,EACclD,EAAC,EAAC,KAAG,EAAA,GAAA,gBAAA,KADnB4E,GAAA,OAAA1B,EAEMlD,EAAC,EAAC,IAAI,EAFZ4F,GAAAhB,GAAA,YAAA1B,EAGWN,CAAK,IAAAM,EAAKlD,EAAC,EAAC,GAAG,0BAQLZ,EAAC8D,EAAClD,EAAC,EAAC,IAAI,MACRZ,EAAC8D,EAAClD,EAAC,EAAC,IAAI,CAAA,cAZ7B4E,GAAA,IAIe,GACdhC,EAAKM,EAAGlD,EAAC,EAAC,IAAG,EAAA,EACb6F,GAAkBpD,GAASS,EAAElD,EAAC,EAAC,IAAGkD,EAAE3D,EAAC,EAAG,CAAC,CAC1C,CAAC,EAPDuG,EAAAnB,GAAAC,EAAA,MAFFF,EAAG,EAyBH,IAAAqB,KAzBArB,GAAG,CAAA,OAyBHqB,GAAM,EAAA,IAANA,EAAM,EAxDP/B,EAAAG,CAAA,EANDH,EAAAC,CAAA,sCAoBG2B,GAAAnB,GAAA,aAAAuB,EAAA,aAHuB,IAAA5G,EAAE,2BAA2B,EAChD,IAAAA,EAAE,2DAA2D,EAOrD,IAAAA,EAAE,OAAO,EAsCpB,IAAAA,EAAE,0BAA0B,IA/DhC6G,GAAA,QAAAhC,EAGSV,CAAU,aAiBhBkB,GAAA,IAIetB,EAAK,OAAO,CAAA,EAsC5B8C,GAAA,QAAAF,GAA6CzC,CAAc,OAxD5Da,EAAA,IAAA+B,GAAA,KAAA,CAMkB,EAAG,IAAK,SAAU,IAAK,OAAQC,EAAQ,EAAA,OAZ1DlC,EAAA,IAAAiC,GAAA,KAAA,CAIkB,SAAU,GAAG,EAAA,EAJ/BJ,EAAAnB,EAAAV,CAAA,aAHGvB,CAAI,GAAA+C,EAAAW,CAAA,UAfPR,GAAA/B,EAAA,gBAAAX,EAMeR,CAAI,CAAA,oBAElB,CAAA,IAAAtD,EAAE,wCAAwC,CAAA,GAR3C6G,GAAA,QAAApC,EAISd,CAAI,cATP,0qNCtER,UAuDE,IAAAsD,oBAAU,MAAM,EAIhBC,uBAAc,OAAO,QAKhBC,EAAIC,GAAA,IAAYC,GAASJ,GAAO,CAAA,CAAA,EAMhCK,EAAWC,GAA2B,MAKxCC,EAAOjE,GAAa,QAAQ,EAC5BkE,EAAOlE,GAAa,OAAO,EAC3BmE,EAAanE,GAAO,aAGfoE,EAAQC,EAAe,CAC/BhE,EAAA4D,EAAOI,EAAO,EAAA,EACR,MAAAC,EAAG,IAAO,IAAIC,GAAK,GAAG,EAI3BD,EAAI,aAAa,IAAI,OAAQD,CAAO,EAErCG,GAAaF,EAAG,EAAA,CACjB,CAGI,IAAAG,EAAgB,GAGpBC,GAAO,IAAO,GACTT,CAAI,IAAK,SACZU,GAAW,IAAGpE,EAAC2D,CAAI,CAAA,EAEnBS,GAAW,IAAI,IAAI,CAErB,CAAC,EAMDD,GAAO,IAAO,CACP,MAAAE,IAAMX,CAAI,IAAK,UAAQ1D,EAAI0D,CAAI,IAAK,OAC1C,gBAAS,KAAK,UAAU,OAAO,aAAcW,CAAG,EACnC,IAAA,SAAS,KAAK,UAAU,OAAO,YAAY,CACzD,CAAC,EAGDC,GAAS,IAAO,CACVJ,GAAeE,GAAW,IAAI,IAAI,CACxC,CAAC,MAEGG,EAAW9E,GAAO,EAAK,EACvB+E,EAAa/E,GAAO,EAAK,EACzBgF,EAAahF,GAAO,IACpBiF,EAAejF,GAAoB,IAAI,EAGvCkF,EAAYlF,GAAgC,IAAI,EAChDmF,EAAcnF,GAAO,EAAE,EACvBoF,EAAYpF,GAAO,EAAI,EAKrB,MAAAqF,EAAU,GAEVC,WAAcpB,CAAI,IAAK,QAAU,aAAe,aAAa,EAE7DqB,EAAkB,EAAI,KAAO,KAC7BC,EAAgB,QAKlBC,EAAgBzF,GAAoB,IAAI,EACxC0F,EAAmB1F,GAAsB,IAAI,EAI3C,MAAA2F,GAAe,4BACfC,GAAkB,GAAK,KAAO,KAC9BC,GAAgB,YAGbC,GAAkBC,EAAiC,YAChD,QAASC,GAAY,CACzB,MAAA1B,EAAM,IAAI,gBAAgByB,CAAC,EAC3BE,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,QAAU,WACZA,EAAE,MAAQ,SACJC,EAAQC,IAAqB,CAClC,IAAI,gBAAgB7B,CAAG,EACvB0B,EAAQG,EAAC,CACV,EACM1J,EAAI,WAAU,IAAOyJ,EAAK,IAAI,EAAG,GAAM,EAC7CD,EAAE,iBAAgB,IAAS,CAC1B,aAAaxJ,CAAC,EACdyJ,EAAK,OAAO,SAASD,EAAE,QAAQ,EAAIA,EAAE,SAAW,IAAI,CACrD,EACAA,EAAE,QAAO,IAAS,CACjB,aAAaxJ,CAAC,EACdyJ,EAAK,IAAI,CACV,EACAD,EAAE,IAAM3B,CACT,CAAC,CACF,gBAEe8B,GAAiBvF,EAAU,CACnC,MAAAkF,EAAKlF,EAAE,OAA4B,QAAQ,CAAC,EAC7C,GAAA,CAAAkF,KAAKf,CAAU,EAAA,UACpB3E,EAAA8E,EAAc,EAAE,GACXQ,GAAa,MAAM,GAAG,EAAE,SAASI,EAAE,IAAI,EAAG,GAC9CZ,EAAc1I,EAAE,+BAA+B,EAAA,EAAA,EAC/C4J,GAAe,QAEhB,CACI,GAAAN,EAAE,KAAOH,GAAiB,GAC7BT,EAAc1I,EAAE,8BAA8B,EAAA,EAAA,EAC9C4J,GAAe,QAEhB,CACAhG,EAAA2E,EAAa,EAAI,QACXsB,EAAG,MAASR,GAAkBC,CAAC,KACrC1F,EAAA2E,EAAa,EAAK,EACdsB,IAAQ,KAAM,GACjBnB,EAAc1I,EAAE,iDAAiD,EAAA,EAAA,EACjE4J,GAAe,QAEhB,IACIC,EAAMT,GAAe,CACxBxF,EAAA8E,EAAc1I,EAAE,6BAA4B,CAAI,EAAGoJ,EAAa,CAAA,EAAA,EAAA,EAChEQ,GAAe,QAEhB,CACAhG,EAAAoF,EAAgBM,EAAC,EAAA,EACjB1F,EAAAqF,EAAmB,KAAK,MAAMY,CAAG,EAAA,EAAA,EACjCjG,EAAA4E,EAAe,IAAI,EACnBsB,GAA0BhG,EAACqD,CAAI,CAAA,EAC/BQ,EAAQ,MAAM,EACdoC,GAA0B,SAAQ5C,CAAI,CAAA,CACvC,CAEe,eAAA6C,IAAsC,CAC/C,GAAA,CAAAlG,EAAAkF,CAAa,SAAS,KACvB,GAAA,OAGG7G,EAAC,MAAS,MAAM,uBAAsB,CAC3C,OAAQ,OACR,QAAO,CAAI,eAAgB,kBAAkB,EAC7C,KAAM,KAAK,UAAS,CAAG,SAAQ2B,EAAEkF,CAAa,EAAC,KAAM,KAAIlF,EAAEkF,CAAa,EAAC,SAEpEiB,EAAI,MAAS9H,EAAE,KAAI,MACpBA,EAAE,IAAE,CAAK8H,EAAK,WAAS,CAAKA,EAAK,KACrCC,OAAAA,GAAyB,CACxB,MAAOD,EAAK,OAAS,oBACrB,QAAS,aACT,MAAO,KAED,KAEF,MAAAE,EAAM,MAAS,MAAMF,EAAK,UAAS,CACxC,OAAQ,MACR,QAAO,CAAI,eAAcnG,EAAEkF,CAAa,EAAC,IAAI,EAC7C,KAAIlF,EAAEkF,CAAA,WAEFmB,EAAO,GAQLF,EAAK,MAPXC,GAAyB,CACxB,MAAK,cAAgBC,EAAO,MAAM,GAClC,QAAS,aACT,MAAO,KAED,KAGT,OAASC,EAAK,CACP,MAAAC,EAAUD,aAAe,SAAWA,EAAI,IAAI,KAAKA,EAAI,OAAO,GAAK,OAAOA,CAAG,EACjFF,OAAAA,GAAyB,CAAG,MAAOG,EAAS,QAAS,aAAc,MAAO,GAAK,EACxE,IACR,CACD,gBASeC,GAAcC,EAA2B,CAC5C,OAAA,IAAA,QAAO,CAAEhB,EAASiB,IAAW,CACjC,MAAAC,MAAU,MACV5C,EAAM,IAAI,gBAAgB0C,CAAI,EACpCE,EAAI,OAAM,SAAe,CACxB,IAAI,gBAAgB5C,CAAG,EAGjB,GAAA,CAAA,aAAc/H,EAAG,cAAeC,EAAC,EAAK0K,EACxC,GAAA3K,EAAIiJ,GAAiBhJ,GAAIgJ,EAAe,OACrChG,GAAQgG,EAAgB,KAAK,IAAIjJ,EAAGC,EAAC,EAC3CD,EAAI,KAAK,MAAMA,EAAIiD,EAAK,EACxBhD,GAAI,KAAK,MAAMA,GAAIgD,EAAK,CACzB,CAEM,MAAAvD,GAAS,SAAS,cAAc,QAAQ,EAC9CA,GAAO,MAAQM,EACfN,GAAO,OAASO,GACJP,GAAO,WAAW,IAAI,EAC9B,UAAUiL,EAAK,EAAG,EAAG3K,EAAGC,EAAC,EAGzB,IAAA2K,GAAU,IACVC,GAAoB,UACjBD,GAAU,KAChBC,GAAI,MAAA,IAAa,QAAsBxI,IAAM3C,GAAO,OAAO2C,GAAG,aAAcuI,EAAO,CAAA,EAC/E,EAAAC,IAAQA,GAAK,MAAQ7B,KACzB4B,IAAW,GAIXnB,EADGoB,OACS,KAAI,CAAEA,EAAI,EAAGJ,EAAK,KAAK,QAAQ,WAAY,MAAM,EAAA,CAAK,KAAM,YAAY,CAAA,EAE5EA,CAF4E,CAItF,EACAE,EAAI,QAAO,IAAS,CACnB,IAAI,gBAAgB5C,CAAG,EACvB2C,EAAM,IAAK,MAAM,qBAAqB,CAAA,CACvC,EACAC,EAAI,IAAM5C,CACX,CAAC,CACF,gBAIe+C,GAAWL,EAAwB,CAM5C,GAAA,CAAAA,KAAQhC,CAAU,EAAA,OACvB3E,EAAA2E,EAAa,EAAI,EACjB3E,EAAA8E,EAAc,EAAE,MACZmC,EACA,GAAA,CAOHA,EAAQ,MAASC,GAChBR,GAAa,MAAOS,GAAU,MAAOC,GAAWT,CAAI,CAAA,CAAA,EACpDU,EAAA,CAEF,OAASb,EAAK,OAKPc,EAAWd,aAAe,OAASA,EAAI,UAAY,mBACzD1B,EAAcwC,EACXlL,EAAE,uDAAuD,EACzDA,EAAE,iDAAiD,MACtDkK,GAAyB,CACxB,MAAOgB,EAAW,uBAAyB,sBAC3C,QAAS,SACT,MAAO,KAKRtB,GAAe,EACfhG,EAAA2E,EAAa,EAAK,QAEnB,CACA3E,EAAA4E,EAAeqC,EAAQ,EAAA,EACvBf,GAA0BhG,EAACqD,CAAI,CAAA,EAC/BvD,EAAA2E,EAAa,EAAK,EAClBZ,EAAQ,MAAM,EACdoC,GAA0B,SAAQ5C,CAAI,CAAA,CACvC,gBACegE,GAAW/G,EAAc,CACvCA,EAAE,eAAc,EAChBR,EAAAyE,EAAW,EAAK,EACV,MAAAuC,GAAWxG,EAAE,cAAc,MAAM,CAAC,CAAA,CACzC,UACSgH,GAAehH,EAAc,CACrCA,EAAE,eAAc,EAChBR,EAAAyE,EAAW,EAAI,EACfzE,EAAA0E,EAAa,EAAI,CAClB,CACS,SAAA+C,IAAkB,CAC1BzH,EAAAyE,EAAW,EAAK,EAChBzE,EAAA0E,EAAa,EAAK,CACnB,CAGM,MAAA2C,GAAoB,IAEjB,SAAAH,GAAelK,EAAe0K,EAAwB,CACnD,OAAA,IAAA,QAAO,CAAK/B,EAASiB,IAAW,OACpCxK,EAAI,WAAU,IAAOwK,MAAW,MAAM,gBAAgB,CAAA,EAAIc,CAAE,EAClE1K,EAAE,KACA4I,GAAM,CACN,aAAaxJ,CAAC,EACduJ,EAAQC,CAAC,CACV,EACCpF,GAAM,CACN,aAAapE,CAAC,EACdwK,EAAOpG,CAAC,CACT,EAEF,CAAC,CACF,CAGS,SAAAwF,IAAkB,CACf,GAAA,SAAA,SAAa,KACb,UAAA2B,KAAM,SAAS,iBAAmC,oBAAoB,EAChFA,EAAG,MAAQ,EAEb,gBAEeC,GAAYpH,EAAU,CAC9B,MAAAwG,GAAYxG,EAAE,OAA4B,QAAQ,CAAC,CAAA,CAC1D,CAIe,eAAAqH,IAAgB,WACpB,aACN,GAAA,OAEGd,EAAI,MADD,MAAS,MAAKe,EAAA,KAAM,YAAY,GAClB,KAAI,EAC3B9H,EAAA4E,EAAY,IAAO,KAAI,CAAEmC,CAAI,EAAG,aAAY,CAAI,KAAMA,EAAK,MAAQ,YAAY,CAAA,EAAA,EAAA,EAC/Eb,GAA0BhG,EAACqD,CAAI,CAAA,EAC/BQ,EAAQ,MAAM,EACdoC,GAA0B,SAAQ5C,CAAI,CAAA,CACvC,MAAQ,GACPuB,EAAc1I,EAAE,qDAAqD,EAAA,EAAA,CACtE,CACD,CAGe,eAAA2L,GAAWC,EAAgBC,EAAgC,CACnE,MAAAC,MAAS,SACH,SAAA,CAAAC,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAM,EAAGC,EAAG,OAAOC,EAAKC,CAAK,EAEnE/E,GAAO,IAAK,QAAQ6E,EAAG,OAAO,UAAW7E,IAAO,QAC9CgF,EAAQ,MAAS,MAAK,UAAWL,CAAM,GAAA,CAAM,OAAQ,OAAQ,KAAME,CAAE,CAAA,SACpEI,GAAW,MAAOD,EAAS,MAAI,CACvC,CAgBe,eAAAE,GAAYC,EAAU,OAAgC,CAC/D,GAAA,CAAAtI,EAAA0E,CAAY,SAAS,KACtB,GAAA,OAGK,KAAA6D,EAAM,MAAAC,CAAK,EAAA,MAAWC,GAAsBjF,EAAQxD,EAAE0E,CAAY,EAAE,MAAM,EAC7E,OAAA8D,GAGL,QAAQ,MAAM,iBAAkBA,EAAM,OAAO,EAC7CpC,GAAyB,CACxB,MAAOoC,EAAM,QACb,QAAAF,EACA,MAAOI,GAAiBF,CAAK,IAEvB,MATYD,CAUpB,OAASjC,EAAK,CAGP,MAAAC,EAAUD,aAAe,SAAWA,EAAI,IAAI,KAAKA,EAAI,OAAO,GAAK,OAAOA,CAAG,EACjF,eAAQ,MAAM,gBAAiBC,CAAO,EACtCH,GAAyB,CAAG,MAAOG,EAAS,QAAA+B,EAAS,MAAOI,GAAiBpC,CAAG,EAAA,EACzE,IACR,CACD,KAEIqC,GAAYlJ,GAAO,EAAK,EAEb,eAAAmJ,IAAc,CAOnB,GANTC,GAAyB7I,EAAC2D,CAAI,IAAEN,CAAI,CAAA,EAM3BuE,EAAA,KAAA,SAAOA,EAAA,KAAS,cAAgB,GAAO,CAC/CkB,GAAgC,uBAAuB,EAKjD,MAAAC,GAAK,wBAAuB,CAAI,aAAc,EAAI,CAAA,QAEzD,CAKI,GAAA/I,EAAAkF,CAAa,EAAE,CACR,GAAA,CAAA0C,EAAA,KAAA,QAAS,GAClBhD,EAAc1I,EAAE,0BAA0B,EAAA,EAAA,QAE3C,CACA4D,EAAA6I,GAAY,EAAI,EAChB7I,EAAA8E,EAAc,EAAE,EAChBoE,GAA4BhJ,EAAC2D,CAAI,IAAEN,CAAI,CAAA,EACjC,MAAA4F,QAAkB/C,GAAW,EAC9B,GAAA,CAAA+C,EAAW,GACfrE,EAAc1I,EAAE,kCAAkC,EAAA,EAAA,EAClD4D,EAAA6I,GAAY,EAAK,QAElB,OACMO,EAAM,MAASrB,GAAW,gBAAe,CAC9C,OAAAlE,CAAI,EACJ,UAAWsF,EACX,UAAW,QACX,QAAS,OAAOnE,CAAO,EACvB,UAAW,QACX,YAAa,OAAM9E,EAACmF,CAAgB,GAAI,EAAE,IAEvC,GAAA+D,EAAO,OAAS,UAAW,OAExBC,EADID,EAAO,MACO,aACxBhF,EAAgB,GACV,MAAA6E,mBAAqBI,CAAY,EAAA,QAExC,CACArJ,EAAA6I,GAAY,EAAK,QAElB,CAGS,GAAAf,EAAA,KAAA,QAAS,CACjB9H,EAAA6I,GAAY,EAAI,EAChB7I,EAAA8E,EAAc,EAAE,EAChBoE,GAA4BhJ,EAAC2D,CAAI,IAAEN,CAAI,CAAA,QACjC+F,EAAS,MAASf,GAAY,WAAW,EAC1C,GAAA,CAAAe,EAAW,GACfxE,EAAc1I,EAAE,uDAAuD,EAAA,EAAA,EAKvE4D,EAAA6I,GAAY,EAAK,QAElB,OACMO,EAAM,MAASrB,GAAW,gBAAe,CAAI,OAAAlE,CAAI,EAAE,UAAAyF,EAAW,UAAW,OAAMpJ,EAAC6E,CAAS,CAAA,EAAG,QAAS,OAAOC,CAAO,IACrH,GAAAoE,EAAO,OAAS,UAAW,OAExBC,EADID,EAAO,MACO,aACxBhF,EAAgB,GAQV,MAAA6E,mBAAqBI,CAAY,EAAA,QAExC,CACArJ,EAAA6I,GAAY,EAAK,QAElB,CAOA7I,EAAA6I,GAAY,EAAI,EAChB7I,EAAA8E,EAAc,EAAE,QACVwE,EAAS,MAASf,GAAY,MAAM,EACrC,GAAA,CAAAe,EAAW,GACfxE,EAAc1I,EAAE,uDAAuD,EAAA,EAAA,EACvE4D,EAAA6I,GAAY,EAAK,QAElB,CACI,GAAA,OACGO,EAAM,MAASrB,GAAW,qBAAuB,KAAI7H,EAAJ2D,CAAI,EAAE,UAAAyF,EAAS,EAClE,GAAAF,EAAO,OAAS,UAAW,OACxBtD,EAAIsD,EAAO,KACjBhF,EAAgB,SAEV6E,GAAI,gBAAiBnD,GAAG,YAAY,EAAA,QAE3C,OACMA,EAAIsD,EAAO,OAAS,UAAaA,EAAO,KAAmC,OAC7EtD,GAAG,QAAU,WAGhBhB,EAAc1I,EAAE,yEAAyE,EAAA,EAAA,EACzFmN,GAAc,OAAW,iBAAiB,GAE1CvJ,EAAA8E,EAAegB,GAAG,OAAoB1J,EAAE,kCAAkC,EAAA,EAAA,CAE5E,MAAQ,GACP0I,EAAc1I,EAAE,sDAAsD,EAAA,EAAA,CACvE,CACA4D,EAAA6I,GAAY,EAAK,CAClB,CAOAW,GAAa,IAAO,CACb,MAAAvF,EAAG,IAAO,IAAIC,GAAK,GAAG,EACvB,CAAAD,EAAI,aAAa,IAAI,MAAM,GAAA,CAAMA,EAAI,aAAa,IAAI,cAAc,IACzEA,EAAI,aAAa,OAAO,MAAM,EAC9BA,EAAI,aAAa,OAAO,cAAc,EACtC,eAAc,IAAOE,GAAaF,EAAG,CAAA,CAAA,CAAA,EACtC,CAAC,+CAaDwF,EAAO9I,GAAA+I,CAAA,EAGNhJ,MAHD+I,CAAO,EAAA,CAAA,MAGN/I,CAAG,kBAaDO,GAAGY,GAAA,EACF8H,KADD1I,EAAG,OACF0I,EAAE,oCAEkB7H,GAAIT,EAAAN,EAAA,CAAA,MAAJe,GAAI,EAAA,IAAJA,EAAI,2BAAtB,CAAA,IAAA1F,EAAE,OAAO,EAAA,IAAkCA,EAAE,gBAAgB,CAAA,wCAEnC6F,GAAIZ,EAAAuI,EAAA,CAAA,MAAJ3H,GAAI,EAAA,IAAJA,EAAI,2BAA9B,CAAA,IAAA7F,EAAE,eAAe,EAAA,IAAkCA,EAAE,kBAAkB,CAAA,2BAH/D,oBAAmBqG,EAAAC,EAAA,EAAAD,EAAAE,GAAA,EAAA,MAD7BgH,EAAE,EAOF,IAAAnI,KAPAmI,GAAE,CAAA,OAOFnI,EAAC,sCAEC,IAAApF,EAAE,yHAAwH,CAAI,MAAOyN,EAAiB,CAAA,2CAEtJ,IAAAzN,EAAE,uFAAsF,CAAI,MAAOyN,EAAiB,CAAA,4BAH5G,oBAAmBpH,EAAAW,EAAA,EAAAX,EAAAqH,GAAA,EAAA,MAD7BtI,EAAC,EAOD,IAAAL,KAPAK,GAAC,CAAA,OAODL,EAAG,yBAEDS,EAAAjB,GAAAoJ,CAAA,EAAAC,GAAAlJ,EAAAc,EAAA,EAAA,EAAAZ,EAAAY,CAAA,MAMAqI,EAAA5I,EANAO,EAAA,CAAA,EAMAsI,EAAApJ,EAAAmJ,EAAA,EAAA,EAAAjJ,EAAAiJ,CAAA,YANArH,GAAAhB,EAAA,OAAA,gBAAAkG,EAAA,KAC2B,mBAAmB,EAAA,kBAG7C,CAAA,IAAA1L,EAAE,kBAAkB,EAAA,IAMpBA,EAAE,gBAAgB,CAAA,6BAGnB+N,EAAAxJ,GAAAyJ,CAAA,EAAAC,GAAAvJ,EAAAqJ,EAAA,EAAA,EAAAnJ,EAAAmJ,CAAA,EAAA,IAAAG,EAAAjJ,EAAA8I,EAAA,CAAA,aAOC,IAAAI,EAAAC,GAAA,EAAAC,GAAA3J,EAAAyJ,EAAA,EAAA,EAAAvJ,EAAAuJ,CAAA,SAAA3H,GAAA2H,EAAA,OAAA,gBAAAzC,EAAA,KAC2B,gBAAgB,EAAA,YAG1C,CAAA,IAAA1L,EAAE,wBAAwB,CAAA,GAJ3B0G,EAAAnB,EAAA4I,CAAA,kBADQ,kBAAgB9H,EAAAiI,CAAA,IAFxBC,EAAAC,GAAAC,EAAAR,GAAAO,CAAA,EAAA,CAAA,IAAAxO,EAAE,gBAAgB,CAAA,CAAA,0BAlBX,oBAAmBqG,EAAAqI,EAAA,EAAArI,EAAAsI,GAAA,EAAA,MAD7B5J,EAAG,IAfJF,EAAG,OAAHA,EAAG,iDAiDH+J,EAACC,GAAA,EACA/I,IADD8I,CAAC,EACqCE,IAArChJ,CAAI,OAAiCgJ,EAAM,EAAA,IAANA,CAAM,WAANA,CAAM,YAA2H/I,EAAId,EAAA8J,CAAA,MAAJhJ,EAAI,EAAA,IAAJA,CAAI,IAA1KD,CAAI,UADL8I,CAAC,6BACoE,MAAM,mDAAY,IAAA5O,EAAE,oBAAoB,EAA0C,IAAAA,EAAE,UAAU,EAA6B,IAAAA,EAAE,8BAA6B,CAAI,MAAOyN,EAAiB,CAAA,QAD3PmB,CAAC,oBADQ,eAAYlD,EAAA,KAAU,QAAU,GAAK,KAAEA,EAAA,KAAU,QAAU,GAAK,GAACrF,EAAA2I,EAAA,4CAY3EC,GAAEhK,EAAAiK,GAAA,CAAA,OAAFD,EAAE,yBAAFA,EAAE,EAIF,IAAAE,KAJAF,GAAE,CAAA,OAIFE,EAAC,uBAADA,EAAC,EAID,IAAAnK,KAJAmK,GAAC,CAAA,SAKSC,EAAQ7J,GAAA,CAChB,IAAA8J,EAAAC,GAAA,EAWCC,EAAK7K,EAXN2K,CAAA,KAWCE,EAAK1N,GAAA+B,EAAqG6E,EAAS5G,CAAA,EAAA,IAAAiC,EAAT2E,CAAS,CAAA,WAAnH8G,EAAK,CAAA,yBAMJC,GAACvK,EAAAV,GAAAkL,CAAA,EAAA,CAAA,OAADD,GAAC,EAAA,IAADA,EAAC,EACD,IAAAE,KADAF,GAAC,CAAA,OACDE,GAAC,EAAA,IAADA,EAAC,kCAD4D,IAAA1P,EAAE,qBAAqB,EACrC,IAAAA,EAAE,mCAAmC,6BAEpFkF,GAAGX,GAAAoL,CAAA,EAKHC,KALA1K,GAAG,CAAA,OAKH0K,GAAC,EAAA,IAADA,EAAC,EACD,IAAAC,KADAD,GAAC,CAAA,OACDC,GAAC,EAAA,IAADA,EAAC,EACD,IAAAvK,KADAuK,GAAC,CAAA,EAEA7J,KADDV,EAAG,OACFU,GAAI,EAAA,IAAJA,EAAI,IADLV,EAAG,iBAPHwK,EAAA5K,GAAG,EAAA,8HAAApB,EAAoIwE,CAAU,EAAG,iBAAmB,EAAE,EAAA,+BAK5G,IAAAtI,EAAE,kBAAkB,EAClC,IAAAA,EAAE,mCAAmC,EAGlF,IAAAA,EAAE,aAAa,uBAjBduI,CAAU,EAAAlC,EAAA0J,EAAA,EAAA1J,EAAA2J,EAAA,EAAA,IAZfpL,EAAAyK,CAAA,SAAAS,EAAAT,EAAA,EAAA;AAAA,QAEEvL,EAAAyE,CAAA,EACC,uCACAzE,EAAAuE,CAAA,EACA,+FACA,qGAAqG,EAAA,EAKvGkH,aAAmFhH,CAAU,IAX9F0H,GAAA,OAAAZ,EAOQlE,EAAU,EAPlB8E,GAAA,WAAAZ,EAQYjE,EAAc,EAR1B6E,GAAA,YAAAZ,EASahE,EAAe,EAE3BxE,GAAA,SAAA0I,EAA4D/D,EAAW,EAXxE9E,EAAAnB,EAAA8J,CAAA,YAFFrK,EAAG,yBAuCe,OAAO,EACLkL,EAAA9I,GAAA,IAAAsE,EAAA,KAAA,cAAgB,IAAI,kBAIxB,QAAU,SAAW,QAAQ,EAN5CyE,GAAAC,GAAA,iFAGQlJ,EAAW,0FAKR,SAAAsC,IAAM6G,GAA+B7G,EAAC,EACjC,SAAA,IAAA,GAMXhB,CAAY,EAAEb,EAAQ,MAAM,EAC3BwF,GAAc,OAAW,YAAY,CAC3C,aACc,CAAEvJ,EAAA4E,EAAe,IAAI,CAAE,aACzBiD,uBACJ2D,OAbR,MAAS,UAAEzG,CAAS,OAApB,KAAS9G,GAAA,GAAE8G,EAAS9G,GAAA,EAAA,oCAiBnByO,EAACC,GAAA,MAADD,EAAC,EAAA,IAADA,CAAC,cAAkC5H,CAAW,CAAA,CAAA,MAA9C4H,CAAC,cADE5H,CAAW,GAAArC,EAAAmK,EAAA,6DASb,IAAAC,EAAAC,GAAA,EAGCC,EAAAjM,EAHD+L,CAAA,EAGCjK,GAAAmK,EAAA,SAEQzH,EAAY,EAMpB,IAAAhD,GAAIjB,EARJ0L,EAAA,CAAA,OAQAzK,EAAI,EAAmB0K,GAAC3L,EAAA4L,EAAA,OAADD,GAAC,EAAA,IAADA,EAAC,WAADA,EAAC,IAAxB1K,EAAI,EAXLtB,EAAA6L,CAAA,iBAGCE,EAAA,SAAA7M,EAKUyE,CAAU,mDAGd,IAAAvI,EAAE,WAAW,EAAyB,IAAAA,EAAE,OAAO,EAAQ,IAAAA,EAAE,eAAc,CAAI,EAAGoJ,EAAa,CAAA,IARjGvC,GAAA,SAAA8J,EAIUhH,EAAgB,EAP3BjD,EAAAnB,EAAAkL,CAAA,UAcA,IAAAhM,EAAAqM,GAAA,EAQCC,EAAI9L,EAAAP,EARLD,CAAA,EAAA,CAAA,OAQCsM,CAAI,EAA2BC,GAAC/L,EAAAgM,EAAA,OAADD,GAAC,EAAA,IAADA,EAAC,WAADA,EAAC,IAAhCD,CAAI,EARLnM,EAAAH,CAAA,kEAQO,IAAAzE,EAAE,mBAAmB,EAAyB,IAAAA,EAAE,KAAK,EAAQ,IAAAA,EAAE,SAAS,eAR/EyE,EAAA,IAEeoI,GAAK,uBAAuB,CAAA,EAF3CnG,EAAAnB,EAAAd,CAAA,kBAfQ,SAAQ4B,EAAA6K,EAAA,EAAA7K,EAAA8K,GAAA,EAAA,4BADT,SAAO9K,EAAA+K,CAAA,MApEjBpM,EAAG,EAkGH,IAAAqM,IAlGArM,GAAG,CAAA,QAkGHqM,CAAC,CAAA,IAADA,CAAC,WAADA,EAAC,CAAA,EASDC,GAAWC,GAAA,CAAA,SAAA,IAAAzN,EAAiB2E,CAAS,GAAE,MAAK,EAAA,EAL3C8F,EAAAC,GAAAC,EAAA+C,EAAA,IAAAhD,GAAA,EAAA,EAAA,EAAA,CAAA,IAAAxO,EAAE,8CAA8C,CAAA,CAAA,4BAtLxC,SAAO0L,EAAA,KAAS,cAAgB,GAAKrF,GAAAoL,CAAA,EAAApL,GAAAqL,GAAA,EAAA,MAD/CpN,CAAG,IAHJ+I,CAAO,WAAPA,EAAO,CAAA,+CA2MPsE,EAAOC,GAAA,EAINC,MAJDF,CAAO,EAAA,CAAA,EAKLG,IADDD,CAAG,MACFC,EAAE,EAAA,EACuBC,EAAI9M,EAAA+M,EAAA,CAAA,OAAJD,EAAI,EAAA,IAAJA,CAAI,IAD7BD,CAAE,EAGF,IAAAG,KAHAH,EAAE,CAAA,OAGFG,GAAC,EAAA,IAADA,EAAC,WAADA,GAAC,CAAA,kBAIAC,EAACC,GAAA,QAADD,CAAC,CAAA,IAADA,CAAC,2BAEA,IAAAlS,EAAE,iEAAgE,CAAI,EAAC8D,EAAEmF,CAAgB,GAAI,EAAE,CAAA,QAFhGiJ,CAAC,cADElJ,CAAa,GAAA3C,EAAA+L,EAAA,QAQjBC,GAAGpN,EAAAqN,GAAA,CAAA,EAGHC,KAHAF,EAAG,EAKFhN,GAAAX,EAFD6N,EAAG,EAQDC,GAAG9N,EANJW,EAAA,EAOEoN,KADDD,EAAG,EAEDE,KADDD,EAAG,EAEFE,KADAD,GAAG,CAAA,IADJD,EAAG,EAIH,IAAAG,KAJAH,GAAG,CAAA,IADJD,EAAG,EAOH,IAAAK,KAPAL,GAAG,CAAA,OAOHK,GAAC,EAAA,kBAADA,EAAC,EAbFjO,EAAAS,EAAA,MAiBAsB,EAAA1B,EAjBAI,GAAA,CAAA,EAuBCyN,EAAGpO,EANJiC,CAAA,EAOEoM,IADDD,CAAG,EAEDE,KADDD,CAAG,EAEFE,IADAD,GAAG,CAAA,IADJD,CAAG,EAIH,IAAAG,IAJAH,EAAG,CAAA,IADJD,CAAG,EAOH,IAAAK,IAPAL,EAAG,CAAA,MAOHK,CAAC,+EACwB,CAAA,IAAAnT,EAAE,OAAO,EAAA,IAASA,EAAE,QAAQ,CAAA,mFAAU,CAAA,IAAAA,EAAE,OAAO,EAAA,IAASA,EAAE,aAAa,CAAA,mBAA3FiH,GAAO,IAAK,OAAMZ,EAAA+M,EAAA,EAAA/M,EAAAgN,GAAA,EAAA,MADvBF,CAAC,EAbFvO,EAAA+B,CAAA,IAnBD4L,EAAG,EAuCH,IAAAe,EAAArO,EAvCAsN,GAAG,CAAA,EAuCHgB,EAAA7O,EAAA4O,CAAA,wBASE/E,EAAAC,GAAAC,EAAA+E,EAAAhF,CAAA,EAAA,CAAA,IAAAxO,EAAE,cAAc,CAAA,CAAA,yCAEhB,IAAA8D,EAAAkF,CAAa,EAAGhJ,EAAE,mBAAmB,EAAIA,EAAE,kBAAkB,sBAH1DyM,EAAS,EAAApG,EAAAoN,CAAA,EAAApN,EAAAqN,GAAA,EAAA,IARd9O,EAAA0O,CAAA,EAAA,IAAAK,GAAA1O,EAAAqO,EAAA,CAAA,kBAkBCM,EAACC,GAAA,MAADD,EAAC,EAAA,IAADA,CAAC,iBACA,IAAA5T,EAAE,6DAA6D,QADhE4T,CAAC,mBAJQ,SAAOvN,EAAAyN,EAAA,mCAShBC,EAACC,GAAA,MAADD,EAAC,EAAA,IAADA,CAAC,cAA8CrL,CAAW,CAAA,CAAA,MAA1DqL,CAAC,cADErL,CAAW,GAAArC,EAAA4N,EAAA,QAOfC,GAAGjP,EAAAkP,GAAA,CAAA,OAAHD,EAAG,cAID,IAAAE,EAAAC,GAAA,EAICC,EAAI5P,EAJL0P,CAAA,OAICE,EAAI,EAAA,IAAJA,CAAI,EACJ,IAAAC,KADAD,EAAI,CAAA,EAEHE,GAAA9P,EADD6P,EAAI,IAAJA,EAAI,EALL3P,EAAAwP,CAAA,kBAKCtE,EAAAyE,GAAI,EAAA,yEAAAzQ,EAA+E6E,CAAS,EAAG,UAAY,WAAW,EAAA,EACrHmH,EAAA0E,GAAA,EAAA;AAAA,YAEE7L,CAAS,EAAG,gBAAkB,iBAAiB,EAAA,GAJE,CAAA,IAAA3I,EAAE,2BAA2B,CAAA,GAJlF6G,GAAA,QAAAuN,EAAA,IAEe,CAAExQ,EAAA+E,KAAaA,CAAS,CAAA,EAAE0H,GAA8B,CAAAvM,EAAE6E,CAAS,CAAA,CAAG,CAAC,EAFtFjC,EAAAnB,EAAA6O,CAAA,mBADQ,SAAO/N,EAAAoO,EAAA,IAehB,IAAAC,GAAAzP,EAAA0P,GAAA,CAAA,EAAAC,GAAAlQ,EAAAgQ,EAAA,EAKCG,GAAI5P,EAAA2P,EAAA,OAAJC,GAAI,EAAA,IAAJA,EAAI,EALLjQ,EAAA8P,EAAA,IAlBDR,EAAG,WAAHA,GAAG,CAAA,cA4BF,IAAAY,EAAAC,GAAA,EAAAC,EAAAtQ,EAAAoQ,CAAA,cAGuBG,GAAa1P,EAAA,CAAA,OAAA,EAAA,CAAA,UAAkB2P,GAAa3P,EAAA,CAAA,OAAA,EAAA,CAAA,WAA9DzB,EAAA2D,CAAI,IAAK,QAAOpB,EAAA8O,EAAA,EAAA9O,EAAA+O,GAAA,EAAA,QACpBC,GAAGpQ,EAAA+P,EAAA,CAAA,EACFM,KADDD,EAAG,OACFC,GAAC,EAAA,IAADA,EAAC,EACD,IAAAC,KADAD,GAAC,CAAA,OACDC,EAAC,0CAEC,IAAAvV,EAAE,sIAAsI,gDAExI,IAAAA,EAAE,sIAAsI,gDAExI,IAAAA,EAAE,0IAA0I,sBALzI8D,EAAA2D,CAAI,IAAK,QAAOpB,EAAAmP,EAAA,EAEXvO,GAAO,IAAK,OAAMZ,EAAAoP,GAAA,CAAA,EAAApP,EAAAqP,GAAA,EAAA,MAH5BH,EAAC,EASD,IAAAI,KATAJ,GAAC,CAAA,OASDI,EAAG,0BAEDC,GAAIrR,GAAAsR,EAAA,OAAJD,EAAI,SAAJA,EAAI,EACJ,IAAAE,KADAF,GAAI,CAAA,OACJE,EAAI,EAAoBC,GAAM9Q,EAAA+Q,EAAA,OAAND,GAAM,EAAA,IAANA,EAAM,IAA9BD,EAAI,EACJ,IAAAG,KADAH,GAAI,CAAA,OACJG,EAAI,SAAJA,EAAI,wFAFE,IAAAjW,EAAE,YAAY,EACd,IAAAA,EAAE,YAAY,EAA+B,IAAAA,EAAE,MAAM,EACrD,IAAAA,EAAE,SAAS,gCAEjBkW,GAAI3R,GAAA4R,EAAA,OAAJD,EAAI,SAAJA,EAAI,EACJ,IAAAE,KADAF,GAAI,CAAA,OACJE,EAAI,SAAJA,EAAI,qDADE,CAAA,IAAApW,EAAE,YAAY,EAAA,IACdA,EAAE,iBAAiB,CAAA,qBANtB8D,EAAA2D,CAAI,IAAK,QAAOpB,EAAAgQ,EAAA,EAAAhQ,EAAAiQ,GAAA,EAAA,MADrBX,EAAG,IAXJN,EAAG,EAJJzQ,EAAAkQ,CAAA,UAAAA,EAAA,EAAA,oEAAAhR,EACyE2D,CAAI,IAAK,QAAU,iCAAmC,kCAAkC,EAAA,EAI/JqI,EAAAwF,8DAA8D7N,CAAI,IAAK,QAAU,gBAAkB,gBAAgB,EAAA,UACnHqI,EAAAyF,6CAA6C9N,CAAI,IAAK,QAAU,gBAAkB,gBAAgB,EAAA,EASlGqI,EAAA6F,sCAAwClO,CAAI,IAAK,QAAU,gBAAkB,gBAAgB,EAAA,GAV0B,CAAA,IAAAzH,EAAE,qBAAoB,CAAI,OAAAyH,CAAI,EAAA,CAAA,GALvJf,EAAAnB,EAAAuP,CAAA,cADGpN,CAAU,GAAArB,EAAAkQ,EAAA,MAlGdlE,EAAG,IAfJR,CAAG,IAJJF,CAAO,8BAMoB7B,EAAAiC,SAAYlJ,CAAE,CAAA,CAAA,oBAkBtCxD,GAAA,EAAA,wGAAAvB,EAC6G2D,CAAI,IAAK,QACnH,iCACA,gDAAgD,EAAA,EAKhDqI,EAAA4C,wCAA0CjL,CAAI,IAAK,QAAU,GAAK,YAAY,EAAA,EAC9EqI,EAAA6C,8DAAiElL,CAAI,IAAK,QAAU,aAAe,YAAY,EAAA,EAEhHqI,EAAA8C,iDAAoDnL,CAAI,IAAK,QAAU,gBAAkB,eAAe,EAAA,EAEzGqI,EAAA+C,+FAA+FpL,CAAI,IAAK,QAAU,aAAe,cAAc,EAAA,sBAIhJd,EAAA,EAAA,wGAAA7C,EAC6G2D,CAAI,IAAK,OACnH,mCACA,gDAAgD,EAAA,EAKhDqI,EAAAkD,yCAA2CvL,CAAI,IAAK,OAAS,GAAK,YAAY,EAAA,EAC9EqI,EAAAmD,6DAAiExL,CAAI,IAAK,OAAS,cAAgB,YAAY,EAAA,EAEhHqI,EAAAoD,gDAAoDzL,CAAI,IAAK,OAAS,iBAAmB,eAAe,EAAA,EAEzGqI,EAAAqD,8FAA+F1L,CAAI,IAAK,OAAS,cAAgB,cAAc,EAAA,EAOjJqI,EAAAwD,EAAA,EAAA;AAAA,MAEExP,EAAA2D,CAAI,IAAK,QACR,0CACA,sCAAsC,EAAA,EAJzC6L,EAAA,SAAAxP,EAMU2I,EAAS,4BA8CQ/E,CAAU,EAAG,IAAM,GAAG,IA3GhD,IAAA1H,EAAE,aAAa,EAA0B,IAAAA,EAAE,UAAU,EAGrD,IAAAA,EAAE,yCAAyC,EA4ByG,IAAAA,EAAE,OAAO,EAAS,IAAAA,EAAE,eAAe,QA2EtLyH,CAAI,IAAK,QAAUzH,EAAE,oBAAoB,EAAIA,EAAE,mBAAmB,eAxFnEqF,GAAA,IAAAzB,EAIgB6D,EAAO,OAAO,CAAA,aAa9Bd,EAAA,IAAA/C,EAIgB6D,EAAO,MAAM,CAAA,EAgB9BZ,GAAA,QAAAyM,EAKS5G,EAAW,aA0CnBgI,GAAA,IAAA9Q,EAEgB8D,KAAcA,CAAU,CAAA,CAAA,MA9G3CiK,CAAO,YArNH7N,EAAA0D,CAAI,IAAK,SAAQnB,EAAAmQ,EAAA,EAAA1S,EAgNZ0D,CAAI,IAAK,QAAMnB,EAAAoQ,GAAA,CAAA,iBAlNjB,wKCxlBR,gBAaOC,GAAkC,CACvC,KAAMtT,GAAI,MAAM,EAChB,MAAOA,GAAI,OAAO,EAClB,IAAKA,GAAI,KAAK,EACd,MAAOA,GAAI,OAAO,GAInB,IAAAuT,EAAA/U,GAAA,EAAAgV,GAAAD,EAAA,GAAA,IAIOE,GAAiBhU,GAAGA,KAAHA,IAAC,CACvB,IAAA2C,EAAAV,GAAA,EAAAH,EAAAD,EAAAc,EAAA,EAAA,EAAAZ,EAAAY,CAAA,WAAAA,EAAA,OACMsR,GAAkBjU,CAAC,CAAA,EADzB2D,GAAAhB,EAAA,eAAAkG,EAAA,SAEyB7I,EAAI,OAAS,MAAS,IAF/C2C,EAAA,EAAA,yIAAAkG,EAAA,SAIA7I,EACG,4DACA,4BAA4B,EAAA,eAE9B7C,EAAE0W,GAAM7T,CAAC,CAAA,CAAA,GARV6D,EAAAnB,EAAAC,CAAA,IALFZ,EAAA+R,CAAA,UAAAA,EAAA,aAAAnI,CAAA,EAAA,CAAA,IACYxO,EAAE,cAAc,CAAA,CAAA,EAD5B0G,EAAAnB,GAAAoR,CAAA,MAFO","names":["mobile","canvas","animId","tick","isMobile","loop","ctx","w","h","t","resolution","points","i","xRatio","x","wave1","wave2","wave3","wave4","edgeFalloff","finalHeight","p","ambientGrad","curr","next","cpx","cpy","flameGrad","innerPoints","innerGrad","edgeGrad","onMount","browser","running","observer","entry","canvas_1","root","$$value","stars","spawn","drawStar","cx","cy","r","rot","alpha","grad","angle","ox","oy","ia","ix","iy","s","progress","scale","px","py","seeded","NO_PHOTO_PRODUCTS","msg","PLACEMENT","open","$.state","going","trigger","closeButton","show","$.set","trackOfferShown","$.get","hide","how","trackOfferDismissed","uploadAfterAll","onBackdrop","e","onKey","div","$.first_child","fragment","button","$.child","text","$.reset","div_1","root_1","div_2","div_3","$.sibling","div_4","h2","p_1","button_1","div_5","$$anchor","a","root_2","span","Icon","node_1","span_1","span_2","span_3","span_4","root_3","span_5","root_4","node_3","$$render","consequent","alternate","$.set_attribute","trackOfferClicked","$.append","button_2","$2","$.delegated","fly","cubicOut","consequent_1","subject","reuseOthers","flow","$.derived","rateFlow","supabase","createSupabaseBrowserClient","step","mode","showSample","setStep","newStep","url","page","replaceState","goingToResult","$.user_effect","activeMode","fit","onDestroy","dragOver","iconBounce","processing","selectedFile","fileInput","uploadError","savePhoto","csamAck","ac","MAX_IMAGE_BYTES","MAX_DIMENSION","selectedVideo","videoDurationSec","VIDEO_ACCEPT","MAX_VIDEO_BYTES","MAX_VIDEO_SEC","readVideoDuration","f","resolve","v","done","d","handleVideoInput","resetFileInputs","dur","analytics.trackPhotoUpload","analytics.trackFunnelStep","uploadVideo","body","analytics.trackUploadFail","putRes","err","message","compressImage","file","reject","img","quality","blob","handleFile","prepared","withTimeout","heicToJpeg","detachFile","DECODE_TIMEOUT_MS","timedOut","handleDrop","handleDragOver","handleDragLeave","ms","el","handleInput","useSavedPhoto","$$props","callAction","action","fields","fd","key","value","response","deserialize","uploadImage","context","path","error","uploadSubmissionPhoto","isStaleFileError","analyzing","startRating","analytics.trackModeSelect","analytics.trackUpgradeModalOpen","goto","analytics.trackAnalysisStart","videoPath","result","generationId","imagePath","openAuthSheet","afterNavigate","section","fragment_1","h1","text_2","PRO_MONTHLY_LABEL","alternate_1","fragment_6","text_6","a_1","text_7","a_2","fragment_7","text_8","node_5","a_3","root_9","text_9","consequent_3","$.template_effect","$0","$.set_text","consequent_2","alternate_2","a_4","root_11","strong","text_12","consequent_5","h1_1","node_7","p_2","dropzone","label","root_12","input","p_3","fragment_9","p_4","fragment_10","p_5","p_6","$.set_class","consequent_6","alternate_3","$.event","$1","ReusePhoto","node_11","analytics.trackSavePhotoToggle","p_7","root_15","consequent_7","label_1","root_17","input_1","b","text_20","root_18","span_6","b_1","text_23","consequent_8","alternate_4","consequent_9","p_8","NotNowSheet","node_15","text_26","consequent_4","alternate_5","section_1","root_19","div_6","h1_2","span_7","text_27","p_9","p_10","root_20","consequent_11","div_7","node_17","div_8","div_9","div_10","div_11","span_8","span_9","p_11","div_12","div_13","div_14","span_10","span_11","p_12","consequent_12","alternate_6","button_3","node_19","text_37","consequent_13","alternate_7","node_20","p_13","root_25","consequent_14","p_14","root_26","consequent_15","div_15","node_21","button_4","root_27","span_12","span_13","span_14","consequent_16","button_5","node_22","text_42","span_15","div_16","root_28","node_24","FireParticles","StarParticles","consequent_17","alternate_8","div_17","p_15","p_16","consequent_18","consequent_19","alternate_9","div_18","span_16","fragment_21","span_17","strong_1","text_49","span_18","span_19","fragment_22","span_20","consequent_20","alternate_10","consequent_21","consequent_10","consequent_22","LABEL","nav","$.each","RATE_SUBJECTS","RATE_SUBJECT_PATH"],"sources":["../../../../../../src/lib/components/FireParticles.svelte","../../../../../../src/lib/components/StarParticles.svelte","../../../../../../src/lib/rate-not-now.ts","../../../../../../src/lib/components/rate/NotNowSheet.svelte","../../../../../../src/lib/components/rate/RateUploader.svelte","../../../../../../src/lib/components/rate/RateSubjectSwitch.svelte"],"sourcesContent":["<script lang=\"ts\">\n\timport { onMount } from 'svelte';\n\timport { browser } from '$app/environment';\n\n\tinterface Props { mobile?: boolean; }\n\tlet { mobile = false }: Props = $props();\n\n\tlet canvas: HTMLCanvasElement;\n\tlet animId: number;\n\tlet tick = 0;\n\tlet isMobile = false;\n\n\tfunction loop() {\n\t\tif (!canvas) return;\n\t\ttick++;\n\n\t\t// Mobile: cap at 30fps. The wave math + multi-layer fills are the most expensive\n\t\t// thing on the homepage on a mid-tier Android — skipping every other frame\n\t\t// halves CPU without any visible difference at this animation speed.\n\t\tif (isMobile && tick % 2 === 0) {\n\t\t\tanimId = requestAnimationFrame(loop);\n\t\t\treturn;\n\t\t}\n\n\t\tconst ctx = canvas.getContext('2d');\n\t\tif (!ctx) return;\n\n\t\tconst w = canvas.offsetWidth;\n\t\tconst h = canvas.offsetHeight;\n\t\t// Only resize when the layout actually changed — assigning canvas.width clears\n\t\t// the buffer and forces a GPU reupload, both wasted if dimensions are unchanged.\n\t\tif (canvas.width !== w || canvas.height !== h) {\n\t\t\tcanvas.width = w;\n\t\t\tcanvas.height = h;\n\t\t} else {\n\t\t\tctx.clearRect(0, 0, w, h);\n\t\t}\n\t\tctx.globalCompositeOperation = 'screen';\n\n\t\tconst t = tick * 0.03;\n\n\t\t// Build one continuous flame silhouette path across the bottom\n\t\t// by combining multiple sine waves at different frequencies\n\t\tconst resolution = 80;\n\t\tconst points: { x: number; y: number }[] = [];\n\n\t\tfor (let i = 0; i <= resolution; i++) {\n\t\t\tconst xRatio = i / resolution;\n\t\t\tconst x = xRatio * w;\n\n\t\t\t// combine waves for organic flickering shape\n\t\t\tconst wave1 = Math.sin(xRatio * 8 + t * 2.5) * 0.35;\n\t\t\tconst wave2 = Math.sin(xRatio * 13 + t * 3.8) * 0.2;\n\t\t\tconst wave3 = Math.sin(xRatio * 21 + t * 5.2) * 0.1;\n\t\t\tconst wave4 = Math.cos(xRatio * 5 + t * 1.8) * 0.15;\n\n\t\t\t// taller in the middle, shorter at edges\n\t\t\tconst edgeFalloff = Math.sin(xRatio * Math.PI);\n\t\t\tconst baseHeight = 0.18 + (wave1 + wave2 + wave3 + wave4) * 0.12;\n\t\t\tconst finalHeight = baseHeight * (0.3 + edgeFalloff * 0.7);\n\n\t\t\tpoints.push({ x, y: h - finalHeight * h });\n\t\t}\n\n\t\t// Layer 1: wide soft ambient glow\n\t\tctx.beginPath();\n\t\tctx.moveTo(0, h);\n\t\tfor (const p of points) {\n\t\t\tctx.lineTo(p.x, p.y - 20);\n\t\t}\n\t\tctx.lineTo(w, h);\n\t\tctx.closePath();\n\t\tconst ambientGrad = ctx.createLinearGradient(0, h, 0, h * 0.5);\n\t\tambientGrad.addColorStop(0, 'rgba(255, 77, 109, 0.06)');\n\t\tambientGrad.addColorStop(1, 'rgba(255, 77, 109, 0)');\n\t\tctx.fillStyle = ambientGrad;\n\t\tctx.fill();\n\n\t\t// Layer 2: main flame body (continuous shape, no individual tongues)\n\t\tctx.beginPath();\n\t\tctx.moveTo(0, h);\n\t\t// smooth curve through all points\n\t\tfor (let i = 0; i < points.length - 1; i++) {\n\t\t\tconst curr = points[i];\n\t\t\tconst next = points[i + 1];\n\t\t\tconst cpx = (curr.x + next.x) / 2;\n\t\t\tconst cpy = (curr.y + next.y) / 2;\n\t\t\tctx.quadraticCurveTo(curr.x, curr.y, cpx, cpy);\n\t\t}\n\t\tctx.lineTo(w, h);\n\t\tctx.closePath();\n\n\t\tconst flameGrad = ctx.createLinearGradient(0, h, 0, h * 0.55);\n\t\tflameGrad.addColorStop(0, 'rgba(255, 100, 60, 0.18)');\n\t\tflameGrad.addColorStop(0.3, 'rgba(255, 77, 109, 0.1)');\n\t\tflameGrad.addColorStop(0.7, 'rgba(255, 77, 109, 0.03)');\n\t\tflameGrad.addColorStop(1, 'rgba(255, 77, 109, 0)');\n\t\tctx.fillStyle = flameGrad;\n\t\tctx.fill();\n\n\t\t// Layer 3: slightly different wave for inner brightness (offset timing)\n\t\tconst innerPoints: { x: number; y: number }[] = [];\n\t\tfor (let i = 0; i <= resolution; i++) {\n\t\t\tconst xRatio = i / resolution;\n\t\t\tconst x = xRatio * w;\n\n\t\t\tconst wave1 = Math.sin(xRatio * 9 + t * 3.2 + 1) * 0.3;\n\t\t\tconst wave2 = Math.sin(xRatio * 16 + t * 4.5 + 2) * 0.15;\n\t\t\tconst wave3 = Math.cos(xRatio * 6 + t * 2.1 + 0.5) * 0.12;\n\n\t\t\tconst edgeFalloff = Math.sin(xRatio * Math.PI);\n\t\t\tconst baseHeight = 0.1 + (wave1 + wave2 + wave3) * 0.08;\n\t\t\tconst finalHeight = baseHeight * (0.2 + edgeFalloff * 0.6);\n\n\t\t\tinnerPoints.push({ x, y: h - finalHeight * h });\n\t\t}\n\n\t\tctx.beginPath();\n\t\tctx.moveTo(0, h);\n\t\tfor (let i = 0; i < innerPoints.length - 1; i++) {\n\t\t\tconst curr = innerPoints[i];\n\t\t\tconst next = innerPoints[i + 1];\n\t\t\tconst cpx = (curr.x + next.x) / 2;\n\t\t\tconst cpy = (curr.y + next.y) / 2;\n\t\t\tctx.quadraticCurveTo(curr.x, curr.y, cpx, cpy);\n\t\t}\n\t\tctx.lineTo(w, h);\n\t\tctx.closePath();\n\n\t\tconst innerGrad = ctx.createLinearGradient(0, h, 0, h * 0.7);\n\t\tinnerGrad.addColorStop(0, 'rgba(255, 180, 120, 0.12)');\n\t\tinnerGrad.addColorStop(0.5, 'rgba(255, 120, 80, 0.05)');\n\t\tinnerGrad.addColorStop(1, 'rgba(255, 77, 109, 0)');\n\t\tctx.fillStyle = innerGrad;\n\t\tctx.fill();\n\n\t\t// Bottom edge: thin hot line\n\t\tctx.globalCompositeOperation = 'source-over';\n\t\tconst edgeGrad = ctx.createLinearGradient(0, h, 0, h - 4);\n\t\tedgeGrad.addColorStop(0, 'rgba(255, 140, 80, 0.15)');\n\t\tedgeGrad.addColorStop(1, 'rgba(255, 77, 109, 0)');\n\t\tctx.fillStyle = edgeGrad;\n\t\tctx.fillRect(0, h - 4, w, 4);\n\n\t\tanimId = requestAnimationFrame(loop);\n\t}\n\n\tonMount(() => {\n\t\tif (!mobile && browser && window.matchMedia('(hover: none)').matches) return;\n\n\t\tisMobile =\n\t\t\tbrowser &&\n\t\t\t(window.matchMedia('(hover: none)').matches || window.innerWidth < 768);\n\n\t\tlet running = false;\n\t\tconst observer = new IntersectionObserver(\n\t\t\t([entry]) => {\n\t\t\t\tif (entry.isIntersecting && !running) {\n\t\t\t\t\trunning = true;\n\t\t\t\t\tloop();\n\t\t\t\t} else if (!entry.isIntersecting && running) {\n\t\t\t\t\trunning = false;\n\t\t\t\t\tcancelAnimationFrame(animId);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ threshold: 0 }\n\t\t);\n\t\tobserver.observe(canvas);\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t\tcancelAnimationFrame(animId);\n\t\t};\n\t});\n</script>\n\n<canvas bind:this={canvas} class=\"pointer-events-none absolute inset-0 h-full w-full\"></canvas>\n","<script lang=\"ts\">\n\timport { onMount } from 'svelte';\n\timport { browser } from '$app/environment';\n\n\tinterface Props { mobile?: boolean; }\n\tlet { mobile = false }: Props = $props();\n\n\tinterface Star {\n\t\tx: number;\n\t\ty: number;\n\t\tsize: number;\n\t\tspeed: number;\n\t\topacity: number;\n\t\trotation: number;\n\t\trotSpeed: number;\n\t\tlife: number;\n\t\tmaxLife: number;\n\t}\n\n\tlet canvas: HTMLCanvasElement;\n\tlet stars: Star[] = [];\n\tlet animId: number;\n\tlet tick = 0;\n\tlet isMobile = false;\n\n\tfunction spawn(): Star {\n\t\treturn {\n\t\t\tx: 10 + Math.random() * 80,\n\t\t\ty: 90 + Math.random() * 15,\n\t\t\tsize: 3 + Math.random() * 4,\n\t\t\tspeed: 0.1 + Math.random() * 0.25,\n\t\t\topacity: 0.5 + Math.random() * 0.3,\n\t\t\trotation: Math.random() * Math.PI * 2,\n\t\t\trotSpeed: (Math.random() - 0.5) * 0.02,\n\t\t\tlife: 0,\n\t\t\tmaxLife: 120 + Math.random() * 140\n\t\t};\n\t}\n\n\tfunction drawStar(ctx: CanvasRenderingContext2D, cx: number, cy: number, r: number, rot: number, alpha: number) {\n\t\tctx.save();\n\t\tctx.translate(cx, cy);\n\t\tctx.rotate(rot);\n\n\t\t// subtle glow\n\t\tconst grad = ctx.createRadialGradient(0, 0, 0, 0, 0, r * 3);\n\t\tgrad.addColorStop(0, `rgba(255, 229, 0, ${alpha * 0.12})`);\n\t\tgrad.addColorStop(1, 'rgba(255, 229, 0, 0)');\n\t\tctx.fillStyle = grad;\n\t\tctx.fillRect(-r * 3, -r * 3, r * 6, r * 6);\n\n\t\t// 4-point star\n\t\tctx.beginPath();\n\t\tfor (let i = 0; i < 4; i++) {\n\t\t\tconst angle = (i * Math.PI) / 2;\n\t\t\tconst ox = Math.cos(angle) * r;\n\t\t\tconst oy = Math.sin(angle) * r;\n\t\t\tconst ia = angle + Math.PI / 4;\n\t\t\tconst ix = Math.cos(ia) * r * 0.3;\n\t\t\tconst iy = Math.sin(ia) * r * 0.3;\n\t\t\tif (i === 0) ctx.moveTo(ox, oy);\n\t\t\telse ctx.lineTo(ox, oy);\n\t\t\tctx.lineTo(ix, iy);\n\t\t}\n\t\tctx.closePath();\n\t\tctx.fillStyle = `rgba(255, 229, 0, ${alpha})`;\n\t\tctx.fill();\n\n\t\tctx.restore();\n\t}\n\n\tfunction loop() {\n\t\tif (!canvas) return;\n\t\ttick++;\n\n\t\t// Mobile: cap at 30fps to keep the main thread responsive (hamburger taps,\n\t\t// scroll, etc). Star drift is slow enough that 30fps is indistinguishable\n\t\t// from 60fps to a viewer.\n\t\tif (isMobile && tick % 2 === 0) {\n\t\t\tanimId = requestAnimationFrame(loop);\n\t\t\treturn;\n\t\t}\n\n\t\tconst ctx = canvas.getContext('2d');\n\t\tif (!ctx) return;\n\n\t\tconst w = canvas.offsetWidth;\n\t\tconst h = canvas.offsetHeight;\n\t\tif (canvas.width !== w || canvas.height !== h) {\n\t\t\tcanvas.width = w;\n\t\t\tcanvas.height = h;\n\t\t}\n\t\tctx.clearRect(0, 0, w, h);\n\n\t\t// fewer, slower spawning\n\t\tif (stars.length < 10 && tick % 12 === 0) {\n\t\t\tstars.push(spawn());\n\t\t}\n\n\t\tfor (let i = stars.length - 1; i >= 0; i--) {\n\t\t\tconst s = stars[i];\n\t\t\ts.y -= s.speed;\n\t\t\ts.rotation += s.rotSpeed;\n\t\t\ts.life++;\n\n\t\t\tconst progress = s.life / s.maxLife;\n\t\t\tconst alpha = s.opacity * (1 - progress) * (1 - progress);\n\t\t\tconst scale = s.size * (0.7 + (1 - progress) * 0.3);\n\n\t\t\tconst px = (s.x / 100) * w;\n\t\t\tconst py = (s.y / 100) * h;\n\n\t\t\tdrawStar(ctx, px, py, scale, s.rotation, alpha);\n\n\t\t\tif (s.life >= s.maxLife || s.y < -5) {\n\t\t\t\tstars.splice(i, 1);\n\t\t\t}\n\t\t}\n\n\t\tanimId = requestAnimationFrame(loop);\n\t}\n\n\tonMount(() => {\n\t\tif (!mobile && browser && window.matchMedia('(hover: none)').matches) return;\n\n\t\tisMobile =\n\t\t\tbrowser &&\n\t\t\t(window.matchMedia('(hover: none)').matches || window.innerWidth < 768);\n\n\t\tlet running = false;\n\t\tlet seeded = false;\n\t\tconst observer = new IntersectionObserver(\n\t\t\t([entry]) => {\n\t\t\t\tif (entry.isIntersecting && !running) {\n\t\t\t\t\tif (!seeded) {\n\t\t\t\t\t\tseeded = true;\n\t\t\t\t\t\tfor (let i = 0; i < 6; i++) {\n\t\t\t\t\t\t\tconst s = spawn();\n\t\t\t\t\t\t\ts.life = Math.random() * s.maxLife * 0.4;\n\t\t\t\t\t\t\ts.y = 20 + Math.random() * 65;\n\t\t\t\t\t\t\tstars.push(s);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\trunning = true;\n\t\t\t\t\tloop();\n\t\t\t\t} else if (!entry.isIntersecting && running) {\n\t\t\t\t\trunning = false;\n\t\t\t\t\tcancelAnimationFrame(animId);\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ threshold: 0 }\n\t\t);\n\t\tobserver.observe(canvas);\n\n\t\treturn () => {\n\t\t\tobserver.disconnect();\n\t\t\tcancelAnimationFrame(animId);\n\t\t};\n\t});\n</script>\n\n<canvas bind:this={canvas} class=\"pointer-events-none absolute inset-0 h-full w-full\"></canvas>\n","/** The /rate \"not ready to upload?\" sheet (RAT-507). Client-safe.\n *\n *  On homepage C, 31% of new visitors who reached /rate left without\n *  uploading. Of those, 43% went back to `/`, 42% left the site, and 6% reached\n *  a product. A quiet link under the upload area opens a sheet of products that\n *  need no photo of you, so a visitor who isn't ready to upload has somewhere\n *  to go that isn't away. Not a button of equal weight to the upload: the\n *  guardrail was that uploads must not drop. It won its test (468971: a paid\n *  product reached 38.1% → 40.2%, uploads level) and is the page since\n *  RAT-555. */\n\nimport { msg } from '$lib/i18n/mark';\n\n/** What the sheet offers, in order. None of them asks for a photo of you. */\nexport const NO_PHOTO_PRODUCTS = [\n\t{\n\t\tkey: 'albums',\n\t\thref: '/albums',\n\t\tname: msg('albums'),\n\t\tdesc: msg('private sets. unlock the ones you want.')\n\t},\n\t{\n\t\tkey: 'roleplay',\n\t\thref: '/roleplay',\n\t\tname: msg('roleplay'),\n\t\tdesc: msg('a world, run by an AI game master')\n\t},\n\t{\n\t\tkey: 'arena',\n\t\thref: '/a',\n\t\tname: msg('arena'),\n\t\tdesc: msg('swipe on strangers, match, then chat')\n\t}\n] as const;\n","<script lang=\"ts\">\n\timport { t } from '$lib/i18n';\n\t/**\n\t * RAT-507: the /rate \"not ready to upload?\" link and the sheet it opens.\n\t *\n\t * The link is quiet on purpose: a line of muted text under the upload area,\n\t * not a button beside \"choose file\". An easy \"no\" next to the main action\n\t * gives people permission to skip it, and uploads are this test's guardrail.\n\t * It is for the visitor who was leaving anyway. On homepage C, 85% of those\n\t * who left /rate without uploading went back or left the site.\n\t *\n\t * The sheet offers only products that need no photo of you (NO_PHOTO_PRODUCTS).\n\t * Duel, beat me and a real rater all start with the photo this visitor isn't\n\t * ready to give. \"Upload a photo after all\" closes the sheet and opens the\n\t * file picker in the same tap, which keeps the user activation iOS Safari\n\t * needs.\n\t *\n\t * Built like AuthSheet: backdrop, bottom sheet on phones, a card from md up,\n\t * Escape and backdrop close.\n\t */\n\timport { tick } from 'svelte';\n\timport { fly } from 'svelte/transition';\n\timport { cubicOut } from 'svelte/easing';\n\timport Icon from '$lib/components/landing/signup-first/Icon.svelte';\n\timport { NO_PHOTO_PRODUCTS } from '$lib/rate-not-now';\n\timport { trackOfferClicked, trackOfferDismissed, trackOfferShown } from '$lib/analytics';\n\n\t/** Opens the page's own file picker. Called inside the tap, synchronously. */\n\tlet { onupload }: { onupload?: () => void } = $props();\n\n\tconst PLACEMENT = 'rate_not_now';\n\n\tlet open = $state(false);\n\t/** The row just tapped. /albums can take a moment to load, and a row that\n\t *  doesn't react looks like a failed tap. */\n\tlet going = $state<string | null>(null);\n\tlet trigger = $state<HTMLButtonElement | null>(null);\n\tlet closeButton = $state<HTMLButtonElement | null>(null);\n\n\tasync function show() {\n\t\topen = true;\n\t\ttrackOfferShown(\n\t\t\tPLACEMENT,\n\t\t\tNO_PHOTO_PRODUCTS.map((p) => p.key)\n\t\t);\n\t\tawait tick();\n\t\t// preventScroll: the sheet is still 400px below the fold while it flies\n\t\t// in, and a plain focus() scrolls the page up to meet it.\n\t\tcloseButton?.focus({ preventScroll: true });\n\t}\n\n\tfunction hide(how: 'close' | 'backdrop' | 'escape' | 'upload') {\n\t\tif (!open) return;\n\t\topen = false;\n\t\ttrackOfferDismissed(PLACEMENT, how);\n\t\tif (how !== 'upload') trigger?.focus({ preventScroll: true });\n\t}\n\n\tfunction uploadAfterAll() {\n\t\thide('upload');\n\t\tonupload?.();\n\t}\n\n\tfunction onBackdrop(e: MouseEvent) {\n\t\tif (e.target === e.currentTarget) hide('backdrop');\n\t}\n\n\tfunction onKey(e: KeyboardEvent) {\n\t\tif (open && e.key === 'Escape') hide('escape');\n\t}\n</script>\n\n<svelte:window onkeydown={onKey} />\n\n<div class=\"notnow\">\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"link\"\n\t\tbind:this={trigger}\n\t\tonclick={show}\n\t\taria-haspopup=\"dialog\"\n\t\taria-expanded={open}\n\t>\n\t\t{t('not ready to upload? look around first')}\n\t\t<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" aria-hidden=\"true\"\n\t\t\t><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 15.75l7.5-7.5 7.5 7.5\" /></svg\n\t\t>\n\t</button>\n</div>\n\n{#if open}\n\t<!-- z-[210], as AuthSheet: above the bottom nav (50). role=presentation on\n\t\t the backdrop; the dialog child carries the semantics. -->\n\t<div\n\t\trole=\"presentation\"\n\t\tclass=\"backdrop fixed inset-0 z-[210] bg-black/60 md:flex md:items-center md:justify-center md:p-6\"\n\t\tonclick={onBackdrop}\n\t\ttransition:fly={{ duration: 180 }}\n\t>\n\t\t<div\n\t\t\trole=\"dialog\"\n\t\t\taria-modal=\"true\"\n\t\t\taria-labelledby=\"notnow-title\"\n\t\t\tclass=\"sheet absolute inset-x-0 bottom-0 rounded-t-[22px] border-t border-border bg-surface shadow-2xl md:static md:w-full md:max-w-[420px] md:rounded-[22px] md:border\"\n\t\t\tstyle=\"padding: 12px 20px calc(24px + env(safe-area-inset-bottom, 0px));\"\n\t\t\ttransition:fly={{ y: 400, duration: 280, easing: cubicOut }}\n\t\t>\n\t\t\t<div class=\"grabber\" aria-hidden=\"true\"></div>\n\t\t\t<div class=\"head\">\n\t\t\t\t<div>\n\t\t\t\t\t<h2 id=\"notnow-title\">{t('no photo needed for these')}</h2>\n\t\t\t\t\t<p>{t(\"look around first. your rating is here when you're ready.\")}</p>\n\t\t\t\t</div>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"close\"\n\t\t\t\t\tbind:this={closeButton}\n\t\t\t\t\tonclick={() => hide('close')}\n\t\t\t\t\taria-label={t('close')}\n\t\t\t\t>\n\t\t\t\t\t<svg\n\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\tstroke-width=\"2\"\n\t\t\t\t\t\taria-hidden=\"true\"><path stroke-linecap=\"round\" d=\"M6 6l12 12M18 6L6 18\" /></svg\n\t\t\t\t\t>\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<div class=\"rows\">\n\t\t\t\t{#each NO_PHOTO_PRODUCTS as p, i (p.key)}\n\t\t\t\t\t<a\n\t\t\t\t\t\tclass=\"row k-{p.key}\"\n\t\t\t\t\t\thref={p.href}\n\t\t\t\t\t\taria-busy={going === p.key}\n\t\t\t\t\t\tonclick={() => {\n\t\t\t\t\t\t\tgoing = p.key;\n\t\t\t\t\t\t\ttrackOfferClicked(PLACEMENT, p.key, i + 1);\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span class=\"glyph\"><Icon name={p.key} /></span>\n\t\t\t\t\t\t<span class=\"txt\">\n\t\t\t\t\t\t\t<span class=\"name\">{t(p.name)}</span>\n\t\t\t\t\t\t\t<span class=\"desc\">{t(p.desc)}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t{#if going === p.key}\n\t\t\t\t\t\t\t<span class=\"spin\" aria-hidden=\"true\"></span>\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t<span class=\"chev\"><Icon name=\"chevron-right\" /></span>\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t</a>\n\t\t\t\t{/each}\n\t\t\t</div>\n\n\t\t\t<button type=\"button\" class=\"upload\" onclick={uploadAfterAll}\n\t\t\t\t>{t('upload a photo after all')}</button\n\t\t\t>\n\t\t</div>\n\t</div>\n{/if}\n\n<style>\n\t.notnow {\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\tmargin-top: 28px;\n\t}\n\t.link {\n\t\tdisplay: inline-flex;\n\t\talign-items: center;\n\t\tgap: 6px;\n\t\tmin-height: 44px;\n\t\tpadding: 0;\n\t\tborder: 0;\n\t\tbackground: none;\n\t\tfont-family: var(--font-display);\n\t\tfont-size: 13px;\n\t\tfont-weight: 700;\n\t\tletter-spacing: -0.01em;\n\t\tcolor: var(--color-muted-2);\n\t\tcursor: pointer;\n\t\ttext-decoration: underline;\n\t\ttext-decoration-color: var(--color-border);\n\t\ttext-underline-offset: 5px;\n\t\ttransition: text-decoration-color 180ms var(--ease-out-quart);\n\t}\n\t.link:hover {\n\t\ttext-decoration-color: var(--color-muted);\n\t}\n\t.link svg {\n\t\twidth: 14px;\n\t\theight: 14px;\n\t}\n\n\t.grabber {\n\t\twidth: 36px;\n\t\theight: 4px;\n\t\tmargin: 0 auto 14px;\n\t\tborder-radius: 2px;\n\t\tbackground: var(--color-border);\n\t}\n\t.head {\n\t\tdisplay: flex;\n\t\talign-items: flex-start;\n\t\tjustify-content: space-between;\n\t\tgap: 12px;\n\t}\n\th2 {\n\t\tmargin: 0;\n\t\tfont-family: var(--font-display);\n\t\tfont-size: 21px;\n\t\tfont-weight: 700;\n\t\tline-height: 1.1;\n\t\tletter-spacing: -0.03em;\n\t\tcolor: var(--color-text);\n\t}\n\t.head p {\n\t\tmargin: 6px 0 0;\n\t\tfont-size: 13px;\n\t\tline-height: 1.5;\n\t\tcolor: var(--color-muted-2);\n\t}\n\t.close {\n\t\tdisplay: grid;\n\t\tplace-items: center;\n\t\tflex: none;\n\t\twidth: 40px;\n\t\theight: 40px;\n\t\tborder: 1px solid var(--color-border);\n\t\tborder-radius: 11px;\n\t\tbackground: var(--color-surface-2);\n\t\tcolor: var(--color-muted-2);\n\t\tcursor: pointer;\n\t}\n\t.close svg {\n\t\twidth: 16px;\n\t\theight: 16px;\n\t}\n\n\t.k-albums {\n\t\t--fill: var(--color-fuchsia);\n\t\t--ink: #fff;\n\t\t--title: #e27af4;\n\t}\n\t.k-roleplay {\n\t\t--fill: var(--color-purple);\n\t\t--ink: #fff;\n\t\t--title: #a78bfa;\n\t}\n\t.k-arena {\n\t\t--fill: var(--color-orange);\n\t\t--ink: #1a0a00;\n\t\t--title: #fb8a3c;\n\t}\n\t.rows {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tmargin-top: 16px;\n\t\tborder: 1px solid var(--color-border);\n\t\tborder-radius: 16px;\n\t\tbackground: var(--color-surface-2);\n\t\toverflow: hidden;\n\t}\n\t.row {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 12px;\n\t\tmin-height: 64px;\n\t\tpadding: 0 14px;\n\t\tcolor: var(--color-text);\n\t\ttext-decoration: none;\n\t\ttransition: background-color 180ms var(--ease-out-quart);\n\t}\n\t.row + .row {\n\t\tborder-top: 1px solid var(--color-border);\n\t}\n\t.row:hover {\n\t\tcolor: var(--color-text);\n\t\tbackground: #202020;\n\t}\n\t.glyph {\n\t\tdisplay: grid;\n\t\tplace-items: center;\n\t\tflex: none;\n\t\twidth: 34px;\n\t\theight: 34px;\n\t\tborder-radius: 10px;\n\t\tbackground: var(--fill);\n\t\tcolor: var(--ink);\n\t}\n\t.glyph :global(svg) {\n\t\twidth: 18px;\n\t\theight: 18px;\n\t}\n\t.txt {\n\t\tdisplay: flex;\n\t\tflex: 1;\n\t\tflex-direction: column;\n\t\tgap: 2px;\n\t\tmin-width: 0;\n\t}\n\t.name {\n\t\tfont-family: var(--font-display);\n\t\tfont-size: 15.5px;\n\t\tfont-weight: 700;\n\t\tletter-spacing: -0.01em;\n\t\tcolor: var(--title);\n\t}\n\t.desc {\n\t\tfont-size: 12px;\n\t\tline-height: 1.4;\n\t\tcolor: var(--color-muted-2);\n\t}\n\t.chev {\n\t\tdisplay: flex;\n\t\tcolor: var(--color-muted);\n\t}\n\t.chev :global(svg) {\n\t\twidth: 15px;\n\t\theight: 15px;\n\t}\n\t.spin {\n\t\tflex: none;\n\t\twidth: 15px;\n\t\theight: 15px;\n\t\tborder: 2px solid var(--color-border);\n\t\tborder-top-color: var(--title);\n\t\tborder-radius: 50%;\n\t\tanimation: notnow-spin 700ms linear infinite;\n\t}\n\t@keyframes notnow-spin {\n\t\tto {\n\t\t\ttransform: rotate(360deg);\n\t\t}\n\t}\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.spin {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\t.upload {\n\t\twidth: 100%;\n\t\theight: 48px;\n\t\tmargin-top: 14px;\n\t\tborder: 1px solid var(--color-border);\n\t\tborder-radius: 13px;\n\t\tbackground: var(--color-surface-2);\n\t\tcolor: var(--color-text);\n\t\tfont-family: var(--font-display);\n\t\tfont-size: 14px;\n\t\tfont-weight: 700;\n\t\tletter-spacing: -0.01em;\n\t\tcursor: pointer;\n\t}\n</style>\n","<script lang=\"ts\">\n\t/**\n\t * The AI rater's upload and mode steps, lifted out of /rate for Epic R:\n\t * /rate-my-boobs, /rate-my-ass and /rate-my-nudes run the same flow (the same\n\t * quota, saved photo, sign-up gate and result page) with their own heading,\n\t * their own page below it and their subject on the rating. /rate renders\n\t * exactly what it rendered before.\n\t */\n\timport type { Snippet } from 'svelte';\n\timport { t } from '$lib/i18n';\n\timport { afterNavigate, goto, replaceState } from '$app/navigation';\n\timport { page } from '$app/state';\n\timport { deserialize } from '$app/forms';\n\timport { onDestroy } from 'svelte';\n\timport FireParticles from '$lib/components/FireParticles.svelte';\n\timport StarParticles from '$lib/components/StarParticles.svelte';\n\timport ReusePhoto from '$lib/components/ReusePhoto.svelte';\n\timport NotNowSheet from '$lib/components/rate/NotNowSheet.svelte';\n\timport { createSupabaseBrowserClient } from '$lib/supabase';\n\timport { uploadSubmissionPhoto } from '$lib/submission-upload';\n\timport { activeMode } from '$lib/stores/activeMode';\n\timport * as analytics from '$lib/analytics';\n\timport { PRO_MONTHLY_LABEL } from '$lib/pricing';\n\timport { heicToJpeg } from '$lib/utils/heic-to-jpeg';\n\timport { detachFile, isStaleFileError } from '$lib/utils/stale-file';\n\timport { openAuthSheet } from '$lib/stores/authSheet';\n\timport { rateFlow, type RateSubject } from '$lib/rate-subjects';\n\n\tinterface Props {\n\t\t/** The page's load (lib/server/rate-uploader.ts) with the layout's data. */\n\t\tdata: {\n\t\t\tsession: unknown;\n\t\t\tcanGenerate: boolean;\n\t\t\tcanVideo: boolean;\n\t\t\tlastGenerationId?: string | null;\n\t\t\tpendingGenerationId?: string | null;\n\t\t\tlastPhotoUrl?: string | null;\n\t\t\tisSubscribed?: boolean;\n\t\t\ttokens?: number | null;\n\t\t};\n\t\tsubject?: RateSubject;\n\t\t/** Above the heading: the subject switcher. */\n\t\ttop?: Snippet;\n\t\t/** The upload step's H1, the page's searchable heading. */\n\t\theading: Snippet;\n\t\t/** The line under the heading. */\n\t\tintro: Snippet;\n\t\t/** Where else the saved photo works (\"Works on Arena & more.\"). */\n\t\treuseOthers?: string;\n\t\t/** The page below the upload step: shown on the upload step only. */\n\t\tchildren?: Snippet;\n\t}\n\n\tlet {\n\t\tdata,\n\t\tsubject = 'dick',\n\t\ttop,\n\t\theading,\n\t\tintro,\n\t\treuseOthers = 'Arena',\n\t\tchildren\n\t}: Props = $props();\n\n\t/** PostHog's flow: `rate` on /rate, `rate_boobs`… on the other pages. */\n\tconst flow = $derived(rateFlow(subject));\n\n\ttype Step = 'upload' | 'mode';\n\ttype Mode = 'roast' | 'hype';\n\n\n\tconst supabase = createSupabaseBrowserClient();\n\n\t// Always the upload step on arrival: a picked photo can't survive a reload, so\n\t// a `?step=mode` left in the URL has nothing behind it (afterNavigate below\n\t// clears it).\n\tlet step = $state<Step>('upload');\n\tlet mode = $state<Mode>('roast');\n\tlet showSample = $state(false); // progressive disclosure of the AI-output sample on the mode step\n\n\t// push step into URL (shallow — no navigation, just URL update)\n\tfunction setStep(newStep: Step) {\n\t\tstep = newStep;\n\t\tconst url = new URL(page.url);\n\t\tif (newStep === 'upload') {\n\t\t\turl.searchParams.delete('step');\n\t\t} else {\n\t\t\turl.searchParams.set('step', newStep);\n\t\t}\n\t\treplaceState(url, {});\n\t}\n\n\t// track whether we're navigating to result (don't reset mode on destroy)\n\tlet goingToResult = false;\n\n\t// sync mode to global store when user picks one\n\t$effect(() => {\n\t\tif (step !== 'upload') {\n\t\t\tactiveMode.set(mode);\n\t\t} else {\n\t\t\tactiveMode.set(null);\n\t\t}\n\t});\n\n\t// RAT-278: lock the page to viewport height on upload + mode steps. body\n\t// .fit-screen drops main's pb (section owns nav clearance) and min-h-svh\n\t// on the section pins to the smallest viewport — keeps the page exactly\n\t// fit on iPhone Chrome where the bottom toolbar shrinks visual viewport.\n\t$effect(() => {\n\t\tconst fit = step === 'upload' || step === 'mode';\n\t\tdocument.body.classList.toggle('fit-screen', fit);\n\t\treturn () => document.body.classList.remove('fit-screen');\n\t});\n\n\t// cleanup on leave\n\tonDestroy(() => {\n\t\tif (!goingToResult) activeMode.set(null);\n\t});\n\n\tlet dragOver = $state(false);\n\tlet iconBounce = $state(false);\n\tlet processing = $state(false); // decoding a freshly-picked file (dropzone pending state)\n\tlet selectedFile = $state<File | null>(null);\n\t// The dropzone's picker, so the not-now sheet's \"upload a photo after all\"\n\t// can open it inside the same tap (RAT-507).\n\tlet fileInput = $state<HTMLInputElement | null>(null);\n\tlet uploadError = $state('');\n\tlet savePhoto = $state(true);\n\t// RAT-272 follow-up: per-upload csamAck checkbox dropped (T&C covers\n\t// the same ground; the audit row is still written server-side).\n\t// A literal `true` keeps any lingering downstream check happy without\n\t// re-introducing the UI gate.\n\tconst csamAck = true;\n\n\tconst ac = $derived(mode === 'roast' ? 'text-coral' : 'text-yellow');\n\n\tconst MAX_IMAGE_BYTES = 4 * 1024 * 1024; // 4MB (Claude limit is 5MB, leave headroom)\n\tconst MAX_DIMENSION = 4000; // max width/height\n\n\t// Video rating (subscriber-only, data.canVideo): a short clip instead of a\n\t// photo. The clip goes up as-is (no canvas pipeline — the server samples\n\t// frames off it), so the caps are its own.\n\tlet selectedVideo = $state<File | null>(null);\n\tlet videoDurationSec = $state<number | null>(null);\n\t// mp4 + mov only — matches the rate-media bucket's allowlist (the clip\n\t// lands there via /api/rate/upload-url; the submissions bucket is\n\t// image-only + 5MB, sized for the photo funnel).\n\tconst VIDEO_ACCEPT = 'video/mp4,video/quicktime';\n\tconst MAX_VIDEO_BYTES = 50 * 1024 * 1024;\n\tconst MAX_VIDEO_SEC = 60;\n\n\t/** Duration via a metadata-only <video> load; null when unreadable. */\n\tfunction readVideoDuration(f: File): Promise<number | null> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst url = URL.createObjectURL(f);\n\t\t\tconst v = document.createElement('video');\n\t\t\tv.preload = 'metadata';\n\t\t\tv.muted = true;\n\t\t\tconst done = (d: number | null) => {\n\t\t\t\tURL.revokeObjectURL(url);\n\t\t\t\tresolve(d);\n\t\t\t};\n\t\t\tconst t = setTimeout(() => done(null), 10_000);\n\t\t\tv.onloadedmetadata = () => {\n\t\t\t\tclearTimeout(t);\n\t\t\t\tdone(Number.isFinite(v.duration) ? v.duration : null);\n\t\t\t};\n\t\t\tv.onerror = () => {\n\t\t\t\tclearTimeout(t);\n\t\t\t\tdone(null);\n\t\t\t};\n\t\t\tv.src = url;\n\t\t});\n\t}\n\n\tasync function handleVideoInput(e: Event) {\n\t\tconst f = (e.target as HTMLInputElement).files?.[0];\n\t\tif (!f || processing) return;\n\t\tuploadError = '';\n\t\tif (!VIDEO_ACCEPT.split(',').includes(f.type)) {\n\t\t\tuploadError = t('use an mp4, mov or webm clip.');\n\t\t\tresetFileInputs();\n\t\t\treturn;\n\t\t}\n\t\tif (f.size > MAX_VIDEO_BYTES) {\n\t\t\tuploadError = t('video too large (100MB max).');\n\t\t\tresetFileInputs();\n\t\t\treturn;\n\t\t}\n\t\tprocessing = true;\n\t\tconst dur = await readVideoDuration(f);\n\t\tprocessing = false;\n\t\tif (dur === null) {\n\t\t\tuploadError = t(\"couldn't read that video — try a different one.\");\n\t\t\tresetFileInputs();\n\t\t\treturn;\n\t\t}\n\t\tif (dur > MAX_VIDEO_SEC) {\n\t\t\tuploadError = t('keep it under {n} seconds.', { n: MAX_VIDEO_SEC });\n\t\t\tresetFileInputs();\n\t\t\treturn;\n\t\t}\n\t\tselectedVideo = f;\n\t\tvideoDurationSec = Math.round(dur);\n\t\tselectedFile = null;\n\t\tanalytics.trackPhotoUpload(flow);\n\t\tsetStep('mode');\n\t\tanalytics.trackFunnelStep('mode', flow);\n\t}\n\n\tasync function uploadVideo(): Promise<string | null> {\n\t\tif (!selectedVideo) return null;\n\t\ttry {\n\t\t\t// Signed-URL upload into rate-media — the same endpoint + PUT the\n\t\t\t// rater-booking flow uses for its video attachments.\n\t\t\tconst r = await fetch('/api/rate/upload-url', {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({ mimeType: selectedVideo.type, size: selectedVideo.size })\n\t\t\t});\n\t\t\tconst body = await r.json();\n\t\t\tif (!r.ok || !body.signedUrl || !body.path) {\n\t\t\t\tanalytics.trackUploadFail({\n\t\t\t\t\terror: body.error || 'upload-url failed',\n\t\t\t\t\tcontext: 'rate_video',\n\t\t\t\t\tstale: false\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst putRes = await fetch(body.signedUrl, {\n\t\t\t\tmethod: 'PUT',\n\t\t\t\theaders: { 'content-type': selectedVideo.type },\n\t\t\t\tbody: selectedVideo\n\t\t\t});\n\t\t\tif (!putRes.ok) {\n\t\t\t\tanalytics.trackUploadFail({\n\t\t\t\t\terror: `signed PUT ${putRes.status}`,\n\t\t\t\t\tcontext: 'rate_video',\n\t\t\t\t\tstale: false\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn body.path as string;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? `${err.name}: ${err.message}` : String(err);\n\t\t\tanalytics.trackUploadFail({ error: message, context: 'rate_video', stale: false });\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Convert + compress any image to JPEG under 4MB.\n\t//\n\t// Rejects when the browser can't decode the file into a bitmap (img.onerror).\n\t// This used to resolve the original file, which then got uploaded and shipped\n\t// to the analyzer — a photo that won't decode (corrupt, or a HEIC that\n\t// heicToJpeg also couldn't rescue) failed silently downstream instead of\n\t// telling the user to pick another. `handleFile` catches this and surfaces it.\n\tasync function compressImage(file: File): Promise<File> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst img = new Image();\n\t\t\tconst url = URL.createObjectURL(file);\n\t\t\timg.onload = async () => {\n\t\t\t\tURL.revokeObjectURL(url);\n\n\t\t\t\t// Scale down if too large\n\t\t\t\tlet { naturalWidth: w, naturalHeight: h } = img;\n\t\t\t\tif (w > MAX_DIMENSION || h > MAX_DIMENSION) {\n\t\t\t\t\tconst scale = MAX_DIMENSION / Math.max(w, h);\n\t\t\t\t\tw = Math.round(w * scale);\n\t\t\t\t\th = Math.round(h * scale);\n\t\t\t\t}\n\n\t\t\t\tconst canvas = document.createElement('canvas');\n\t\t\t\tcanvas.width = w;\n\t\t\t\tcanvas.height = h;\n\t\t\t\tconst ctx = canvas.getContext('2d')!;\n\t\t\t\tctx.drawImage(img, 0, 0, w, h);\n\n\t\t\t\t// Try decreasing quality until under 4MB\n\t\t\t\tlet quality = 0.85;\n\t\t\t\tlet blob: Blob | null = null;\n\t\t\t\twhile (quality > 0.3) {\n\t\t\t\t\tblob = await new Promise<Blob | null>((r) => canvas.toBlob(r, 'image/jpeg', quality));\n\t\t\t\t\tif (blob && blob.size <= MAX_IMAGE_BYTES) break;\n\t\t\t\t\tquality -= 0.1;\n\t\t\t\t}\n\n\t\t\t\tif (blob) {\n\t\t\t\t\tresolve(new File([blob], file.name.replace(/\\.[^.]+$/, '.jpg'), { type: 'image/jpeg' }));\n\t\t\t\t} else {\n\t\t\t\t\tresolve(file);\n\t\t\t\t}\n\t\t\t};\n\t\t\timg.onerror = () => {\n\t\t\t\tURL.revokeObjectURL(url);\n\t\t\t\treject(new Error('image decode failed'));\n\t\t\t};\n\t\t\timg.src = url;\n\t\t});\n\t}\n\n\t// `detachFile` reads the picked bytes at pick time so the OS handle can't go\n\t// stale while the user is off in the login flow — see $lib/utils/stale-file.\n\tasync function handleFile(file: File | undefined) {\n\t\t// Guard re-entry: decode is async (detach → HEIC convert → compress) and\n\t\t// showed nothing in the dropzone, so a user who tapped again mid-decode\n\t\t// fired a second run for no visible reason (and could get nothing back for\n\t\t// minutes). `processing` drives the dropzone's pending state and blocks\n\t\t// the double-pick.\n\t\tif (!file || processing) return;\n\t\tprocessing = true;\n\t\tuploadError = '';\n\t\tlet prepared: File;\n\t\ttry {\n\t\t\t// Bounded, because the decode can hang rather than fail: `compressImage`\n\t\t\t// resolves off `img.onload`/`img.onerror`, and under memory pressure —\n\t\t\t// iOS Safari with a large photo — neither ever fires. With the picker\n\t\t\t// disabled by `processing`, that leaves the dropzone stuck on \"reading\n\t\t\t// your photo…\" with no way out: the exact dead end this flow is meant to\n\t\t\t// remove, just one screen earlier.\n\t\t\tprepared = await withTimeout(\n\t\t\t\tcompressImage(await heicToJpeg(await detachFile(file))),\n\t\t\t\tDECODE_TIMEOUT_MS\n\t\t\t);\n\t\t} catch (err) {\n\t\t\t// The picked photo couldn't be decoded into a bitmap (or took so long it\n\t\t\t// never will). Tell the user to try another instead of silently advancing\n\t\t\t// with a file the analyzer will reject, and fire upload_fail so the\n\t\t\t// previously-invisible decode miss is measurable.\n\t\t\tconst timedOut = err instanceof Error && err.message === 'decode_timeout';\n\t\t\tuploadError = timedOut\n\t\t\t\t? t('that photo took too long to open — try a smaller one.')\n\t\t\t\t: t(\"couldn't read that photo — try a different one.\");\n\t\t\tanalytics.trackUploadFail({\n\t\t\t\terror: timedOut ? 'image decode timeout' : 'image decode failed',\n\t\t\t\tcontext: 'decode',\n\t\t\t\tstale: false\n\t\t\t});\n\t\t\t// Let the same file be picked again: without this the input still holds\n\t\t\t// it, so re-selecting it fires no change event and the retry we just\n\t\t\t// invited does nothing.\n\t\t\tresetFileInputs();\n\t\t\tprocessing = false;\n\t\t\treturn;\n\t\t}\n\t\tselectedFile = prepared;\n\t\tanalytics.trackPhotoUpload(flow);\n\t\tprocessing = false;\n\t\tsetStep('mode');\n\t\tanalytics.trackFunnelStep('mode', flow);\n\t}\n\tasync function handleDrop(e: DragEvent) {\n\t\te.preventDefault();\n\t\tdragOver = false;\n\t\tawait handleFile(e.dataTransfer?.files[0]);\n\t}\n\tfunction handleDragOver(e: DragEvent) {\n\t\te.preventDefault();\n\t\tdragOver = true;\n\t\ticonBounce = true;\n\t}\n\tfunction handleDragLeave() {\n\t\tdragOver = false;\n\t\ticonBounce = false;\n\t}\n\t/** Longest we'll wait for the browser to turn a picked file into a bitmap.\n\t *  A healthy decode is well under a second even for a 12 MP phone photo. */\n\tconst DECODE_TIMEOUT_MS = 20_000;\n\n\tfunction withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst t = setTimeout(() => reject(new Error('decode_timeout')), ms);\n\t\t\tp.then(\n\t\t\t\t(v) => {\n\t\t\t\t\tclearTimeout(t);\n\t\t\t\t\tresolve(v);\n\t\t\t\t},\n\t\t\t\t(e) => {\n\t\t\t\t\tclearTimeout(t);\n\t\t\t\t\treject(e);\n\t\t\t\t}\n\t\t\t);\n\t\t});\n\t}\n\n\t/** Clear every file input so re-picking the SAME file still fires `change`. */\n\tfunction resetFileInputs() {\n\t\tif (typeof document === 'undefined') return;\n\t\tfor (const el of document.querySelectorAll<HTMLInputElement>('input[type=\"file\"]')) {\n\t\t\tel.value = '';\n\t\t}\n\t}\n\n\tasync function handleInput(e: Event) {\n\t\tawait handleFile((e.target as HTMLInputElement).files?.[0]);\n\t}\n\n\t// Photo reuse: pull the user's saved photo down as a File and run it through\n\t// the exact same path as a fresh upload — no pipeline changes, no re-pick.\n\tasync function useSavedPhoto() {\n\t\tif (!data.lastPhotoUrl) return;\n\t\ttry {\n\t\t\tconst res = await fetch(data.lastPhotoUrl);\n\t\t\tconst blob = await res.blob();\n\t\t\tselectedFile = new File([blob], 'reused.jpg', { type: blob.type || 'image/jpeg' });\n\t\t\tanalytics.trackPhotoUpload(flow);\n\t\t\tsetStep('mode');\n\t\t\tanalytics.trackFunnelStep('mode', flow);\n\t\t} catch {\n\t\t\tuploadError = t('could not load your saved photo — upload a new one.');\n\t\t}\n\t}\n\n\t// helper: call a SvelteKit form action programmatically\n\tasync function callAction(action: string, fields: Record<string, string>) {\n\t\tconst fd = new FormData();\n\t\tfor (const [key, value] of Object.entries(fields)) fd.append(key, value);\n\t\t// Epic R: what is rated. A dick rating posts exactly what it always did.\n\t\tif (subject !== 'dick') fd.append('subject', subject);\n\t\tconst response = await fetch(`/rate?/${action}`, { method: 'POST', body: fd });\n\t\treturn deserialize(await response.text());\n\t}\n\n\t// Upload the selected image to Supabase Storage, returning the path or null.\n\t//\n\t// Hardened for the primary get-rated funnel (signup hard-block):\n\t//  - EVERY failure branch (Supabase reject + thrown exception) is captured to\n\t//    PostHog with the underlying message, so the previously-invisible failure\n\t//    rate is measurable. `context` tags which entry point called us, `stale`\n\t//    flags a dead File handle.\n\t//  - Exactly ONE `upload_fail` per user-facing failure — the funnel number is\n\t//    a count of blocked users, not of internal attempts.\n\t//\n\t// There is deliberately no retry here: `handleFile` detaches the picked file\n\t// from its OS handle up front, so the bytes we hold can't go stale in the\n\t// first place. A retry would also have nothing to retry with — see the note\n\t// on `detachFile`.\n\tasync function uploadImage(context = 'rate'): Promise<string | null> {\n\t\tif (!selectedFile) return null;\n\t\ttry {\n\t\t\t// Signed upload: the server names the path (owner folder) so the\n\t\t\t// action can tell this upload apart from somebody else's.\n\t\t\tconst { path, error } = await uploadSubmissionPhoto(supabase, selectedFile, 'rate');\n\t\t\tif (!error) return path;\n\t\t\t// The upload-url endpoint or Supabase rejected the upload — no JS\n\t\t\t// exception, so this branch was previously silent on every entry point.\n\t\t\tconsole.error('Upload failed:', error.message);\n\t\t\tanalytics.trackUploadFail({\n\t\t\t\terror: error.message,\n\t\t\t\tcontext,\n\t\t\t\tstale: isStaleFileError(error)\n\t\t\t});\n\t\t\treturn null;\n\t\t} catch (err) {\n\t\t\t// Reached for what storage-js re-throws (anything that isn't a\n\t\t\t// StorageError) and for a network failure reaching the upload-url endpoint.\n\t\t\tconst message = err instanceof Error ? `${err.name}: ${err.message}` : String(err);\n\t\t\tconsole.error('Upload threw:', message);\n\t\t\tanalytics.trackUploadFail({ error: message, context, stale: isStaleFileError(err) });\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tlet analyzing = $state(false);\n\n\tasync function startRating() {\n\t\tanalytics.trackModeSelect(mode, flow);\n\n\t\t// RAT-199: signed-in non-pro user who already used their one free\n\t\t// analysis → bounce to /pricing where the Pro plan + their last\n\t\t// result link live. We do NOT start a new analysis under any\n\t\t// circumstance for them — that's the paywall.\n\t\tif (data.session && data.canGenerate === false) {\n\t\t\tanalytics.trackUpgradeModalOpen('already_used_redirect');\n\t\t\t// replaceState, not push: the mode step this fired from must NOT be\n\t\t\t// left in history, or Back drops the user straight back into the\n\t\t\t// upload→mode loop they just failed. This is only a backstop now —\n\t\t\t// the upload step already discloses the used-up state up front.\n\t\t\tawait goto('/?upsell=already_used', { replaceState: true });\n\t\t\treturn;\n\t\t}\n\n\t\t// Video path (subscriber-only — the picker is gated on data.canVideo and\n\t\t// the server action re-checks). Uploads the clip and starts the analysis;\n\t\t// no email/anon branch exists here because a sub always has a session.\n\t\tif (selectedVideo) {\n\t\t\tif (!data.session) {\n\t\t\t\tuploadError = t('sign in to rate a video.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tanalyzing = true;\n\t\t\tuploadError = '';\n\t\t\tanalytics.trackAnalysisStart(mode, flow);\n\t\t\tconst videoPath = await uploadVideo();\n\t\t\tif (!videoPath) {\n\t\t\t\tuploadError = t('video upload failed — try again.');\n\t\t\t\tanalyzing = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await callAction('startAnalysis', {\n\t\t\t\tmode,\n\t\t\t\timagePath: videoPath,\n\t\t\t\tsavePhoto: 'false',\n\t\t\t\tcsamAck: String(csamAck),\n\t\t\t\tmediaKind: 'video',\n\t\t\t\tdurationSec: String(videoDurationSec ?? '')\n\t\t\t});\n\t\t\tif (result.type === 'success') {\n\t\t\t\tconst d = result.data as Record<string, unknown>;\n\t\t\t\tconst generationId = d?.generationId as string;\n\t\t\t\tgoingToResult = true;\n\t\t\t\tawait goto(`/rate/result/${generationId}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tanalyzing = false;\n\t\t\treturn;\n\t\t}\n\n\t\t// if user has active session, upload image + save generation server-side + go to result\n\t\tif (data.session) {\n\t\t\tanalyzing = true;\n\t\t\tuploadError = '';\n\t\t\tanalytics.trackAnalysisStart(mode, flow);\n\t\t\tconst imagePath = await uploadImage('logged_in');\n\t\t\tif (!imagePath) {\n\t\t\t\tuploadError = t('image upload failed. try a different photo or format.');\n\t\t\t\t// No `analysis_fail(upload_failed)` here: `upload_fail` now covers every\n\t\t\t\t// upload failure on every entry point, with the real error string and a\n\t\t\t\t// `context` tag. Firing both double-counted this one failure and split\n\t\t\t\t// the funnel across two events — replaced in place, not run in parallel.\n\t\t\t\tanalyzing = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst result = await callAction('startAnalysis', { mode, imagePath, savePhoto: String(savePhoto), csamAck: String(csamAck) });\n\t\t\tif (result.type === 'success') {\n\t\t\t\tconst d = result.data as Record<string, unknown>;\n\t\t\t\tconst generationId = d?.generationId as string;\n\t\t\t\tgoingToResult = true;\n\t\t\t\t// Navigate immediately. The previous smooth-scroll +\n\t\t\t\t// 400ms setTimeout setup looked smooth on desktop but\n\t\t\t\t// felt broken on mobile: the button reverted to \"analyze\n\t\t\t\t// my pic\", the page just scrolled, and users tapped\n\t\t\t\t// again because nothing visibly happened (RAT-129). The\n\t\t\t\t// result page renders its own loader the moment it\n\t\t\t\t// mounts. Don't reset `analyzing` — we're unmounting.\n\t\t\t\tawait goto(`/rate/result/${generationId}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tanalyzing = false;\n\t\t\treturn;\n\t\t}\n\n\t\t// Signed out: rate it now and ask for the account on the result page,\n\t\t// once they can see a rating exists (anon-rate.ts). The mandatory sign-in\n\t\t// that used to sit here, before any result, lost about a third of the\n\t\t// people who reached it. The result page shows the rating blurred behind\n\t\t// the sign-up and claims it for them when they come back signed in.\n\t\tanalyzing = true;\n\t\tuploadError = '';\n\t\tconst imagePath = await uploadImage('anon');\n\t\tif (!imagePath) {\n\t\t\tuploadError = t('image upload failed. try a different photo or format.');\n\t\t\tanalyzing = false;\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst result = await callAction('startAnonAnalysis', { mode, imagePath });\n\t\t\tif (result.type === 'success') {\n\t\t\t\tconst d = result.data as Record<string, unknown>;\n\t\t\t\tgoingToResult = true;\n\t\t\t\t// Navigate immediately — the result page renders its own loader.\n\t\t\t\tawait goto(`/rate/result/${d?.generationId as string}`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst d = result.type === 'failure' ? (result.data as Record<string, unknown>) : undefined;\n\t\t\tif (d?.error === 'limit') {\n\t\t\t\t// Past the signed-out allowance (ANON_RATE_LIMITS): the account is the\n\t\t\t\t// way on, and the photo is still picked when they come back from it.\n\t\t\t\tuploadError = t(\"that's today's free ratings without an account — sign in to keep going.\");\n\t\t\t\topenAuthSheet(undefined, 'rate_anon_limit');\n\t\t\t} else {\n\t\t\t\tuploadError = (d?.error as string) || t('something went wrong. try again.');\n\t\t\t}\n\t\t} catch {\n\t\t\tuploadError = t('network error — check your connection and try again.');\n\t\t}\n\t\tanalyzing = false;\n\t}\n\n\t// A `?step=` left in the URL by a reload has no photo behind it, and a Google\n\t// sign-in raised from the sheet on this page comes back with `?oauth_resume=1`.\n\t// Neither means anything to a fresh page. On the first load SvelteKit runs\n\t// afterNavigate a beat before its router counts as started, and replaceState\n\t// throws until then — hence the microtask.\n\tafterNavigate(() => {\n\t\tconst url = new URL(page.url);\n\t\tif (!url.searchParams.has('step') && !url.searchParams.has('oauth_resume')) return;\n\t\turl.searchParams.delete('step');\n\t\turl.searchParams.delete('oauth_resume');\n\t\tqueueMicrotask(() => replaceState(url, {}));\n\t});\n</script>\n\n{#if step === 'upload'}\n<!-- ============================================================ -->\n<!--  UPLOAD                                                        -->\n<!-- ============================================================ -->\n<!-- Batch 24: min-h-screen dropped + top padding pulled in. The page is\n\t content-height now so the dropzone + CTA fit first-view.\n\t RAT-278: pt-14 was tighter than the Navbar h-16 (64px) — heading slid\n\t under the nav. pt-20 (80px) restores a 16px gap. min-h-svh + section-\n\t owned pb-[calc(100+env)] + body.fit-screen (zeroes main pb) keeps\n\t the page exactly viewport-height on iPhone Chrome. -->\n<section class=\"relative flex min-h-svh flex-col overflow-hidden pt-20 pb-[calc(100px+env(safe-area-inset-bottom))] md:pt-28 md:pb-28\">\n\t<div class=\"pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(255,255,255,.006)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,.006)_1px,transparent_1px)] bg-[size:60px_60px]\"></div>\n\n\t<div class=\"relative mx-auto w-full max-w-5xl px-5 md:px-0\">\n\t\t{#if data.session && data.canGenerate === false}\n\t\t\t<!-- RAT-199: the free rating is already spent. `canGenerate` is known\n\t\t\t\t at load, so disclose it HERE, before the user picks a photo and a\n\t\t\t\t mode — rather than uploading, committing, then getting ejected off\n\t\t\t\t the mode step (which read as a broken button and drove the retry\n\t\t\t\t loop). No dropzone for this user; just the Pro CTA + their last\n\t\t\t\t result. -->\n\t\t\t<!-- The gate also trips while an analysis is still running, and that\n\t\t\t\t user has never had a rating — \"you've used your one free rating\"\n\t\t\t\t would be flatly untrue, and it's the screen the result page's\n\t\t\t\t timeout CTA sends people to. Say what's actually happening and\n\t\t\t\t point at the run. -->\n\t\t\t<div class=\"max-w-xl\">\n\t\t\t\t<h1 class=\"font-display text-[clamp(2.4rem,8vw,7rem)] font-bold leading-[0.9] tracking-tighter\">\n\t\t\t\t\t{#if data.pendingGenerationId}\n\t\t\t\t\t\t{t('still')}<br /><span class=\"text-coral\">{t('working on it.')}</span>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t{t(\"that's a wrap\")}<br /><span class=\"text-coral\">{t('on the free one.')}</span>\n\t\t\t\t\t{/if}\n\t\t\t\t</h1>\n\t\t\t\t<p class=\"mt-3 max-w-md text-sm leading-relaxed text-muted md:mt-8 md:text-lg\">\n\t\t\t\t\t{#if data.pendingGenerationId}\n\t\t\t\t\t\t{t(\"your rating is still being analyzed — open it to see where it's at. go Pro for unlimited roasts and hype — {price}/mo.\", { price: PRO_MONTHLY_LABEL })}\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t{t(\"you've used your one free rating. go Pro for unlimited roasts and hype — {price}/mo.\", { price: PRO_MONTHLY_LABEL })}\n\t\t\t\t\t{/if}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"mt-6 flex flex-col gap-3 sm:flex-row sm:items-center md:mt-10\">\n\t\t\t\t\t{#if data.pendingGenerationId}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={`/rate/result/${data.pendingGenerationId}`}\n\t\t\t\t\t\t\tclass=\"inline-block rounded-xl bg-coral px-7 py-4 text-center font-display text-base font-semibold text-white no-underline transition-all hover:bg-coral-dark\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t('open my rating →')}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref=\"/pricing\"\n\t\t\t\t\t\t\tclass=\"text-center text-sm font-medium text-muted no-underline transition-colors hover:text-text\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t('go unlimited →')}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref=\"/pricing\"\n\t\t\t\t\t\t\tclass=\"inline-block rounded-xl bg-coral px-7 py-4 text-center font-display text-base font-semibold text-white no-underline transition-all hover:bg-coral-dark\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t('go unlimited →')}\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t{#if data.lastGenerationId}\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={`/rate/result/${data.lastGenerationId}`}\n\t\t\t\t\t\t\t\tclass=\"text-center text-sm font-medium text-muted no-underline transition-colors hover:text-text\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t('see your last rating →')}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t{/if}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t{:else}\n\t\t{#if !data.isSubscribed && (data.tokens ?? 0) < 10 && (data.tokens ?? 0) > 0}\n\t\t\t<a href=\"/pricing\" class=\"mb-6 flex items-center justify-between rounded-xl border border-border bg-surface/50 px-4 py-3 no-underline transition-all hover:border-muted/30\">\n\t\t\t\t<span class=\"text-[13px] text-muted\"><strong class=\"text-text\">{data.tokens}</strong> {t('tokens left — need')} <strong class=\"text-text\">10</strong> {t('to rate.')} <span class=\"text-coral\">{t('go unlimited for {price}/mo', { price: PRO_MONTHLY_LABEL })}</span></span>\n\t\t\t\t<svg class=\"h-4 w-4 shrink-0 text-muted/30\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\"/></svg>\n\t\t\t</a>\n\t\t{/if}\n\n\t\t<!-- Batch 24: step indicator removed — the upload-then-mode flow is\n\t\t\t only 2 steps and the visual scaffolding ate first-viewport real\n\t\t\t estate. -->\n\t\t{@render top?.()}\n\n\t\t<h1 class=\"font-display text-[clamp(2.4rem,8vw,7rem)] font-bold leading-[0.9] tracking-tighter\">\n\t\t\t{@render heading()}\n\t\t</h1>\n\n\t\t<p class=\"mt-3 max-w-md text-sm leading-relaxed text-muted md:mt-8 md:text-lg\">\n\t\t\t{@render intro()}\n\t\t</p>\n\n\t\t<div class=\"mt-6 max-w-xl md:mt-10\">\n\t\t\t{#snippet dropzone()}\n\t\t\t\t<label\n\t\t\t\t\tclass=\"block rounded-2xl border px-6 py-8 transition-all duration-300 md:py-14\n\t\t\t\t\t\t{processing\n\t\t\t\t\t\t? 'cursor-wait border-border bg-surface'\n\t\t\t\t\t\t: dragOver\n\t\t\t\t\t\t? 'cursor-pointer border-coral/30 bg-coral/[.03] shadow-[inset_0_1px_20px_rgba(255,77,109,.05)]'\n\t\t\t\t\t\t: 'cursor-pointer border-border bg-surface shadow-[inset_0_1px_10px_rgba(0,0,0,.2)] hover:border-muted'}\"\n\t\t\t\t\tondrop={handleDrop}\n\t\t\t\t\tondragover={handleDragOver}\n\t\t\t\t\tondragleave={handleDragLeave}\n\t\t\t\t>\n\t\t\t\t\t<input type=\"file\" accept=\"image/*\" class=\"hidden\" onchange={handleInput} disabled={processing} bind:this={fileInput} />\n\t\t\t\t\t{#if processing}\n\t\t\t\t\t\t<!-- Pending state — covers the async decode window (detach → HEIC\n\t\t\t\t\t\t\t convert → compress) so a freshly-picked file gives instant\n\t\t\t\t\t\t\t feedback instead of a dead-looking dropzone. -->\n\t\t\t\t\t\t<div class=\"mx-auto h-11 w-11 animate-spin rounded-full border-4 border-border border-t-coral\"></div>\n\t\t\t\t\t\t<p class=\"mt-3 text-center font-display text-base font-bold\">{t('reading your photo…')}</p>\n\t\t\t\t\t\t<p class=\"mt-1 text-center text-xs text-muted\">{t('hang tight — prepping your upload')}</p>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t<div class=\"mx-auto flex h-11 w-11 items-center justify-center rounded-xl border border-border bg-bg transition-transform duration-300 {iconBounce ? '-translate-y-1' : ''}\">\n\t\t\t\t\t\t\t<svg class=\"h-5 w-5 text-muted\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"1.5\">\n\t\t\t\t\t\t\t\t<path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5\" />\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p class=\"mt-3 text-center font-display text-base font-bold\">{t('drag & drop here')}</p>\n\t\t\t\t\t\t<p class=\"mt-1 text-center text-xs text-muted\">{t('or browse your gallery of regrets')}</p>\n\t\t\t\t\t\t<div class=\"mt-4 text-center\">\n\t\t\t\t\t\t\t<span class=\"inline-block rounded-lg bg-coral px-7 py-3 text-sm font-semibold text-white transition-all hover:bg-coral-dark\">\n\t\t\t\t\t\t\t\t{t('choose file')}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t{/if}\n\t\t\t\t</label>\n\t\t\t{/snippet}\n\n\t\t\t<ReusePhoto\n\t\t\t\tloggedIn={!!data.session}\n\t\t\t\tlastPhotoUrl={data.lastPhotoUrl ?? null}\n\t\t\t\tothers={reuseOthers}\n\t\t\t\tuseBtnClass=\"bg-coral text-white\"\n\t\t\t\ttoggleOnClass=\"bg-coral\"\n\t\t\t\tsaveMode={data.session ? 'toggle' : 'signup'}\n\t\t\t\tbind:save={savePhoto}\n\t\t\t\tonToggle={(v) => analytics.trackSavePhotoToggle(v)}\n\t\t\t\tonSignUp={() => {\n\t\t\t\t\t// Never hand a picked file to the sheet: its Google button does a\n\t\t\t\t\t// full-page redirect, and the photo doesn't survive it. The upload\n\t\t\t\t\t// step normally unmounts the instant a file lands, so this is a\n\t\t\t\t\t// guard rather than a hot path — continue into the page's own flow,\n\t\t\t\t\t// which rates the photo signed out and asks for the account after.\n\t\t\t\t\tif (selectedFile) setStep('mode');\n\t\t\t\t\telse openAuthSheet(undefined, 'rate_reuse');\n\t\t\t\t}}\n\t\t\t\tonBack={() => { selectedFile = null; }}\n\t\t\t\tonUseSaved={useSavedPhoto}\n\t\t\t\tupload={dropzone}\n\t\t\t/>\n\n\t\t\t{#if uploadError}\n\t\t\t\t<p class=\"mt-3 text-xs text-coral\">{uploadError}</p>\n\t\t\t{/if}\n\n\t\t\t<!-- Video rating entry — subscriber feature. Subs get the real picker;\n\t\t\t\t signed-in non-subs see the locked variant that routes to the upsell.\n\t\t\t\t Anonymous visitors see nothing (a sub always has a session). -->\n\t\t\t{#if data.session}\n\t\t\t\t{#if data.canVideo}\n\t\t\t\t\t<label\n\t\t\t\t\t\tclass=\"mt-4 flex cursor-pointer items-center justify-center gap-2 rounded-xl border border-border bg-surface px-4 py-3 text-sm text-muted transition-colors hover:border-muted hover:text-text\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t\t\taccept={VIDEO_ACCEPT}\n\t\t\t\t\t\t\tclass=\"hidden\"\n\t\t\t\t\t\t\tonchange={handleVideoInput}\n\t\t\t\t\t\t\tdisabled={processing}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<svg class=\"h-4 w-4 shrink-0\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\" /></svg>\n\t\t\t\t\t\t<span>{t('or rate a')} <b class=\"text-text\">{t('video')}</b> {t('— up to {n}s', { n: MAX_VIDEO_SEC })}</span>\n\t\t\t\t\t</label>\n\t\t\t\t{:else}\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tonclick={() => goto('/?upsell=video_rating')}\n\t\t\t\t\t\tclass=\"mt-4 flex w-full items-center justify-center gap-2 rounded-xl border border-border bg-surface px-4 py-3 text-sm text-muted transition-colors hover:border-muted hover:text-text\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<svg class=\"h-3.5 w-3.5 shrink-0\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n\t\t\t\t\t\t\t<rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<span>{t('video rating is a')} <b class=\"text-text\">{t('pro')}</b> {t('feature')}</span>\n\t\t\t\t\t</button>\n\t\t\t\t{/if}\n\t\t\t{/if}\n\t\t</div>\n\n\t\t<p class=\"mt-3 flex items-center gap-1.5 text-xs text-muted\">\n\t\t\t<svg class=\"h-3 w-3 shrink-0 text-muted\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n\t\t\t\t<rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" /><path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n\t\t\t</svg>\n\t\t\t{t('zero storage · deleted instantly · encrypted')}\n\t\t</p>\n\n\t\t<!-- RAT-507: \"not ready to upload?\", the sheet that won its test (468971,\n\t\t\t RAT-555). -->\n\t\t<NotNowSheet onupload={() => fileInput?.click()} />\n\t\t{/if}\n\t</div>\n</section>\n\n{@render children?.()}\n\n{:else if step === 'mode'}\n<!-- ============================================================ -->\n<!--  MODE                                                          -->\n<!-- ============================================================ -->\n<!-- RAT-278: same nav-clipping + iOS Chrome scroll fix as upload step. -->\n<section class=\"relative flex min-h-svh flex-col overflow-hidden pt-20 pb-[calc(100px+env(safe-area-inset-bottom))] md:pt-28 md:pb-28\">\n\t<div class=\"pointer-events-none absolute inset-0 bg-[linear-gradient(rgba(255,255,255,.006)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,.006)_1px,transparent_1px)] bg-[size:60px_60px]\"></div>\n\n\t<!-- left-aligned column, matching the upload step (\"drop your masterpiece\") -->\n\t<div class=\"relative mx-auto w-full max-w-5xl px-5 md:px-0\">\n\t\t<h1 class=\"font-display text-[clamp(2.4rem,8vw,7rem)] font-bold leading-[0.9] tracking-tighter\">\n\t\t\t{t('choose your')}<br /><span class={ac}>{t('fighter.')}</span>\n\t\t</h1>\n\t\t<p class=\"mt-3 max-w-md text-sm leading-relaxed text-muted md:mt-8 md:text-lg\">\n\t\t\t{t('two personalities. pick one, get rated.')}\n\t\t</p>\n\t\t{#if selectedVideo}\n\t\t\t<p class=\"mt-2 inline-flex items-center gap-1.5 rounded-lg bg-surface px-3 py-1.5 text-xs text-muted\">\n\t\t\t\t<svg class=\"h-3 w-3 shrink-0\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M8 5v14l11-7z\" /></svg>\n\t\t\t\t{t('video · {n}s — we sample a few frames and judge the whole clip', { n: videoDurationSec ?? '' })}\n\t\t\t</p>\n\t\t{/if}\n\n\t\t<!-- content column (cards + cta + controls), capped like the dropzone -->\n\t\t<div class=\"mt-6 max-w-xl md:mt-10\">\n\t\t<!-- mode selector: two calm fighter cards. selected = a soft accent tint +\n\t\t\t a stronger (not glowing) accent border. -->\n\t\t<div class=\"grid grid-cols-2 gap-3\">\n\t\t\t<!-- roast -->\n\t\t\t<button\n\t\t\t\tclass=\"flex min-h-[130px] flex-col rounded-2xl border p-4 pb-5 text-left transition-colors md:min-h-[150px] {mode === 'roast'\n\t\t\t\t\t? 'border-coral/50 bg-coral/[.06]'\n\t\t\t\t\t: 'border-border bg-surface hover:border-muted/40'}\"\n\t\t\t\tonclick={() => (mode = 'roast')}\n\t\t\t>\n\t\t\t\t<div class=\"flex items-center justify-between\">\n\t\t\t\t\t<div class=\"flex items-center gap-2\">\n\t\t\t\t\t\t<div class=\"h-2 w-2 rounded-full bg-coral {mode === 'roast' ? '' : 'opacity-40'}\"></div>\n\t\t\t\t\t\t<span class=\"text-[11px] font-semibold tracking-widest uppercase {mode === 'roast' ? 'text-coral' : 'text-muted'}\">roast</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"text-[11px] font-semibold tabular-nums {mode === 'roast' ? 'text-coral/70' : 'text-muted/40'}\">63%</span>\n\t\t\t\t</div>\n\t\t\t\t<p class=\"mt-auto pt-4 font-display text-lg font-bold leading-tight tracking-tight md:text-2xl {mode === 'roast' ? 'text-coral' : 'text-text/60'}\">{t('\"bro,')}<br />{t('delete this.\"')}</p>\n\t\t\t</button>\n\n\t\t\t<!-- hype -->\n\t\t\t<button\n\t\t\t\tclass=\"flex min-h-[130px] flex-col rounded-2xl border p-4 pb-5 text-left transition-colors md:min-h-[150px] {mode === 'hype'\n\t\t\t\t\t? 'border-yellow/50 bg-yellow/[.06]'\n\t\t\t\t\t: 'border-border bg-surface hover:border-muted/40'}\"\n\t\t\t\tonclick={() => (mode = 'hype')}\n\t\t\t>\n\t\t\t\t<div class=\"flex items-center justify-between\">\n\t\t\t\t\t<div class=\"flex items-center gap-2\">\n\t\t\t\t\t\t<div class=\"h-2 w-2 rounded-full bg-yellow {mode === 'hype' ? '' : 'opacity-40'}\"></div>\n\t\t\t\t\t\t<span class=\"text-[11px] font-semibold tracking-widest uppercase {mode === 'hype' ? 'text-yellow' : 'text-muted'}\">hype</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"text-[11px] font-semibold tabular-nums {mode === 'hype' ? 'text-yellow/70' : 'text-muted/40'}\">37%</span>\n\t\t\t\t</div>\n\t\t\t\t<p class=\"mt-auto pt-4 font-display text-lg font-bold leading-tight tracking-tight md:text-2xl {mode === 'hype' ? 'text-yellow' : 'text-text/60'}\">\n\t\t\t\t\t{#if subject === 'dick'}{t('\"king')}<br />{t('shit.\"')}{:else}{t('\"main')}<br />{t('character.\"')}{/if}\n\t\t\t\t</p>\n\t\t\t</button>\n\t\t</div>\n\n\t\t<!-- full-width CTA -->\n\t\t<button\n\t\t\tclass=\"mt-5 w-full rounded-xl py-4 font-display text-base font-semibold transition-all active:scale-[0.99] disabled:opacity-50\n\t\t\t\t{mode === 'roast'\n\t\t\t\t? 'bg-coral text-white hover:bg-coral-dark'\n\t\t\t\t: 'bg-yellow text-bg hover:bg-yellow/80'}\"\n\t\t\tonclick={startRating}\n\t\t\tdisabled={analyzing}\n\t\t>\n\t\t\t{#if analyzing}\n\t\t\t\t{t('analyzing...')}\n\t\t\t{:else}\n\t\t\t\t{selectedVideo ? t('analyze my clip →') : t('analyze my pic →')}\n\t\t\t{/if}\n\t\t</button>\n\t\t{#if !data.session}\n\t\t\t<!-- Say BEFORE the tap what the account is for: the photo is rated\n\t\t\t\t without one, and a free sign-up on the result page unlocks the\n\t\t\t\t score. An undisclosed wall after the CTA read as a bait-and-switch. -->\n\t\t\t<p class=\"mt-2.5 text-center text-[12.5px] text-muted\">\n\t\t\t\t{t('free · rated in seconds · a free sign-up unlocks your score')}\n\t\t\t</p>\n\t\t{/if}\n\t\t{#if uploadError}\n\t\t\t<p class=\"mt-4 text-center text-xs text-coral\">{uploadError}</p>\n\t\t{/if}\n\n\t\t<hr class=\"my-5 border-0 border-t border-border\" />\n\n\t\t<!-- controls row: save-photo toggle + sample expander -->\n\t\t<div class=\"flex items-center justify-between gap-3\">\n\t\t\t<!-- Signed out there's no account to keep a photo for: the rating is\n\t\t\t\t made without saving it (startAnonAnalysis), so no toggle. -->\n\t\t\t{#if data.session}\n\t\t\t\t<button\n\t\t\t\t\tclass=\"flex items-center gap-2.5 text-left\"\n\t\t\t\t\tonclick={() => { savePhoto = !savePhoto; analytics.trackSavePhotoToggle(!savePhoto); }}\n\t\t\t\t>\n\t\t\t\t\t<span class=\"text-[12.5px] leading-snug text-muted\">{t('save photo for foil cards')}</span>\n\t\t\t\t\t<span class=\"relative h-5 w-9 shrink-0 rounded-full transition-colors duration-200 {savePhoto ? 'bg-blue' : 'bg-border'}\">\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"absolute top-0.5 block h-4 w-4 rounded-full bg-white shadow transition-transform duration-200\n\t\t\t\t\t\t\t\t{savePhoto ? 'translate-x-4' : 'translate-x-0.5'}\"\n\t\t\t\t\t\t></span>\n\t\t\t\t\t</span>\n\t\t\t\t</button>\n\t\t\t{/if}\n\n\t\t\t<button\n\t\t\t\tclass=\"ml-auto inline-flex shrink-0 items-center gap-1.5 text-[12.5px] text-muted transition-colors hover:text-text\"\n\t\t\t\tonclick={() => (showSample = !showSample)}\n\t\t\t>\n\t\t\t\t{mode === 'roast' ? t('see a sample roast') : t('see a sample hype')}\n\t\t\t\t<span class=\"text-[9px]\">{showSample ? '▲' : '▼'}</span>\n\t\t\t</button>\n\t\t</div>\n\n\t\t{#if showSample}\n\t\t\t<div\n\t\t\t\tclass=\"relative mt-2.5 max-w-xl overflow-hidden rounded-xl border p-3.5 {mode === 'roast' ? 'border-coral/15 bg-coral/[.03]' : 'border-yellow/15 bg-yellow/[.03]'}\"\n\t\t\t>\n\t\t\t\t{#if mode === 'roast'}<FireParticles mobile />{:else}<StarParticles mobile />{/if}\n\t\t\t\t<div class=\"relative z-10\">\n\t\t\t\t\t<p class=\"text-[10px] font-semibold uppercase tracking-widest {mode === 'roast' ? 'text-coral/45' : 'text-yellow/45'}\">{t('AI output · {mode}', { mode })}</p>\n\t\t\t\t\t<p class=\"mt-1.5 text-[13px] leading-relaxed {mode === 'roast' ? 'text-coral/80' : 'text-yellow/80'}\">\n\t\t\t\t\t\t{#if mode === 'roast'}\n\t\t\t\t\t\t\t{t('\"5.2/10 — the bathroom mirror selfie era needs to end. your lighting screams 3am existential crisis. also, we can see your laundry.\"')}\n\t\t\t\t\t\t{:else if subject === 'dick'}\n\t\t\t\t\t\t\t{t('\"9.1/10 — genuinely top 15%. the proportions are impressive and the grooming shows real effort. you are absolutely built different.\"')}\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t{t('\"9.1/10 — genuinely top 15%. the shape is unreal and that side light is doing all the right things. you are absolutely built different.\"')}\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t</p>\n\t\t\t\t\t<div class=\"mt-3 flex gap-4 text-[11px] {mode === 'roast' ? 'text-coral/50' : 'text-yellow/50'}\">\n\t\t\t\t\t\t{#if mode === 'roast'}\n\t\t\t\t\t\t\t<span>{t('avg score:')} <strong class=\"text-coral\">5.8</strong></span>\n\t\t\t\t\t\t\t<span>{t('avg tears:')} <strong class=\"text-coral\">{t('many')}</strong></span>\n\t\t\t\t\t\t\t<span>{t('regret:')} <strong class=\"text-coral\">47%</strong></span>\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t<span>{t('avg score:')} <strong class=\"text-yellow\">8.4</strong></span>\n\t\t\t\t\t\t\t<span>{t('avg confidence:')} <strong class=\"text-yellow\">+340%</strong></span>\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t{/if}\n\t\t</div>\n\t</div>\n</section>\n\n{/if}\n","<script lang=\"ts\">\n\t/**\n\t * Epic R: one AI rater per subject, each on a page of its own. The switch is\n\t * links, not buttons, so every page gets crawled and ranks for its own\n\t * search (\"rate my boobs\" is /rate-my-boobs, not /rate with a tab open). It\n\t * looks like beat me's category switch, which people already know.\n\t */\n\timport { t } from '$lib/i18n';\n\timport { msg } from '$lib/i18n/mark';\n\timport { RATE_SUBJECTS, RATE_SUBJECT_PATH, type RateSubject } from '$lib/rate-subjects';\n\n\tlet { active }: { active: RateSubject } = $props();\n\n\tconst LABEL: Record<RateSubject, string> = {\n\t\tdick: msg('dick'),\n\t\tboobs: msg('boobs'),\n\t\tass: msg('ass'),\n\t\tnudes: msg('nudes')\n\t};\n</script>\n\n<nav\n\taria-label={t('what to rate')}\n\tclass=\"mb-6 grid w-full max-w-md grid-cols-4 gap-1 rounded-xl bg-surface p-1 md:mb-8\"\n>\n\t{#each RATE_SUBJECTS as s (s)}\n\t\t<a\n\t\t\thref={RATE_SUBJECT_PATH[s]}\n\t\t\taria-current={active === s ? 'page' : undefined}\n\t\t\tclass=\"flex min-h-11 items-center justify-center rounded-lg font-display text-[15px] font-bold tracking-tight no-underline transition-colors {active ===\n\t\t\ts\n\t\t\t\t? 'bg-surface-2 text-text shadow-[0_1px_3px_rgba(0,0,0,0.5)]'\n\t\t\t\t: 'text-muted hover:text-text'}\"\n\t\t>\n\t\t\t{t(LABEL[s])}\n\t\t</a>\n\t{/each}\n</nav>\n"],"version":3}