wealth-alpha-chat-widget 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/session.ts","../src/api/chatApi.ts","../src/hooks/useAuth.ts","../src/hooks/useChat.ts","../src/hooks/useChip.ts","../src/hooks/useSession.ts","../src/styles/chat.module.css","../src/components/AuthGate.tsx","../src/components/Chip.tsx","../src/components/ChipRow.tsx","../src/utils/markdown.ts","../src/components/MessageBubble.tsx","../src/components/TypingIndicator.tsx","../src/components/ChatBody.tsx","../src/utils/time.ts","../src/components/ChatHeader.tsx","../src/components/ChatInput.tsx","../src/components/FloatingButton.tsx","../src/components/WealthChat.tsx"],"names":["fallback","useRef","useEffect","useCallback","useState","root","floatingButton","positionRight","positionLeft","widget","popupBubbleLeft","popupBubbleRight","header","headerTitle","headerMeta","headerActions","iconButton","body","bubble","markdown","bubbleBot","bubbleUser","chipRow","chip","chipActive","chipDisabled","typing","typingDot","input","inputBox","sendButton","hiddenFileInput","authGate","authGateIcon","authGateTitle","authGateText","authGateButton","authGateDisclaimer","authGateDisclaimerTitle","errorBanner","popupBubble","popupDismiss","jsxs","jsx"],"mappings":";;;;;;;AAEO,IAAM,WAAA,GAAc;AACpB,IAAM,2BAAA,GAA8B;AACpC,IAAM,WAAA,GAAc,GAAA;AAI3B,IAAM,mBAAA,GAAsB,CAAC,OAAA,EAAS,cAAA,EAAgB,cAAc,KAAK,CAAA;AAEzE,IAAM,YAAY,MAChB,OAAO,WAAW,WAAA,IAAe,OAAO,OAAO,YAAA,KAAiB,WAAA;AAElE,SAAS,gBAAgB,KAAA,EAAuB;AAC9C,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AACzD,EAAA,MAAM,SAAS,MAAA,GAAS,KAAA,CAAM,OAAO,MAAA,CAAO,MAAA,GAAS,KAAK,CAAC,CAAA;AAC3D,EAAA,OAAO,KAAK,MAAM,CAAA;AACpB;AAEA,SAAS,UAAU,KAAA,EAA+C;AAChE,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,MAAM,MAAA,KAAW,CAAA,IAAK,CAAC,KAAA,CAAM,CAAC,GAAG,OAAO,IAAA;AAC5C,IAAA,OAAO,KAAK,KAAA,CAAM,eAAA,CAAgB,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAAA,EAC7C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,aAAa,KAAA,EAA8B;AAClD,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,MAAM,GAAA,GAAM,UAAU,KAAK,CAAA;AAC3B,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,IAAA;AACpC,EAAA,OAAO,GAAA,GAAM,GAAA;AACf;AAEA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,IAAI,CAAC,SAAS,OAAO,EAAA;AACrB,EAAA,MAAM,EAAA,GAAK,QAAQ,IAAI,CAAA,IAAK,QAAQ,KAAK,CAAA,IAAK,QAAQ,SAAS,CAAA;AAC/D,EAAA,OAAO,EAAA,IAAM,IAAA,GAAO,MAAA,CAAO,EAAE,CAAA,GAAI,EAAA;AACnC;AAEA,SAAS,iBAAA,GAA2D;AAClE,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,KAAA,MAAW,OAAO,mBAAA,EAAqB;AACrC,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC7C,IAAA,IAAI,KAAA,IAAS,MAAM,MAAA,GAAS,EAAA,SAAW,EAAE,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,EAC7D;AACA,EAAA,OAAO,IAAA;AACT;AAEA,IAAM,UAAA,GAAa,CAAC,MAAA,KAA2B;AAC7C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAA,CAAO,YAAY,CAAA,CAAA;AAAA,EACzC;AACA,EAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,KAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAC,IAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACxF,CAAA;AAEO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,WAAW,KAAK,CAAA;AACzB;AAEO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,WAAW,KAAK,CAAA;AACzB;AAEO,SAAS,WAAA,GAAiC;AAC/C,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AACnD,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC9B,MAAA,MAAM,QACJ,OAAA,IACA,OAAO,OAAA,CAAQ,KAAA,KAAU,YACzB,OAAA,CAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,IACvB,OAAO,OAAA,CAAQ,SAAA,KAAc,YAC7B,IAAA,CAAK,GAAA,KAAQ,OAAA,CAAQ,SAAA;AACvB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,MAAMA,YAAW,iBAAA,EAAkB;AAGnC,QAAA,IAAI,CAACA,SAAAA,IAAY,OAAA,CAAQ,UAAA,KAAe,UAAA,EAAY;AAClD,UAAA,YAAA,EAAa;AACb,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,IAAIA,SAAAA,IAAYA,SAAAA,CAAS,KAAA,KAAU,OAAA,CAAQ,KAAA,EAAO;AAChD,UAAA,OAAO,kBAAA,CAAmBA,SAAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AAAA,QACnD;AACA,QAAA,OAAO,OAAA;AAAA,MACT;AAEA,MAAA,YAAA,EAAa;AAAA,IACf;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,YAAA,EAAa;AAAA,EACf;AAEA,EAAA,MAAM,WAAW,iBAAA,EAAkB;AACnC,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,EAAA,OAAO,kBAAA,CAAmB,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AAChD;AAEA,SAAS,kBAAA,CAAmB,OAAe,KAAA,EAA6C;AACtF,EAAA,MAAM,MAAA,GAAS,aAAa,KAAK,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,SAAA,GAAY,MAAA,IAAU,GAAA,GAAM,2BAAA,GAA8B,GAAA;AAChE,EAAA,IAAI,GAAA,IAAO,WAAW,OAAO,IAAA;AAC7B,EAAA,MAAM,OAAA,GAAsB;AAAA,IAC1B,KAAA;AAAA,IACA,MAAA,EAAQ,SAAA,CAAU,KAAK,CAAA,IAAK,OAAO,MAAA,IAAU,EAAA;AAAA,IAC7C,SAAA,EAAW,KAAA,EAAO,SAAA,IAAa,YAAA,EAAa;AAAA,IAC5C,SAAA;AAAA,IACA,UAAA,EAAY,GAAA;AAAA,IACZ,OAAA,EAAS,KAAA,EAAO,OAAA,IAAW,EAAC;AAAA,IAC5B,UAAA,EAAY;AAAA,GACd;AACA,EAAA,IAAI,WAAU,EAAG;AACf,IAAA,IAAI;AACF,MAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,WAAA,EAAa,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,IAClE,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,YAAA,CACd,IAAA,EACA,UAAA,GAAqB,2BAAA,EACF;AACnB,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,OACJ,QAAA,IACA;AAAA,IACE,KAAA,EAAO,EAAA;AAAA,IACP,MAAA,EAAQ,EAAA;AAAA,IACR,WAAW,YAAA,EAAa;AAAA,IACxB,SAAA,EAAW,MAAM,UAAA,GAAa,GAAA;AAAA,IAC9B,UAAA,EAAY,GAAA;AAAA,IACZ,SAAS;AAAC,GACZ;AAEF,EAAA,MAAM,MAAA,GAAqB;AAAA,IACzB,GAAG,IAAA;AAAA,IACH,GAAG,IAAA;AAAA,IACH,SAAA,EAAW,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,aAAa,YAAA,EAAa;AAAA,IAC5D,UAAA,EAAY,GAAA;AAAA,IACZ,SAAA,EAAW,MAAM,UAAA,GAAa,GAAA;AAAA,IAC9B,OAAA,EAAS,WAAA,CAAY,IAAA,CAAK,OAAA,IAAW,KAAK,OAAO;AAAA,GACnD;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,WAAA,EAAa,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAC/D,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,YAAA,GAAqB;AACnC,EAAA,IAAI,CAAC,WAAU,EAAG;AAClB,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA,EAC5C,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEO,SAAS,YAAY,OAAA,EAA2C;AACrE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,SAAU,EAAC;AACrC,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,WAAA,EAAa,OAAO,OAAA;AAC1C,EAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,WAAW,CAAA;AACnD;AAEO,SAAS,YAAA,CACd,aAAqB,2BAAA,EACF;AACnB,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,OAAO,YAAA,CAAa,EAAC,EAAG,UAAU,CAAA;AACpC;;;ACtLA,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,eAAA,GAAkB,CAAA;AACxB,IAAM,mBAAA,GAAsB,GAAA;AAErB,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EAGlC,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,SAAA,EAAmB;AAC9D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AACF;AAEO,IAAM,gBAAA,GAAN,cAA+B,QAAA,CAAS;AAAA,EAC7C,YAAY,SAAA,EAAmB;AAC7B,IAAA,KAAA,CAAM,4BAAA,EAA8B,KAAK,SAAS,CAAA;AAClD,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF;AAWA,IAAM,oBAAoB,MAAc;AACtC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,OAAO,UAAA,EAAW;AAAA,EAC3B;AACA,EAAA,OAAO,OAAO,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AAClF,CAAA;AAEA,IAAM,KAAA,GAAQ,CAAC,EAAA,KACb,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAElD,IAAM,OAAA,GAAU,CAAC,IAAA,EAAc,IAAA,KAAyB;AACtD,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC3C,EAAA,MAAM,cAAc,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAI,CAAA,CAAA;AAC1D,EAAA,OAAO,CAAA,EAAG,WAAW,CAAA,EAAG,WAAW,CAAA,CAAA;AACrC,CAAA;AAEA,eAAe,OAAA,CACb,OAAA,EACA,IAAA,EACA,IAAA,GAAuB,EAAC,EACZ;AACZ,EAAA,MAAM;AAAA,IACJ,MAAA,GAAS,KAAA;AAAA,IACT,IAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,OAAA,GAAU,eAAA;AAAA,IACV,IAAA,GAAO;AAAA,GACT,GAAI,IAAA;AAEJ,EAAA,MAAM,GAAA,GAAM,gBAAgB,IAAA,CAAK,IAAI,IAAI,IAAA,GAAO,OAAA,CAAQ,SAAS,IAAI,CAAA;AACrE,EAAA,MAAM,YAAY,iBAAA,EAAkB;AAEpC,EAAA,IAAI,SAAA,GAA0B,IAAA;AAE9B,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,OAAA,EAAS,OAAA,EAAA,EAAW;AACnD,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,SAAS,CAAA;AAEhE,IAAA,MAAM,WAAA,GAAc,MAAM,UAAA,CAAW,KAAA,EAAM;AAC3C,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAA;AAAA,MAChD;AACA,MAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,WAAA,EAAa,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IAC9D;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAkC;AAAA,QACtC,cAAA,EAAgB,kBAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OAClB;AACA,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,QAAA,IAAI,SAAS,KAAA,EAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,QAAQ,KAAK,CAAA,CAAA;AAAA,MACxE;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QAC3B,MAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAM,IAAA,KAAS,KAAA,CAAA,GAAY,KAAA,CAAA,GAAY,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,QAC1D,QAAQ,UAAA,CAAW,MAAA;AAAA,QACnB,WAAA,EAAa;AAAA,OACd,CAAA;AAED,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,QAAA,YAAA,EAAa;AACb,QAAA,MAAM,IAAI,iBAAiB,SAAS,CAAA;AAAA,MACtC;AAEA,MAAA,IAAI,GAAA,CAAI,MAAA,IAAU,GAAA,IAAO,OAAA,GAAU,OAAA,EAAS;AAC1C,QAAA,SAAA,GAAY,IAAI,SAAS,CAAA,aAAA,EAAgB,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,QAAQ,SAAS,CAAA;AAC5E,QAAA,MAAM,SAAA;AAAA,MACR;AAEA,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,IAAI,SAAS,GAAA,CAAI,UAAA;AACjB,QAAA,IAAI;AACF,UAAA,MAAM,OAAA,GAAW,MAAM,GAAA,CAAI,IAAA,EAAK;AAChC,UAAA,MAAA,GAAS,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,MAAA,IAAU,MAAA;AAAA,QAChD,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,MAAM,IAAI,SAAS,MAAA,IAAU,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,MAAA,EAAQ,SAAS,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,EAAK,OAAO,KAAA,CAAA;AAC/B,MAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,IACzB,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,KAAA,GAAQ,GAAA;AACd,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,KAAS,YAAA;AAC/B,MAAA,MAAM,SAAS,KAAA,YAAiB,gBAAA;AAChC,MAAA,MAAM,WAAA,GACJ,CAAC,MAAA,IACD,CAAC,MAAA,EAAQ,YACR,OAAA,IAAW,KAAA,YAAiB,SAAA,IAAc,KAAA,CAAmB,MAAA,IAAU,GAAA,CAAA;AAE1E,MAAA,IAAI,MAAA,IAAU,CAAC,WAAA,IAAe,OAAA,KAAY,OAAA,EAAS;AACjD,QAAA,MAAM,KAAA;AAAA,MACR;AACA,MAAA,SAAA,GAAY,KAAA;AACZ,MAAA,MAAM,MAAM,mBAAA,GAAsB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAC,CAAA;AAAA,IACxD,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,IAAI,MAAA,EAAQ,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,WAAW,CAAA;AAAA,IAC7D;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,IAAa,IAAI,KAAA,CAAM,gBAAgB,CAAA;AAC/C;AAEA,eAAsB,SAAA,CACpB,OAAA,EACA,SAAA,EACA,MAAA,EACkB;AAClB,EAAA,OAAO,OAAA,CAAiB,SAAS,SAAA,EAAW;AAAA,IAC1C,MAAA,EAAQ,KAAA;AAAA,IACR,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACV,CAAA;AACH;AAEA,eAAsB,QAAA,CACpB,OAAA,EACA,IAAA,EACA,SAAA,EACA,MAAA,EACsB;AACtB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,IAAW,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,CAAA;AAC7C,EAAA,OAAO,OAAA,CAAqB,SAAS,IAAA,EAAM;AAAA,IACzC,MAAA,EAAQ,MAAA;AAAA,IACR,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,CAAK,IAAI,SAAA,EAAU;AAAA,IACnC;AAAA,GACD,CAAA;AACH;AAEA,eAAsB,WAAA,CACpB,OAAA,EACA,OAAA,EACA,SAAA,EACA,SACA,MAAA,EACsB;AACtB,EAAA,OAAO,OAAA,CAAqB,SAAS,UAAA,EAAY;AAAA,IAC/C,MAAA,EAAQ,MAAA;AAAA,IACR,IAAA,EAAM,EAAE,OAAA,EAAS,SAAA,EAAW,OAAA,EAAQ;AAAA,IACpC;AAAA,GACD,CAAA;AACH;AAEA,eAAsB,kBAAA,CACpB,OAAA,EACA,IAAA,EACA,SAAA,EACA,MAAA,EACsB;AACtB,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,EAAS,uBAAuB,CAAA;AACpD,EAAA,MAAM,YAAY,iBAAA,EAAkB;AACpC,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,EAAA,IAAA,CAAK,MAAA,CAAO,aAAa,SAAS,CAAA;AAClC,EAAA,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,IAAA,CAAK,IAAI,CAAA;AAEnC,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,GAAK,CAAA;AAC5D,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,MAAM,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAA;AAAA,IAChD;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,MAAM,UAAA,CAAW,OAAM,EAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,EAC3E;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAkC,EAAE,cAAA,EAAgB,SAAA,EAAU;AACpE,IAAA,IAAI,SAAS,KAAA,EAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,QAAQ,KAAK,CAAA,CAAA;AAEtE,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAC3B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA;AAAA,MACN,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,WAAA,EAAa;AAAA,KACd,CAAA;AAED,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,MAAA,YAAA,EAAa;AACb,MAAA,MAAM,IAAI,iBAAiB,SAAS,CAAA;AAAA,IACtC;AACA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,IAAI,SAAS,GAAA,CAAI,UAAA;AACjB,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAW,MAAM,GAAA,CAAI,IAAA,EAAK;AAChC,QAAA,MAAA,GAAS,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,MAAA,IAAU,MAAA;AAAA,MAChD,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,SAAS,MAAA,IAAU,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,MAAA,EAAQ,SAAS,CAAA;AAAA,IAC1E;AACA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,SAAS,CAAA;AAAA,EACxB;AACF;AAEA,eAAsB,MAAA,CAAO,SAAiB,MAAA,EAAqC;AACjF,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,CAAc,SAAS,cAAA,EAAgB;AAAA,MAC3C,MAAA,EAAQ,MAAA;AAAA,MACR,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,YAAA,EAAa;AAAA,EACf;AACF;;;ACvOO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,OAAA,GAAU,IAAA,EAAM,SAAQ,GAAI,IAAA;AACxD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAyB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAkB,IAAI,CAAA;AACpD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAClC,EAAA,MAAM,UAAA,GAAa,OAAO,OAAO,CAAA;AAEjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAAA,EACvB,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,IAAA,IAAI,CAAC,SAAS,KAAA,EAAO;AACnB,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,SAAA,CAAU,SAAS,SAAA,EAAW,UAAA,CAAW,MAAM,CAAA,CAC5C,IAAA,CAAK,CAAC,CAAA,KAAM;AACX,MAAA,OAAA,CAAQ,CAAC,CAAA;AACT,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAe;AACrB,MAAA,IAAI,GAAA,CAAI,SAAS,YAAA,EAAc;AAC/B,MAAA,IAAI,eAAe,gBAAA,EAAkB;AACnC,QAAA,YAAA,EAAa;AACb,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,CAAA,MAAO;AACL,QAAA,QAAA,CAAS,GAAG,CAAA;AACZ,QAAA,UAAA,CAAW,UAAU,GAAG,CAAA;AAAA,MAC1B;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,aAAoB,KAAK,CAAA;AAAA,IAClD,CAAC,CAAA;AAEH,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAChC,GAAG,CAAC,OAAA,EAAS,SAAA,EAAW,OAAA,EAAS,IAAI,CAAC,CAAA;AAEtC,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,OAAA,CAAQ,CAAC,MAAM,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAE3D,EAAA,OAAO;AAAA,IACL,YAAY,IAAA,KAAS,IAAA;AAAA,IACrB,IAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AACF;AC9DA,IAAM,YAAA,GAA0B;AAAA,EAC9B,UAAU,EAAC;AAAA,EACX,QAAA,EAAU,KAAA;AAAA,EACV,MAAA,EAAQ,MAAA;AAAA,EACR,KAAA,EAAO;AACT,CAAA;AAEA,SAAS,OAAA,CAAQ,OAAkB,MAAA,EAA+B;AAChE,EAAA,QAAQ,OAAO,IAAA;AAAM,IACnB,KAAK,aAAA,EAAe;AAClB,MAAA,MAAM,OAAO,CAAC,GAAG,KAAA,CAAM,QAAA,EAAU,OAAO,OAAO,CAAA;AAC/C,MAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,WAAA,GAAc,KAAK,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,WAAW,CAAA,GAAI,IAAA;AACpF,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAA,EAAQ;AAAA,IACvC;AAAA,IACA,KAAK,YAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAO,OAAA,EAAQ;AAAA,IAC9C,KAAK,YAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,OAAO,OAAA,EAAQ;AAAA,IAC5C,KAAK,WAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,KAAA,EAAO,OAAO,OAAA,EAAQ;AAAA,IAC3C,KAAK,kBAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,QAAA,EAAU,MAAM,QAAA,CAAS,GAAA;AAAA,UAAI,CAAC,CAAA,KAC5B,CAAA,CAAE,EAAA,KAAO,MAAA,CAAO,OAAA,CAAQ,QAAA,GAAW,CAAA,GAAI,EAAE,GAAG,CAAA,EAAG,WAAA,EAAa,KAAA;AAAM;AACpE,OACF;AAAA,IACF,KAAK,cAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAO,OAAA,EAAQ;AAAA,IAC9C,KAAK,OAAA;AACH,MAAA,OAAO,YAAA;AAAA,IACT;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;AAuBO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,iBAAiB,eAAA,EAAiB,OAAA,EAAS,eAAc,GAAI,IAAA;AACzF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,UAAA,CAAW,SAAS,YAAY,CAAA;AAC1D,EAAA,MAAM,QAAA,GAAWC,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,kBAAA,GAAqBA,OAAO,eAAe,CAAA;AACjD,EAAA,MAAM,UAAA,GAAaA,OAAO,OAAO,CAAA;AACjC,EAAA,MAAM,gBAAA,GAAmBA,OAAO,aAAa,CAAA;AAE7C,EAAAC,UAAU,MAAM;AACd,IAAA,kBAAA,CAAmB,OAAA,GAAU,eAAA;AAC7B,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AACrB,IAAA,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAAA,EAC7B,CAAA,EAAG,CAAC,eAAA,EAAiB,OAAA,EAAS,aAAa,CAAC,CAAA;AAE5C,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,eAAA,IAAmB,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACjD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,iBAAiB,CAAA;AAAA,IAC7D;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,kBAAA,CAAmB,OAAA,GAAU,MAAM,QAAQ,CAAA;AAAA,EAC7C,CAAA,EAAG,CAAC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAEnB,EAAAA,UAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,IAC1B,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,iBAAA,GAAoBC,WAAAA,CAAY,CAAC,OAAA,KAA6B;AAClE,IAAA,MAAM,GAAA,GAAe;AAAA,MACnB,IAAI,YAAA,EAAa;AAAA,MACjB,IAAA,EAAM,MAAA;AAAA,MACN,OAAA;AAAA,MACA,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AACA,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAA,EAAS,KAAK,CAAA;AAC9C,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,iBAAA,GAAoBA,WAAAA,CAAY,CAAC,IAAA,KAAsB;AAC3D,IAAA,MAAM,MAAA,GAAkB;AAAA,MACtB,IAAI,YAAA,EAAa;AAAA,MACjB,IAAA,EAAM,KAAA;AAAA,MACN,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,KAAA,EAAO,IAAA,CAAK,KAAA,IAAS,EAAC;AAAA,MACtB,WAAA,EAAA,CAAc,IAAA,CAAK,KAAA,IAAS,IAAI,MAAA,GAAS,CAAA;AAAA,MACzC,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AACA,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAA,EAAS,QAAQ,CAAA;AAAA,EACnD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,oBAAA,GAAuBA,WAAAA,CAAY,CAAC,MAAA,KAAoB;AAC5D,IAAA,QAAA,CAAS,EAAE,MAAM,kBAAA,EAAoB,OAAA,EAAS,EAAE,QAAA,EAAU,MAAA,IAAU,CAAA;AAAA,EACtE,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,SAAA,GAAYA,WAAAA;AAAA,IAChB,OAAO,IAAA,KAAe;AACpB,MAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,oBAAA,EAAqB;AACrB,MAAA,iBAAA,CAAkB,CAAA,SAAA,EAAY,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AACzC,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,MAAM,CAAA;AAC9C,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,WAAW,CAAA;AACnD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,MAAM,CAAA;AAE7C,MAAA,IAAI;AACF,QAAA,MAAM,OAAO,MAAM,kBAAA,CAAsB,SAAS,IAAA,EAAM,SAAA,EAAW,WAAW,MAAM,CAAA;AACpF,QAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,QAAQ,CAAA;AAAA,MAClD,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,SAAS,YAAA,EAAc;AACjC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAC1B,UAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,KAAA,CAAM,SAAS,CAAA;AAAA,QACxD;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,SAAS,CAAA;AAAA,MACnD,CAAA,SAAE;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,MACjD;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,SAAA,EAAW,iBAAA,EAAmB,mBAAmB,oBAAoB;AAAA,GACjF;AAEA,EAAA,MAAM,QAAA,GAAWA,WAAAA;AAAA,IACf,OAAO,IAAA,KAAiB;AACtB,MAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,MAAA,IAAI,CAAC,OAAA,IAAW,CAAC,SAAA,EAAW;AAE5B,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,oBAAA,EAAqB;AACrB,MAAA,iBAAA,CAAkB,OAAO,CAAA;AACzB,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,MAAM,CAAA;AAC9C,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,WAAW,CAAA;AACnD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,MAAM,CAAA;AAE7C,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAA;AACxC,QAAA,MAAM,IAAA,GAAO,MAAM,WAAA,CAAe,OAAA,EAAS,SAAS,SAAA,EAAW,OAAA,EAAS,WAAW,MAAM,CAAA;AACzF,QAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,QAAQ,CAAA;AAAA,MAClD,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,SAAS,YAAA,EAAc;AACjC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAC1B,UAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,KAAA,CAAM,SAAS,CAAA;AAAA,QACxD;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,SAAS,CAAA;AAAA,MACnD,CAAA,SAAE;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,MACjD;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,SAAA,EAAW,MAAM,QAAA,EAAU,iBAAA,EAAmB,mBAAmB,oBAAoB;AAAA,GACjG;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AAAA,EAC5B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,WAAA,GAAcA,WAAAA,CAAY,CAAC,OAAA,KAAuB;AACtD,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,SAAS,CAAA;AAAA,EACrD,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,SAAA,GAAYA,WAAAA,CAAY,CAAC,KAAA,KAAmB;AAChD,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,EACjD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,oBAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;ACtNO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,aAAA,EAAe,SAAQ,GAAI,IAAA;AACvD,EAAA,MAAM,QAAA,GAAWF,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,gBAAA,GAAmBA,OAAO,aAAa,CAAA;AAC7C,EAAA,MAAM,UAAA,GAAaA,OAAO,OAAO,CAAA;AAEjC,EAAAC,UAAU,MAAM;AACd,IAAA,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAC3B,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAAA,EACvB,CAAA,EAAG,CAAC,aAAA,EAAe,OAAO,CAAC,CAAA;AAE3B,EAAAA,UAAU,MAAM;AACd,IAAA,OAAO,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,EACvC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAWC,WAAAA;AAAA,IACf,OAAO,IAAA,KAA4C;AACjD,MAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AACvB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,QAAA,CAAS,OAAA,EAAS,IAAA,EAAM,SAAA,EAAW,WAAW,MAAM,CAAA;AAAA,MACnE,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc,OAAO,IAAA;AACxC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,QAC5B;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAS,SAAS;AAAA,GACrB;AAEA,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB;AC7BO,SAAS,UAAA,CAAW,IAAA,GAA0B,EAAC,EAAqB;AACzE,EAAA,MAAM,EAAE,UAAA,GAAa,2BAAA,EAA6B,QAAA,EAAS,GAAI,IAAA;AAC/D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIC,SAA4B,IAAI,CAAA;AAC9D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIA,SAAS,CAAC,CAAA;AAChD,EAAA,MAAM,UAAA,GAAaH,OAAO,KAAK,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAcA,OAAO,QAAQ,CAAA;AAEnC,EAAAC,UAAU,MAAM;AACd,IAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AAAA,EACxB,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAAA,UAAU,MAAM;AACd,IAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,IAAA,UAAA,CAAW,OAAO,CAAA;AAClB,IAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,EAC7D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,WAAA,CAAY,MAAM;AACxC,MAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACvB,UAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,UAAA,WAAA,CAAY,OAAA,IAAU;AAAA,QACxB;AACA,QAAA,UAAA,CAAW,IAAI,CAAA;AACf,QAAA,cAAA,CAAe,CAAC,CAAA;AAChB,QAAA;AAAA,MACF;AACA,MAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAC/C,GAAG,IAAK,CAAA;AACR,IAAA,OAAO,MAAM,MAAA,CAAO,aAAA,CAAc,QAAQ,CAAA;AAAA,EAC5C,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,IAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAoB;AACrC,MAAA,IAAI,CAAA,CAAE,GAAA,IAAO,CAAA,CAAE,GAAA,KAAQ,aAAA,EAAe;AACtC,MAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,IAC7D,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC5C,IAAA,OAAO,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAA,EAAW,SAAS,CAAA;AAAA,EAC9D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAWC,WAAAA;AAAA,IACf,CAAC,OAAe,MAAA,KAAmB;AACjC,MAAA,UAAA,CAAW,OAAA,GAAU,KAAA;AACrB,MAAA,MAAM,OAAA,GAAU,YAAA;AAAA,QACd;AAAA,UACE,KAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA,EAAW,WAAA,EAAY,EAAG,SAAA,IAAa,YAAA,EAAa;AAAA,UACpD,OAAA,EAAS,WAAA,EAAY,EAAG,OAAA,IAAW;AAAC,SACtC;AAAA,QACA;AAAA,OACF;AACA,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,IAC7D,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,CAAC,OAAA,KAAuB;AACtB,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,EAAE,OAAA,IAAW,UAAU,CAAA;AACpD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,UAAA,CAAW,OAAO,CAAA;AAClB,QAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,MAC/C;AAAA,IACF,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,MAAM,OAAA,GAAU,aAAa,UAAU,CAAA;AACvC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAC/C;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,YAAA,EAAa;AACb,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,cAAA,CAAe,CAAC,CAAA;AAChB,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAAA,EACvB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,OAAA,EAAS,WAAA,EAAa,QAAA,EAAU,UAAA,EAAY,OAAO,KAAA,EAAM;AACpE;;;ACrHA,IAAA,YAAA,GAAA;AAAA,EAAC,IAAA,EAAAE,WAAAA;AAAA,EA0BA,cAAA,EAAAC,qBAAAA;AAAA,EAwBA,aAAA,EAAAC,oBAAAA;AAAA,EAIA,YAAA,EAAAC,mBAAAA;AAAA,EAIA,MAAA,EAAAC,aAAAA;AAAA,EAkCE,eAAA,EAAAC,sBAAAA;AAAA,EACA,gBAAA,EAAAC,uBAAAA;AAAA,EAQF,MAAA,EAAAC,aAAAA;AAAA,EAUA,WAAA,EAAAC,kBAAAA;AAAA,EAMA,UAAA,EAAAC,iBAAAA;AAAA,EAMA,aAAA,EAAAC,oBAAAA;AAAA,EAMA,UAAA,EAAAC,iBAAAA;AAAA,EAeA,IAAA,EAAAC,WAAAA;AAAA,EAoBA,MAAA,EAAAC,aAAAA;AAAA,EAeA,QAAA,EAAAC,eAAAA;AAAA,EAiDA,SAAA,EAAAC,gBAAAA;AAAA,EAOA,UAAA,EAAAC,iBAAAA;AAAA,EAcA,OAAA,EAAAC,cAAAA;AAAA,EAOA,IAAA,EAAAC,WAAAA;AAAA,EAiBA,UAAA,EAAAC,iBAAAA;AAAA,EAKA,YAAA,EAAAC,mBAAAA;AAAA,EAKA,MAAA,EAAAC,aAAAA;AAAA,EAUA,SAAA,EAAAC,gBAAAA;AAAA,EAoBA,KAAA,EAAAC,YAAAA;AAAA,EAQA,QAAA,EAAAC,eAAAA;AAAA,EAsBA,UAAA,EAAAC,iBAAAA;AAAA,EAiBA,eAAA,EAAAC,sBAAAA;AAAA,EA4BA,QAAA,EAAAC,eAAAA;AAAA,EAWA,YAAA,EAAAC,mBAAAA;AAAA,EAIA,aAAA,EAAAC,oBAAAA;AAAA,EAKA,YAAA,EAAAC,mBAAAA;AAAA,EAMA,cAAA,EAAAC,qBAAAA;AAAA,EAaA,kBAAA,EAAAC,yBAAAA;AAAA,EAWA,uBAAA,EAAAC,8BAAAA;AAAA,EAQA,WAAA,EAAAC,kBAAAA;AAAA,EAYA,WAAA,EAAAC,kBAAAA;AAAA,EAmDA,YAAA,EAAAC;AAAA,CAAA;ACrfM,SAAS,QAAA,CAAS,EAAE,SAAA,EAAW,QAAA,EAAU,cAAa,EAAkB;AAC7E,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,YAAA,EAAa;AACb,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,IACzB;AAAA,EACF,CAAA;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,QAAA,EACrB,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAI,SAAA,EAAW,YAAA,CAAO,YAAA,EAAc,aAAA,EAAY,QAAO,QAAA,EAAA,WAAA,EAAE,CAAA;AAAA,oBAC1D,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,eAAe,QAAA,EAAA,gBAAA,EAAc,CAAA;AAAA,oBACpD,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,YAAA,EAAc,QAAA,EAAA;AAAA,MAAA,YAAA;AAAA,MACxB,SAAA;AAAA,MAAU;AAAA,KAAA,EACvB,CAAA;AAAA,oBACA,GAAA,CAAC,YAAO,IAAA,EAAK,QAAA,EAAS,WAAW,YAAA,CAAO,cAAA,EAAgB,OAAA,EAAS,WAAA,EAAa,QAAA,EAAA,2BAAA,EAE9E,CAAA;AAAA,oBACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,kBAAA,EACrB,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,uBAAA,EAAyB,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,sBAC1D,GAAA,CAAC,SAAI,QAAA,EAAA,4DAAA,EAAqD,CAAA;AAAA,sBAC1D,GAAA,CAAC,SAAI,QAAA,EAAA,oDAAA,EAA6C,CAAA;AAAA,sBAClD,GAAA,CAAC,SAAI,QAAA,EAAA,4DAAA,EAAqD;AAAA,KAAA,EAC5D;AAAA,GAAA,EACF,CAAA;AAEJ;AC3BO,SAAS,KAAK,EAAE,IAAA,EAAM,QAAA,EAAU,MAAA,EAAQ,SAAQ,EAAc;AACnE,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,YAAA,CAAO,IAAA;AAAA,IACP,MAAA,GAAS,aAAO,UAAA,GAAa,EAAA;AAAA,IAC7B,QAAA,GAAW,aAAO,YAAA,GAAe;AAAA,GACnC,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,uBACEC,IAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA;AAAA,MACA,OAAA,EAAS,MAAM,CAAC,QAAA,IAAY,QAAQ,IAAI,CAAA;AAAA,MAEvC,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,IAAA,mBAAOC,GAAAA,CAAC,MAAA,EAAA,EAAK,eAAY,MAAA,EAAQ,QAAA,EAAA,IAAA,CAAK,MAAK,CAAA,GAAU,IAAA;AAAA,wBAC3DA,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,IAAA,CAAK,KAAA,EAAM;AAAA;AAAA;AAAA,GACpB;AAEJ;ACpBO,SAAS,OAAA,CAAQ,EAAE,KAAA,EAAO,QAAA,EAAU,SAAQ,EAAiB;AAClE,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,IAAA;AACzC,EAAA,uBACEA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,OAAA,EACpB,QAAA,EAAA,KAAA,CAAM,IAAI,CAAC,CAAA,qBACVA,GAAAA,CAAC,IAAA,EAAA,EAAgB,MAAM,CAAA,EAAG,QAAA,EAAoB,WAAnC,CAAA,CAAE,EAAmD,CACjE,CAAA,EACH,CAAA;AAEJ;ACLA,IAAM,YAAA,GAAe;AAAA,EACnB,GAAA;AAAA,EAAK,QAAA;AAAA,EACL,GAAA;AAAA,EAAK,IAAA;AAAA,EACL,GAAA;AAAA,EAAK,KAAA;AAAA,EACL,GAAA;AAAA,EAAK,QAAA;AAAA,EAAU,KAAA;AAAA,EACf,IAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA;AAAA,EAAQ,KAAA;AAAA,EACR,GAAA;AAAA,EACA,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA,EACZ,YAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,YAAA,GAAe,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,OAAO,CAAA;AAEtD,IAAM,YAAA,GAAe;AAAA,EACnB,YAAA;AAAA,EACA,YAAA;AAAA;AAAA,EAEA,uBAAA,EAAyB,KAAA;AAAA,EACzB,kBAAA,EAAoB;AACtB,CAAA;AAmBA,SAAS,qBAAqB,IAAA,EAAsB;AAClD,EAAA,OAAO,KAEJ,OAAA,CAAQ,mCAAA,EAAqC,WAAW,CAAA,CAExD,OAAA,CAAQ,wBAAwB,WAAW,CAAA,CAC3C,QAAQ,kBAAA,EAAoB,WAAW,EAEvC,OAAA,CAAQ,gCAAA,EAAkC,WAAW,CAAA,CACrD,OAAA,CAAQ,oDAAoD,WAAW,CAAA;AAC5E;AAWO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAElB,EAAA,MAAM,OAAA,GAAU,qBAAqB,IAAI,CAAA;AAGzC,EAAA,MAAM,aAAa,OAAA,CAChB,KAAA,CAAM,QAAQ,CAAA,CACd,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,QAAQ,KAAA,EAAO,MAAM,CAAC,CAAA,CACzC,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAE7B,EAAA,MAAM,OAAO,UAAA,CAAW,MAAA,GAAS,CAAA,GAC7B,UAAA,CAAW,IAAI,CAAC,CAAA,KAAM,CAAA,GAAA,EAAM,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAC5C,UAAA,CAAW,CAAC,CAAA,IAAK,EAAA;AAErB,EAAA,OAAO,SAAA,CAAU,QAAA,CAAS,IAAA,EAAM,YAAY,CAAA;AAC9C;AClFO,SAAS,aAAA,CAAc,EAAE,OAAA,EAAS,WAAA,EAAY,EAAuB;AAC1E,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,KAAS,KAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,KAAA,GAChB,CAAA,EAAG,YAAA,CAAO,MAAM,CAAA,CAAA,EAAI,YAAA,CAAO,SAAS,CAAA,CAAA,GACpC,CAAA,EAAG,YAAA,CAAO,MAAM,CAAA,CAAA,EAAI,aAAO,UAAU,CAAA,CAAA;AAEzC,EAAA,uBACED,KAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,aAAA,EAAe,QAAA,EAAS,EACrD,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,WAAA,EACb,kCACCA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,WAAW,YAAA,CAAO,QAAA;AAAA,QAClB,yBAAyB,EAAE,MAAA,EAAQ,cAAA,CAAe,OAAA,CAAQ,OAAO,CAAA;AAAE;AAAA,KACrE,GAEA,QAAQ,OAAA,EAEZ,CAAA;AAAA,IACC,SAAS,OAAA,CAAQ,KAAA,IAAS,QAAQ,KAAA,CAAM,MAAA,GAAS,oBAChDA,GAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,OAAO,OAAA,CAAQ,KAAA;AAAA,QACf,QAAA,EAAU,CAAC,OAAA,CAAQ,WAAA;AAAA,QACnB,OAAA,EAAS;AAAA;AAAA,KACX,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;ACnCO,SAAS,eAAA,GAAkB;AAChC,EAAA,uBACED,KAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,MAAA,EAAQ,WAAA,EAAU,QAAA,EAAS,YAAA,EAAW,qBAAA,EAC3D,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,YAAA,CAAO,SAAA,EAAW,CAAA;AAAA,oBACnCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,aAAO,SAAA,EAAW,CAAA;AAAA,oBACnCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,aAAO,SAAA,EAAW;AAAA,GAAA,EACrC,CAAA;AAEJ;ACSO,SAAS,QAAA,CAAS;AAAA,EACvB,UAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAAkB;AAChB,EAAA,MAAM,MAAA,GAAS1C,OAA8B,IAAI,CAAA;AAEjD,EAAAC,UAAU,MAAM;AACd,IAAA,MAAA,CAAO,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,UAAU,CAAA;AAAA,EACvD,CAAA,EAAG,CAAC,QAAA,CAAS,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAE9B,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACEyC,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,IAAA,EACrB,QAAA,kBAAAA,GAAAA,CAAC,eAAA,EAAA,EAAgB,CAAA,EACnB,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,MACrB,QAAA,kBAAAA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,SAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA;AAAA,KACF,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,IAAA,EACpB,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,qBACbC,GAAAA,CAAC,aAAA,EAAA,EAAyB,OAAA,EAAS,CAAA,EAAG,WAAA,EAAA,EAAlB,CAAA,CAAE,EAA0C,CACjE,CAAA;AAAA,IACA,QAAA,mBAAWA,GAAAA,CAAC,eAAA,EAAA,EAAgB,CAAA,GAAK,IAAA;AAAA,IACjC,KAAA,mBAAQA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAO,WAAA,EAAc,iBAAM,CAAA,GAAS,IAAA;AAAA,oBAC7DA,GAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,MAAA,EAAQ;AAAA,GAAA,EACpB,CAAA;AAEJ;;;AClEO,SAAS,gBAAgB,WAAA,EAA6B;AAC3D,EAAA,IAAI,WAAA,IAAe,GAAG,OAAO,SAAA;AAC7B,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,WAAA,GAAc,GAAI,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,YAAA,GAAe,IAAI,CAAA;AAC5C,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAO,YAAA,GAAe,OAAQ,EAAE,CAAA;AACrD,EAAA,MAAM,UAAU,YAAA,GAAe,EAAA;AAE/B,EAAA,IAAI,QAAQ,CAAA,EAAG,OAAO,CAAA,EAAG,KAAK,KAAK,OAAO,CAAA,MAAA,CAAA;AAC1C,EAAA,IAAI,UAAU,CAAA,EAAG,OAAO,CAAA,EAAG,OAAO,KAAK,OAAO,CAAA,MAAA,CAAA;AAC9C,EAAA,OAAO,GAAG,OAAO,CAAA,MAAA,CAAA;AACnB;ACCO,SAAS,UAAA,CAAW;AAAA,EACzB,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,MAAA,EACrB,QAAA,EAAA;AAAA,oBAAAA,KAAC,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAAC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,aAAc,QAAA,EAAA,SAAA,EAAU,CAAA;AAAA,MAC9C,aAAA,IAAiB,cAAc,CAAA,mBAC9BD,KAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,UAAA,EAAY,QAAA,EAAA;AAAA,QAAA,WAAA;AAAA,QAAU,gBAAgB,WAAW;AAAA,OAAA,EAAE,CAAA,GACxE;AAAA,KAAA,EACN,CAAA;AAAA,oBACAA,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,aAAA,EACpB,QAAA,EAAA;AAAA,MAAA,OAAA,mBACCC,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,WAAW,YAAA,CAAO,UAAA;AAAA,UAClB,OAAA,EAAS,OAAA;AAAA,UACT,YAAA,EAAW,oBAAA;AAAA,UACX,KAAA,EAAM,oBAAA;AAAA,UACP,QAAA,EAAA;AAAA;AAAA,OAED,GACE,IAAA;AAAA,sBACJA,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,WAAW,YAAA,CAAO,UAAA;AAAA,UAClB,OAAA,EAAS,OAAA;AAAA,UACT,YAAA,EAAW,YAAA;AAAA,UACX,KAAA,EAAM,OAAA;AAAA,UACP,QAAA,EAAA;AAAA;AAAA;AAED,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;ACzCO,SAAS,SAAA,CAAU,EAAE,QAAA,EAAU,WAAA,EAAa,QAAO,EAAmB;AAC3E,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIvC,SAAS,EAAE,CAAA;AACrC,EAAA,MAAM,QAAA,GAAWH,OAAyB,IAAI,CAAA;AAE9C,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,IAC1B;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AAC1B,IAAA,MAAA,CAAO,OAAO,CAAA;AACd,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B,CAAA;AAEA,EAAA,uBACEwC,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,KAAA,EACrB,QAAA,EAAA;AAAA,oBAAAC,GAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,WAAW,YAAA,CAAO,QAAA;AAAA,QAClB,KAAA;AAAA,QACA,UAAU,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,QACxC,SAAA,EAAW,CAAC,CAAA,KAAM;AAChB,UAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,OAAA,IAAW,CAAC,EAAE,QAAA,EAAU;AACpC,YAAA,CAAA,CAAE,cAAA,EAAe;AACjB,YAAA,MAAA,EAAO;AAAA,UACT;AAAA,QACF,CAAA;AAAA,QACA,QAAA;AAAA,QACA,aAAa,WAAA,IAAe,sBAAA;AAAA,QAC5B,YAAA,EAAW;AAAA;AAAA,KACb;AAAA,oBACAA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,WAAW,YAAA,CAAO,UAAA;AAAA,QAClB,OAAA,EAAS,MAAA;AAAA,QACT,QAAA,EAAU,QAAA,IAAY,KAAA,CAAM,IAAA,GAAO,MAAA,KAAW,CAAA;AAAA,QAC/C,QAAA,EAAA;AAAA;AAAA;AAED,GAAA,EACF,CAAA;AAEJ;AC3CO,SAAS,cAAA,CAAe,EAAE,QAAA,EAAU,OAAA,EAAS,YAAY,SAAA,EAAW,YAAA,EAAc,gBAAe,EAAwB;AAC9H,EAAA,MAAM,QAAA,GAAW,QAAA,KAAa,aAAA,GAAgB,YAAA,CAAO,eAAe,YAAA,CAAO,aAAA;AAC3E,EAAA,MAAM,aAAA,GAAgB,QAAA,KAAa,aAAA,GAAgB,YAAA,CAAO,kBAAkB,YAAA,CAAO,gBAAA;AACnF,EAAA,uBACED,KAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,SAAA,IAAa,+BACZA,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,WAAW,IAAI,aAAa,CAAA,CAAA;AAAA,QACjD,IAAA,EAAK,QAAA;AAAA,QACL,WAAA,EAAU,QAAA;AAAA,QAET,QAAA,EAAA;AAAA,UAAA,YAAA;AAAA,0BACDC,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,WAAW,YAAA,CAAO,YAAA;AAAA,cAClB,OAAA,EAAS,cAAA;AAAA,cACT,YAAA,EAAW,kBAAA;AAAA,cACZ,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,KACF,GACE,IAAA;AAAA,oBACJA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,cAAc,IAAI,QAAQ,CAAA,CAAA;AAAA,QAC/C,OAAA;AAAA,QACA,YAAA,EAAW,WAAA;AAAA,QACX,KAAA,EAAO,UAAA,GAAa,EAAE,UAAA,EAAY,YAAW,GAAI,MAAA;AAAA,QAClD,QAAA,EAAA;AAAA;AAAA;AAED,GAAA,EACF,CAAA;AAEJ;AC9BA,IAAM,kBAAA,GAAqB,iBAAA;AAC3B,IAAM,mBAAA,GAAsB,SAAA;AAC5B,IAAM,kBAAA,GAAqB,KAAA;AAC3B,IAAM,gBAAA,GAAmB,6DAAA;AAEzB,IAAM,gBAAA,GACJ,yLAAA;AAKF,IAAM,QAAA,GACJ,iGAAA;AAGF,IAAM,qBAAA,GAAwB,wBAAA;AAE9B,SAAS,YAAA,CAAa,MAA0B,IAAA,EAAkC;AAChF,EAAA,MAAM,QAAA,GAAW,IAAA,GACb,CAAA,cAAA,EAAiB,IAAI,CAAA,WAAA,EAAc,IAAA,GAAO,IAAA,GAAO,SAAS,CAAA,QAAA,CAAA,GAC1D,CAAA,kBAAA,EAAqB,IAAA,GAAO,IAAA,GAAO,SAAS,CAAA,QAAA,CAAA;AAChD,EAAA,OAAO,GAAG,QAAQ;;AAAA,EAAO,gBAAgB;;AAAA,EAAO,QAAQ,CAAA,CAAA;AAC1D;AAEO,SAAS,WAAW,KAAA,EAAwB;AACjD,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,QAAA;AAAA,IACA,UAAA,GAAa,2BAAA;AAAA,IACb,cAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,UAAA,GAAa,mBAAA;AAAA,IACb,QAAA,GAAW,cAAA;AAAA,IACX,WAAA,GAAc,KAAA;AAAA,IACd,aAAA,GAAgB,IAAA;AAAA,IAChB,eAAA,GAAkB,gBAAA;AAAA,IAClB,OAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AAEJ,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIvC,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,SAAS,WAAW,CAAA;AAC5C,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,aAAA,GAAgBH,OAAO,WAAW,CAAA;AAExC,EAAAC,UAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,IAAA,IAAQ,aAAA,CAAc,OAAA,EAAS;AAC/C,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AAAA,IAC1B,GAAG,GAAI,CAAA;AACP,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,OAAA,EAAS,IAAI,CAAC,CAAA;AAElB,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA,EAAO;AAAA,MACL,UAAA,CAAW;AAAA,IACb,UAAA,EAAY,UAAA;AAAA,IACZ,QAAA,EAAU;AAAA,GACX,CAAA;AAED,EAAA,MAAM,EAAE,UAAA,EAAY,IAAA,EAAM,OAAA,EAAS,WAAA,KAAgB,OAAA,CAAQ;AAAA,IACzD,OAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAS,OAAA,IAAW,IAAA;AAAA,IACpB;AAAA,GACD,CAAA;AAED,EAAA,MAAM,iBAAA,GAAoBC,YAAY,MAAM;AAC1C,IAAA,iBAAA,EAAkB;AAClB,IAAA,eAAA,IAAkB;AAAA,EACpB,CAAA,EAAG,CAAC,iBAAA,EAAmB,eAAe,CAAC,CAAA;AAEvC,EAAA,MAAM,mBAAA,GAAsBA,WAAAA;AAAA,IAC1B,CAAC,OAAA,KAAuB;AACtB,MAAA,IAAI,CAAC,OAAA,EAAS;AACd,MAAA,UAAA,CAAW,OAAO,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,GACtB;AAEA,EAAA,MAAM,UAAA,GAAaF,OAAyB,IAAI,CAAA;AAEhD,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,SAAA;AAAA,IACP,QAAA;AAAA,IACA,SAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,oBAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,KAAA,EAAO;AAAA,MACL,OAAA,CAAQ;AAAA,IACV,OAAA;AAAA,IACA,SAAA,EAAW,SAAS,SAAA,IAAa,IAAA;AAAA,IACjC,iBAAiB,OAAA,EAAS,OAAA;AAAA,IAC1B,eAAA,EAAiB,mBAAA;AAAA,IACjB,aAAA,EAAe,iBAAA;AAAA,IACf;AAAA,GACD,CAAA;AAED,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ;AAAA,IAC3B,OAAA;AAAA,IACA,SAAA,EAAW,SAAS,SAAA,IAAa,IAAA;AAAA,IACjC,aAAA,EAAe,iBAAA;AAAA,IACf;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,QAAQ,OAAO,EAAE,OAAO,KAAA,EAAM,CAAA,EAAI,EAAE,CAAA;AAE5D,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,IAAc,CAAC,IAAA,EAAM;AAC1B,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AACnC,IAAA,IAAI,gBAAgB,KAAA,EAAO;AAC3B,IAAA,eAAA,CAAgB,KAAA,GAAQ,IAAA;AACxB,IAAA,MAAM,WAAA,GACJ,kBACA,IAAA,EAAM,cAAA,IACN,aAAa,IAAA,EAAM,IAAA,EAAM,MAAM,IAAI,CAAA;AACrC,IAAA,iBAAA,CAAkB;AAAA,MAChB,OAAA,EAAS,WAAA;AAAA,MACT,KAAA,EAAO,IAAA,EAAM,SAAA,IAAa,EAAC;AAAA,MAC3B,SAAA,EAAW,SAAS,SAAA,IAAa,EAAA;AAAA,MACjC,SAAA,EAAW;AAAA,KACZ,CAAA;AACD,IAAA,OAAA,IAAU;AAAA,EACZ,CAAA,EAAG,CAAC,UAAA,EAAY,IAAA,EAAM,SAAA,CAAU,QAAA,CAAS,MAAA,EAAQ,cAAA,EAAgB,OAAA,EAAS,IAAA,EAAM,iBAAA,EAAmB,OAAA,EAAS,eAAe,CAAC,CAAA;AAE5H,EAAA,MAAM,eAAA,GAAkBC,WAAAA;AAAA,IACtB,OAAO,IAAA,KAAe;AACpB,MAAA,KAAA,EAAM;AACN,MAAA,oBAAA,EAAqB;AAErB,MAAA,IAAI,IAAA,CAAK,OAAO,qBAAA,EAAuB;AACrC,QAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAC5B,QAAA,UAAA,CAAW,SAAS,KAAA,EAAM;AAC1B,QAAA;AAAA,MACF;AAEA,MAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAC5B,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAI,CAAA;AAChC,QAAA,IAAI,IAAA,oBAAwB,IAAI,CAAA;AAAA,MAClC,CAAA,SAAE;AACA,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,KAAA,EAAO,oBAAA,EAAsB,iBAAA,EAAmB,QAAA,EAAU,WAAW,iBAAiB;AAAA,GACzF;AAEA,EAAA,MAAM,qBAAA,GAAwBA,WAAAA;AAAA,IAC5B,CAAC,CAAA,KAA2C;AAC1C,MAAA,MAAM,IAAA,GAAO,CAAA,CAAE,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA;AAC/B,MAAA,CAAA,CAAE,OAAO,KAAA,GAAQ,EAAA;AACjB,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,KAAA,EAAM;AACN,QAAA,KAAK,UAAU,IAAI,CAAA;AAAA,MACrB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAO,SAAS;AAAA,GACnB;AAEA,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,CAAC,IAAA,KAAiB;AAChB,MAAA,KAAA,EAAM;AACN,MAAA,KAAK,SAAS,IAAI,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,OAAO,QAAQ;AAAA,GAClB;AAEA,EAAA,MAAM,yBAAA,GAA4BA,YAAY,MAAM;AAClD,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,cAAcA,WAAAA,CAAY,MAAM,QAAQ,KAAK,CAAA,EAAG,EAAE,CAAA;AAExD,EAAA,MAAM,WAAA,GAAcA,YAAY,MAAM;AACpC,IAAA,SAAA,EAAU;AACV,IAAA,eAAA,CAAgB,KAAA,GAAQ,KAAA;AACxB,IAAA,UAAA,CAAW,EAAE,CAAA;AAAA,EACf,CAAA,EAAG,CAAC,SAAA,EAAW,UAAA,EAAY,eAAe,CAAC,CAAA;AAE3C,EAAA,MAAM,gBAAA,GAAmBA,YAAY,MAAM;AACzC,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,IACzB;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,MAAM,SAAA,GAAY;AAAA,IAChB,CAAC,aAAuB,GAAG;AAAA,GAC7B;AAEA,EAAA,uBACEuC,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAO,IAAA,EAAM,OAAO,SAAA,EACjC,QAAA,EAAA;AAAA,IAAA,CAAC,uBACAC,GAAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,QAAA;AAAA,QACA,OAAA,EAAS,yBAAA;AAAA,QACT,UAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA,EAAc,eAAA;AAAA,QACd,cAAA,EAAgB,MAAM,YAAA,CAAa,KAAK;AAAA;AAAA,KAC1C,GACE,IAAA;AAAA,IACH,uBACCD,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,MAAM,CAAA,CAAA,EAAI,aAAa,aAAA,GAAgB,YAAA,CAAO,YAAA,GAAe,YAAA,CAAO,aAAa,CAAA,CAAA;AAAA,QAEtG,QAAA,EAAA;AAAA,0BAAAC,GAAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA;AAAA,cACA,WAAA;AAAA,cACA,eAAe,aAAA,IAAiB,UAAA;AAAA,cAChC,OAAA,EAAS,WAAA;AAAA,cACT,OAAA,EAAS,aAAa,WAAA,GAAc;AAAA;AAAA,WACtC;AAAA,0BACAA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,UAAA;AAAA,cACA,OAAA,EAAS,WAAA;AAAA,cACT,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,SAAA;AAAA,cACA,QAAA;AAAA,cACA,OAAO,SAAA,CAAU,KAAA;AAAA,cACjB,WAAA,EAAa,eAAA;AAAA,cACb,YAAA,EAAc;AAAA;AAAA,WAChB;AAAA,0BACAA,GAAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,UAAA;AAAA,cACL,IAAA,EAAK,MAAA;AAAA,cACL,MAAA,EAAO,eAAA;AAAA,cACP,WAAW,YAAA,CAAO,eAAA;AAAA,cAClB,QAAA,EAAU,qBAAA;AAAA,cACV,aAAA,EAAW,IAAA;AAAA,cACX,QAAA,EAAU;AAAA;AAAA,WACZ;AAAA,UACC,6BACCA,GAAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,MAAA,EAAQ,UAAA;AAAA,cACR,WAAA,EAAY;AAAA;AAAA,WACd,GACE;AAAA;AAAA;AAAA,KACN,GACE;AAAA,GAAA,EACN,CAAA;AAEJ","file":"index.mjs","sourcesContent":["import type { Message, WACSession } from \"../types\";\n\nexport const SESSION_KEY = \"wac_session\";\nexport const DEFAULT_SESSION_TTL_SECONDS = 1800;\nexport const MAX_HISTORY = 100;\n\n// Fallback localStorage keys checked in order when wac_session is empty.\n// Host apps that already store a JWT under one of these keys get auth for free.\nconst FALLBACK_TOKEN_KEYS = [\"token\", \"access_token\", \"auth_token\", \"jwt\"];\n\nconst isBrowser = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nfunction base64UrlDecode(input: string): string {\n const base64 = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = base64 + \"===\".slice((base64.length + 3) % 4);\n return atob(padded);\n}\n\nfunction decodeJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3 || !parts[1]) return null;\n return JSON.parse(base64UrlDecode(parts[1])) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction jwtExpiresAt(token: string): number | null {\n const payload = decodeJwt(token);\n const exp = payload?.[\"exp\"];\n if (typeof exp !== \"number\") return null;\n return exp * 1000;\n}\n\nfunction jwtUserId(token: string): string {\n const payload = decodeJwt(token);\n if (!payload) return \"\";\n const id = payload[\"id\"] ?? payload[\"sub\"] ?? payload[\"user_id\"];\n return id != null ? String(id) : \"\";\n}\n\nfunction readFallbackToken(): { token: string; key: string } | null {\n if (!isBrowser()) return null;\n for (const key of FALLBACK_TOKEN_KEYS) {\n const value = window.localStorage.getItem(key);\n if (value && value.length > 20) return { token: value, key };\n }\n return null;\n}\n\nconst generateId = (prefix: string): string => {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return `${prefix}_${crypto.randomUUID()}`;\n }\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n};\n\nexport function newSessionId(): string {\n return generateId(\"ses\");\n}\n\nexport function newMessageId(): string {\n return generateId(\"msg\");\n}\n\nexport function readSession(): WACSession | null {\n if (!isBrowser()) return null;\n try {\n const raw = window.localStorage.getItem(SESSION_KEY);\n if (raw) {\n const session = JSON.parse(raw) as WACSession;\n const valid =\n session &&\n typeof session.token === \"string\" &&\n session.token.length > 0 &&\n typeof session.expiresAt === \"number\" &&\n Date.now() < session.expiresAt;\n if (valid) {\n const fallback = readFallbackToken();\n // If this session was adopted from a fallback key but that key is now gone,\n // the host app has logged out — drop the cached session.\n if (!fallback && session.bootSource === \"fallback\") {\n clearSession();\n return null;\n }\n // If the host app's raw token has rotated (re-login), prefer that one.\n if (fallback && fallback.token !== session.token) {\n return adoptFallbackToken(fallback.token, session);\n }\n return session;\n }\n // Stale wac_session — drop it and try fallback below.\n clearSession();\n }\n } catch {\n clearSession();\n }\n\n const fallback = readFallbackToken();\n if (!fallback) return null;\n return adoptFallbackToken(fallback.token, null);\n}\n\nfunction adoptFallbackToken(token: string, prior: WACSession | null): WACSession | null {\n const jwtExp = jwtExpiresAt(token);\n const now = Date.now();\n const expiresAt = jwtExp ?? now + DEFAULT_SESSION_TTL_SECONDS * 1000;\n if (now >= expiresAt) return null;\n const session: WACSession = {\n token,\n userId: jwtUserId(token) || prior?.userId || \"\",\n sessionId: prior?.sessionId ?? newSessionId(),\n expiresAt,\n lastActive: now,\n history: prior?.history ?? [],\n bootSource: \"fallback\",\n };\n if (isBrowser()) {\n try {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify(session));\n } catch {\n /* ignore quota */\n }\n }\n return session;\n}\n\nexport function writeSession(\n data: Partial<WACSession>,\n ttlSeconds: number = DEFAULT_SESSION_TTL_SECONDS,\n): WACSession | null {\n if (!isBrowser()) return null;\n const now = Date.now();\n const existing = readSession();\n const base: WACSession =\n existing ??\n {\n token: \"\",\n userId: \"\",\n sessionId: newSessionId(),\n expiresAt: now + ttlSeconds * 1000,\n lastActive: now,\n history: [],\n };\n\n const merged: WACSession = {\n ...base,\n ...data,\n sessionId: data.sessionId ?? base.sessionId ?? newSessionId(),\n lastActive: now,\n expiresAt: now + ttlSeconds * 1000,\n history: trimHistory(data.history ?? base.history),\n };\n\n try {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify(merged));\n return merged;\n } catch {\n return null;\n }\n}\n\nexport function clearSession(): void {\n if (!isBrowser()) return;\n try {\n window.localStorage.removeItem(SESSION_KEY);\n } catch {\n /* ignore */\n }\n}\n\nexport function trimHistory(history: Message[] | undefined): Message[] {\n if (!Array.isArray(history)) return [];\n if (history.length <= MAX_HISTORY) return history;\n return history.slice(history.length - MAX_HISTORY);\n}\n\nexport function touchSession(\n ttlSeconds: number = DEFAULT_SESSION_TTL_SECONDS,\n): WACSession | null {\n const current = readSession();\n if (!current) return null;\n return writeSession({}, ttlSeconds);\n}\n","import type { BotResponse, Chip, Message, WACUser } from \"../types\";\nimport { clearSession, newMessageId, readSession } from \"../utils/session\";\n\nconst DEFAULT_TIMEOUT_MS = 20000;\nconst DEFAULT_RETRIES = 2;\nconst RETRY_BASE_DELAY_MS = 400;\n\nexport class ApiError extends Error {\n status: number;\n requestId: string;\n constructor(message: string, status: number, requestId: string) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.requestId = requestId;\n }\n}\n\nexport class AuthExpiredError extends ApiError {\n constructor(requestId: string) {\n super(\"Session expired or invalid\", 401, requestId);\n this.name = \"AuthExpiredError\";\n }\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n signal?: AbortSignal;\n timeoutMs?: number;\n retries?: number;\n auth?: boolean;\n}\n\nconst generateRequestId = (): string => {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n};\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst joinUrl = (base: string, path: string): string => {\n const trimmedBase = base.replace(/\\/+$/, \"\");\n const trimmedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${trimmedBase}${trimmedPath}`;\n};\n\nasync function request<T>(\n apiBase: string,\n path: string,\n opts: RequestOptions = {},\n): Promise<T> {\n const {\n method = \"GET\",\n body,\n signal,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n retries = DEFAULT_RETRIES,\n auth = true,\n } = opts;\n\n const url = /^https?:\\/\\//i.test(path) ? path : joinUrl(apiBase, path);\n const requestId = generateRequestId();\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n const onUserAbort = () => controller.abort();\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeoutId);\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n signal.addEventListener(\"abort\", onUserAbort, { once: true });\n }\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Request-Id\": requestId,\n };\n if (auth) {\n const session = readSession();\n if (session?.token) headers[\"Authorization\"] = `Bearer ${session.token}`;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n credentials: \"same-origin\",\n });\n\n if (res.status === 401 || res.status === 403) {\n clearSession();\n throw new AuthExpiredError(requestId);\n }\n\n if (res.status >= 500 && attempt < retries) {\n lastError = new ApiError(`Server error ${res.status}`, res.status, requestId);\n throw lastError;\n }\n\n if (!res.ok) {\n let detail = res.statusText;\n try {\n const errBody = (await res.json()) as { message?: string; detail?: string };\n detail = errBody.message ?? errBody.detail ?? detail;\n } catch {\n /* ignore body parse */\n }\n throw new ApiError(detail || `HTTP ${res.status}`, res.status, requestId);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n } catch (err) {\n const error = err as Error;\n const isAbort = error.name === \"AbortError\";\n const isAuth = error instanceof AuthExpiredError;\n const isRetryable =\n !isAuth &&\n !signal?.aborted &&\n (isAbort || error instanceof TypeError || (error as ApiError).status >= 500);\n\n if (isAuth || !isRetryable || attempt === retries) {\n throw error;\n }\n lastError = error;\n await sleep(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n } finally {\n clearTimeout(timeoutId);\n if (signal) signal.removeEventListener(\"abort\", onUserAbort);\n }\n }\n\n throw lastError ?? new Error(\"Request failed\");\n}\n\nexport async function checkAuth(\n apiBase: string,\n authCheck: string,\n signal?: AbortSignal,\n): Promise<WACUser> {\n return request<WACUser>(apiBase, authCheck, {\n method: \"GET\",\n signal,\n retries: 1,\n });\n}\n\nexport async function sendChip(\n apiBase: string,\n chip: Chip,\n sessionId: string,\n signal?: AbortSignal,\n): Promise<BotResponse> {\n const path = chip.apiPath ?? `/chip/${chip.id}`;\n return request<BotResponse>(apiBase, path, {\n method: \"POST\",\n body: { chipId: chip.id, sessionId },\n signal,\n });\n}\n\nexport async function sendMessage(\n apiBase: string,\n message: string,\n sessionId: string,\n context: Message[],\n signal?: AbortSignal,\n): Promise<BotResponse> {\n return request<BotResponse>(apiBase, \"/message\", {\n method: \"POST\",\n body: { message, sessionId, context },\n signal,\n });\n}\n\nexport async function uploadPortfolioCsv(\n apiBase: string,\n file: File,\n sessionId: string,\n signal?: AbortSignal,\n): Promise<BotResponse> {\n const url = joinUrl(apiBase, \"/upload-portfolio-csv\");\n const requestId = generateRequestId();\n const session = readSession();\n const form = new FormData();\n form.append(\"sessionId\", sessionId);\n form.append(\"file\", file, file.name);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000);\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeoutId);\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n signal.addEventListener(\"abort\", () => controller.abort(), { once: true });\n }\n\n try {\n const headers: Record<string, string> = { \"X-Request-Id\": requestId };\n if (session?.token) headers[\"Authorization\"] = `Bearer ${session.token}`;\n\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: form,\n signal: controller.signal,\n credentials: \"same-origin\",\n });\n\n if (res.status === 401 || res.status === 403) {\n clearSession();\n throw new AuthExpiredError(requestId);\n }\n if (!res.ok) {\n let detail = res.statusText;\n try {\n const errBody = (await res.json()) as { message?: string; detail?: string };\n detail = errBody.message ?? errBody.detail ?? detail;\n } catch {\n /* ignore */\n }\n throw new ApiError(detail || `HTTP ${res.status}`, res.status, requestId);\n }\n return (await res.json()) as BotResponse;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nexport async function logout(apiBase: string, signal?: AbortSignal): Promise<void> {\n try {\n await request<void>(apiBase, \"/auth/logout\", {\n method: \"POST\",\n signal,\n retries: 0,\n });\n } finally {\n clearSession();\n }\n}\n\nexport { generateRequestId };\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AuthExpiredError, checkAuth } from \"../api/chatApi\";\nimport type { WACUser } from \"../types\";\nimport { clearSession, readSession } from \"../utils/session\";\n\ninterface UseAuthOptions {\n apiBase: string;\n authCheck: string;\n enabled?: boolean;\n onError?: (err: Error) => void;\n}\n\ninterface UseAuthReturn {\n isLoggedIn: boolean;\n user: WACUser | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nexport function useAuth(opts: UseAuthOptions): UseAuthReturn {\n const { apiBase, authCheck, enabled = true, onError } = opts;\n const [user, setUser] = useState<WACUser | null>(null);\n const [loading, setLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n\n const session = readSession();\n if (!session?.token) {\n setUser(null);\n setLoading(false);\n return;\n }\n\n const controller = new AbortController();\n setLoading(true);\n setError(null);\n\n checkAuth(apiBase, authCheck, controller.signal)\n .then((u) => {\n setUser(u);\n setError(null);\n })\n .catch((err: Error) => {\n if (err.name === \"AbortError\") return;\n if (err instanceof AuthExpiredError) {\n clearSession();\n setUser(null);\n } else {\n setError(err);\n onErrorRef.current?.(err);\n }\n })\n .finally(() => {\n if (!controller.signal.aborted) setLoading(false);\n });\n\n return () => controller.abort();\n }, [apiBase, authCheck, enabled, tick]);\n\n const refresh = useCallback(() => setTick((t) => t + 1), []);\n\n return {\n isLoggedIn: user !== null,\n user,\n loading,\n error,\n refresh,\n };\n}\n","import { useCallback, useEffect, useReducer, useRef } from \"react\";\nimport {\n AuthExpiredError,\n sendMessage as apiSendMessage,\n uploadPortfolioCsv as apiUploadPortfolioCsv,\n} from \"../api/chatApi\";\nimport type { BotResponse, ChatState, Message } from \"../types\";\nimport { MAX_HISTORY, newMessageId } from \"../utils/session\";\n\ntype ChatAction =\n | { type: \"ADD_MESSAGE\"; payload: Message }\n | { type: \"SET_TYPING\"; payload: boolean }\n | { type: \"SET_STATUS\"; payload: ChatState[\"status\"] }\n | { type: \"SET_ERROR\"; payload: string | null }\n | { type: \"DEACTIVATE_CHIPS\"; payload: { exceptId?: string } }\n | { type: \"LOAD_HISTORY\"; payload: Message[] }\n | { type: \"CLEAR\" };\n\nconst initialState: ChatState = {\n messages: [],\n isTyping: false,\n status: \"idle\",\n error: null,\n};\n\nfunction reducer(state: ChatState, action: ChatAction): ChatState {\n switch (action.type) {\n case \"ADD_MESSAGE\": {\n const next = [...state.messages, action.payload];\n const trimmed = next.length > MAX_HISTORY ? next.slice(next.length - MAX_HISTORY) : next;\n return { ...state, messages: trimmed };\n }\n case \"SET_TYPING\":\n return { ...state, isTyping: action.payload };\n case \"SET_STATUS\":\n return { ...state, status: action.payload };\n case \"SET_ERROR\":\n return { ...state, error: action.payload };\n case \"DEACTIVATE_CHIPS\":\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.id === action.payload.exceptId ? m : { ...m, chipsActive: false },\n ),\n };\n case \"LOAD_HISTORY\":\n return { ...state, messages: action.payload };\n case \"CLEAR\":\n return initialState;\n default:\n return state;\n }\n}\n\ninterface UseChatOptions {\n apiBase: string;\n sessionId: string | null;\n initialMessages?: Message[];\n onHistoryChange?: (history: Message[]) => void;\n onError?: (err: Error) => void;\n onAuthExpired?: () => void;\n}\n\ninterface UseChatReturn {\n state: ChatState;\n sendText: (text: string) => Promise<void>;\n uploadCsv: (file: File) => Promise<void>;\n appendBotResponse: (resp: BotResponse) => void;\n appendUserMessage: (content: string) => Message;\n deactivatePriorChips: (keepId?: string) => void;\n setTyping: (value: boolean) => void;\n clear: () => void;\n loadHistory: (history: Message[]) => void;\n}\n\nexport function useChat(opts: UseChatOptions): UseChatReturn {\n const { apiBase, sessionId, initialMessages, onHistoryChange, onError, onAuthExpired } = opts;\n const [state, dispatch] = useReducer(reducer, initialState);\n const abortRef = useRef<AbortController | null>(null);\n const onHistoryChangeRef = useRef(onHistoryChange);\n const onErrorRef = useRef(onError);\n const onAuthExpiredRef = useRef(onAuthExpired);\n\n useEffect(() => {\n onHistoryChangeRef.current = onHistoryChange;\n onErrorRef.current = onError;\n onAuthExpiredRef.current = onAuthExpired;\n }, [onHistoryChange, onError, onAuthExpired]);\n\n useEffect(() => {\n if (initialMessages && initialMessages.length > 0) {\n dispatch({ type: \"LOAD_HISTORY\", payload: initialMessages });\n }\n }, []);\n\n useEffect(() => {\n onHistoryChangeRef.current?.(state.messages);\n }, [state.messages]);\n\n useEffect(() => {\n return () => {\n abortRef.current?.abort();\n };\n }, []);\n\n const appendUserMessage = useCallback((content: string): Message => {\n const msg: Message = {\n id: newMessageId(),\n role: \"user\",\n content,\n timestamp: Date.now(),\n };\n dispatch({ type: \"ADD_MESSAGE\", payload: msg });\n return msg;\n }, []);\n\n const appendBotResponse = useCallback((resp: BotResponse) => {\n const botMsg: Message = {\n id: newMessageId(),\n role: \"bot\",\n content: resp.message,\n chips: resp.chips ?? [],\n chipsActive: (resp.chips ?? []).length > 0,\n timestamp: Date.now(),\n };\n dispatch({ type: \"ADD_MESSAGE\", payload: botMsg });\n }, []);\n\n const deactivatePriorChips = useCallback((keepId?: string) => {\n dispatch({ type: \"DEACTIVATE_CHIPS\", payload: { exceptId: keepId } });\n }, []);\n\n const uploadCsv = useCallback(\n async (file: File) => {\n if (!sessionId) return;\n\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n deactivatePriorChips();\n appendUserMessage(`Uploaded ${file.name}`);\n dispatch({ type: \"SET_TYPING\", payload: true });\n dispatch({ type: \"SET_STATUS\", payload: \"sending\" });\n dispatch({ type: \"SET_ERROR\", payload: null });\n\n try {\n const resp = await apiUploadPortfolioCsv(apiBase, file, sessionId, controller.signal);\n appendBotResponse(resp);\n dispatch({ type: \"SET_STATUS\", payload: \"idle\" });\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n dispatch({ type: \"SET_ERROR\", payload: error.message });\n }\n dispatch({ type: \"SET_STATUS\", payload: \"error\" });\n } finally {\n dispatch({ type: \"SET_TYPING\", payload: false });\n }\n },\n [apiBase, sessionId, appendUserMessage, appendBotResponse, deactivatePriorChips],\n );\n\n const sendText = useCallback(\n async (text: string) => {\n const trimmed = text.trim();\n if (!trimmed || !sessionId) return;\n\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n deactivatePriorChips();\n appendUserMessage(trimmed);\n dispatch({ type: \"SET_TYPING\", payload: true });\n dispatch({ type: \"SET_STATUS\", payload: \"sending\" });\n dispatch({ type: \"SET_ERROR\", payload: null });\n\n try {\n const context = state.messages.slice(-20);\n const resp = await apiSendMessage(apiBase, trimmed, sessionId, context, controller.signal);\n appendBotResponse(resp);\n dispatch({ type: \"SET_STATUS\", payload: \"idle\" });\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n dispatch({ type: \"SET_ERROR\", payload: error.message });\n }\n dispatch({ type: \"SET_STATUS\", payload: \"error\" });\n } finally {\n dispatch({ type: \"SET_TYPING\", payload: false });\n }\n },\n [apiBase, sessionId, state.messages, appendUserMessage, appendBotResponse, deactivatePriorChips],\n );\n\n const clear = useCallback(() => {\n abortRef.current?.abort();\n dispatch({ type: \"CLEAR\" });\n }, []);\n\n const loadHistory = useCallback((history: Message[]) => {\n dispatch({ type: \"LOAD_HISTORY\", payload: history });\n }, []);\n\n /** Toggle the typing dots externally — used by WealthChat around chip clicks. */\n const setTyping = useCallback((value: boolean) => {\n dispatch({ type: \"SET_TYPING\", payload: value });\n }, []);\n\n return {\n state,\n sendText,\n uploadCsv,\n appendBotResponse,\n appendUserMessage,\n deactivatePriorChips,\n clear,\n loadHistory,\n setTyping,\n };\n}\n","import { useCallback, useEffect, useRef } from \"react\";\nimport { AuthExpiredError, sendChip } from \"../api/chatApi\";\nimport type { BotResponse, Chip } from \"../types\";\n\ninterface UseChipOptions {\n apiBase: string;\n sessionId: string | null;\n onAuthExpired?: () => void;\n onError?: (err: Error) => void;\n}\n\ninterface UseChipReturn {\n callChip: (chip: Chip) => Promise<BotResponse | null>;\n}\n\nexport function useChip(opts: UseChipOptions): UseChipReturn {\n const { apiBase, sessionId, onAuthExpired, onError } = opts;\n const abortRef = useRef<AbortController | null>(null);\n const onAuthExpiredRef = useRef(onAuthExpired);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onAuthExpiredRef.current = onAuthExpired;\n onErrorRef.current = onError;\n }, [onAuthExpired, onError]);\n\n useEffect(() => {\n return () => abortRef.current?.abort();\n }, []);\n\n const callChip = useCallback(\n async (chip: Chip): Promise<BotResponse | null> => {\n if (!sessionId) return null;\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n return await sendChip(apiBase, chip, sessionId, controller.signal);\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return null;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n }\n return null;\n }\n },\n [apiBase, sessionId],\n );\n\n return { callChip };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Message, WACSession } from \"../types\";\nimport {\n DEFAULT_SESSION_TTL_SECONDS,\n clearSession,\n newSessionId,\n readSession,\n touchSession,\n writeSession,\n} from \"../utils/session\";\n\ninterface UseSessionOptions {\n ttlSeconds?: number;\n onExpire?: () => void;\n}\n\ninterface UseSessionReturn {\n session: WACSession | null;\n remainingMs: number;\n setToken: (token: string, userId: string) => void;\n setHistory: (history: Message[]) => void;\n touch: () => void;\n clear: () => void;\n}\n\nexport function useSession(opts: UseSessionOptions = {}): UseSessionReturn {\n const { ttlSeconds = DEFAULT_SESSION_TTL_SECONDS, onExpire } = opts;\n const [session, setSession] = useState<WACSession | null>(null);\n const [remainingMs, setRemainingMs] = useState(0);\n const expiredRef = useRef(false);\n const onExpireRef = useRef(onExpire);\n\n useEffect(() => {\n onExpireRef.current = onExpire;\n }, [onExpire]);\n\n useEffect(() => {\n const current = readSession();\n setSession(current);\n setRemainingMs(current ? current.expiresAt - Date.now() : 0);\n }, []);\n\n useEffect(() => {\n if (!session) return;\n const interval = window.setInterval(() => {\n const current = readSession();\n if (!current) {\n if (!expiredRef.current) {\n expiredRef.current = true;\n onExpireRef.current?.();\n }\n setSession(null);\n setRemainingMs(0);\n return;\n }\n setRemainingMs(current.expiresAt - Date.now());\n }, 15000);\n return () => window.clearInterval(interval);\n }, [session]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onStorage = (e: StorageEvent) => {\n if (e.key && e.key !== \"wac_session\") return;\n const current = readSession();\n setSession(current);\n setRemainingMs(current ? current.expiresAt - Date.now() : 0);\n };\n window.addEventListener(\"storage\", onStorage);\n return () => window.removeEventListener(\"storage\", onStorage);\n }, []);\n\n const setToken = useCallback(\n (token: string, userId: string) => {\n expiredRef.current = false;\n const updated = writeSession(\n {\n token,\n userId,\n sessionId: readSession()?.sessionId ?? newSessionId(),\n history: readSession()?.history ?? [],\n },\n ttlSeconds,\n );\n setSession(updated);\n setRemainingMs(updated ? updated.expiresAt - Date.now() : 0);\n },\n [ttlSeconds],\n );\n\n const setHistory = useCallback(\n (history: Message[]) => {\n const updated = writeSession({ history }, ttlSeconds);\n if (updated) {\n setSession(updated);\n setRemainingMs(updated.expiresAt - Date.now());\n }\n },\n [ttlSeconds],\n );\n\n const touch = useCallback(() => {\n const updated = touchSession(ttlSeconds);\n if (updated) {\n setSession(updated);\n setRemainingMs(updated.expiresAt - Date.now());\n }\n }, [ttlSeconds]);\n\n const clear = useCallback(() => {\n clearSession();\n setSession(null);\n setRemainingMs(0);\n expiredRef.current = true;\n }, []);\n\n return { session, remainingMs, setToken, setHistory, touch, clear };\n}\n",".root {\n --wac-brand: #1a2d5a;\n --wac-brand-contrast: #ffffff;\n --wac-bg: #ffffff;\n --wac-fg: #1f2937;\n --wac-muted: #6b7280;\n --wac-border: #e5e7eb;\n --wac-bot-bg: #f3f4f6;\n --wac-user-bg: var(--wac-brand);\n --wac-chip-bg: #eef2ff;\n --wac-chip-fg: #1e293b;\n --wac-chip-active-bg: var(--wac-brand);\n --wac-chip-active-fg: #ffffff;\n --wac-radius: 14px;\n --wac-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n color: var(--wac-fg);\n box-sizing: border-box;\n}\n\n.root *,\n.root *::before,\n.root *::after {\n box-sizing: inherit;\n}\n\n.floatingButton {\n position: fixed;\n bottom: 24px;\n z-index: 2147483646;\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n cursor: pointer;\n box-shadow: var(--wac-shadow);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 26px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.floatingButton:hover {\n transform: translateY(-2px);\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.22);\n}\n\n.positionRight {\n right: 24px;\n}\n\n.positionLeft {\n left: 24px;\n}\n\n.widget {\n position: fixed;\n bottom: 24px;\n z-index: 2147483647;\n width: 420px;\n max-width: calc(100vw - 24px);\n height: min(760px, calc(100vh - 48px));\n background: var(--wac-bg);\n color: var(--wac-fg);\n border-radius: var(--wac-radius);\n box-shadow: var(--wac-shadow);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--wac-border);\n}\n\n@media (max-width: 640px) {\n .widget {\n width: calc(100vw - 12px);\n height: calc(100vh - 24px);\n bottom: 12px;\n }\n .positionRight,\n .positionLeft {\n right: 6px;\n left: auto;\n }\n .floatingButton {\n width: 56px;\n height: 56px;\n bottom: 16px;\n }\n /* Both positions collapse to right: 6px on mobile, so sync popup */\n .popupBubbleLeft,\n .popupBubbleRight {\n right: 72px;\n left: auto;\n bottom: 16px;\n max-width: calc(100vw - 84px);\n }\n}\n\n.header {\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n padding: 14px 16px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.headerTitle {\n font-weight: 600;\n font-size: 15px;\n line-height: 1.2;\n}\n\n.headerMeta {\n font-size: 11px;\n opacity: 0.85;\n margin-top: 2px;\n}\n\n.headerActions {\n display: flex;\n gap: 4px;\n align-items: center;\n}\n\n.iconButton {\n background: transparent;\n color: inherit;\n border: none;\n cursor: pointer;\n font-size: 18px;\n padding: 4px 8px;\n border-radius: 6px;\n line-height: 1;\n}\n\n.iconButton:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.body {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background: #fafafa;\n scroll-behavior: smooth;\n}\n\n.body::-webkit-scrollbar {\n width: 6px;\n}\n\n.body::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 3px;\n}\n\n.bubble {\n max-width: 80%;\n padding: 10px 14px;\n border-radius: 12px;\n font-size: 14px;\n line-height: 1.45;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n/* markdown-it output inside a bot bubble.\n markdown-it (breaks: true) emits a <br> for every \\n in the source,\n so we MUST NOT also apply white-space: pre-wrap here — otherwise every\n newline gets rendered twice (once via <br>, once via the literal \\n in\n CSS) and the bubble looks double-spaced. */\n.markdown {\n white-space: normal;\n}\n.markdown p {\n margin: 0 0 6px 0;\n}\n.markdown p:last-child {\n margin-bottom: 0;\n}\n.markdown br {\n /* Make consecutive <br>s collapse a bit — keeps line rhythm tight. */\n line-height: 1.4;\n}\n.markdown strong {\n font-weight: 700;\n color: var(--wac-fg);\n letter-spacing: 0.2px;\n}\n.markdown em {\n font-style: italic;\n color: var(--wac-muted);\n}\n.markdown ul,\n.markdown ol {\n margin: 4px 0 6px 0;\n padding-left: 22px;\n}\n.markdown li {\n margin: 1px 0;\n}\n.markdown a {\n color: var(--wac-brand);\n text-decoration: underline;\n}\n.markdown code {\n background: rgba(0, 0, 0, 0.06);\n padding: 1px 4px;\n border-radius: 4px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n}\n.markdown h1,\n.markdown h2,\n.markdown h3 {\n margin: 6px 0 2px 0;\n font-size: 14px;\n font-weight: 700;\n}\n\n.bubbleBot {\n align-self: flex-start;\n background: var(--wac-bot-bg);\n color: var(--wac-fg);\n border-bottom-left-radius: 4px;\n}\n\n.bubbleUser {\n align-self: flex-end;\n background: var(--wac-user-bg);\n color: var(--wac-brand-contrast);\n border-bottom-right-radius: 4px;\n}\n\n.bubbleMeta {\n font-size: 10px;\n color: var(--wac-muted);\n margin-top: 4px;\n text-align: right;\n}\n\n.chipRow {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 8px;\n}\n\n.chip {\n padding: 7px 12px;\n background: var(--wac-chip-bg);\n color: var(--wac-chip-fg);\n border: 1px solid transparent;\n border-radius: 999px;\n font-size: 13px;\n cursor: pointer;\n transition: background 0.15s ease, transform 0.15s ease;\n font-family: inherit;\n}\n\n.chip:hover:not(:disabled) {\n background: #dbeafe;\n transform: translateY(-1px);\n}\n\n.chipActive {\n background: var(--wac-chip-active-bg);\n color: var(--wac-chip-active-fg);\n}\n\n.chipDisabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.typing {\n align-self: flex-start;\n display: inline-flex;\n gap: 4px;\n padding: 10px 14px;\n background: var(--wac-bot-bg);\n border-radius: 12px;\n border-bottom-left-radius: 4px;\n}\n\n.typingDot {\n width: 7px;\n height: 7px;\n background: var(--wac-muted);\n border-radius: 50%;\n animation: wacBlink 1.2s infinite ease-in-out both;\n}\n\n.typingDot:nth-child(2) {\n animation-delay: 0.18s;\n}\n.typingDot:nth-child(3) {\n animation-delay: 0.36s;\n}\n\n@keyframes wacBlink {\n 0%, 80%, 100% { opacity: 0.3; transform: scale(0.85); }\n 40% { opacity: 1; transform: scale(1); }\n}\n\n.input {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--wac-border);\n background: var(--wac-bg);\n}\n\n.inputBox {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--wac-border);\n border-radius: 999px;\n font-size: 14px;\n outline: none;\n font-family: inherit;\n background: #f9fafb;\n color: var(--wac-fg);\n}\n\n.inputBox:focus {\n border-color: var(--wac-brand);\n background: var(--wac-bg);\n}\n\n.inputBox:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.sendButton {\n padding: 0 16px;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n border-radius: 999px;\n font-weight: 600;\n cursor: pointer;\n font-size: 14px;\n font-family: inherit;\n}\n\n.sendButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.hiddenFileInput {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.csvButton {\n flex-shrink: 0;\n padding: 0 12px;\n background: var(--wac-chip-bg);\n color: var(--wac-chip-fg);\n border: 1px solid var(--wac-border);\n border-radius: 999px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n font-family: inherit;\n white-space: nowrap;\n}\n\n.csvButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.authGate {\n margin: auto;\n text-align: center;\n padding: 32px 24px;\n max-width: 280px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.authGateIcon {\n font-size: 36px;\n}\n\n.authGateTitle {\n font-size: 16px;\n font-weight: 600;\n}\n\n.authGateText {\n font-size: 13px;\n color: var(--wac-muted);\n line-height: 1.5;\n}\n\n.authGateButton {\n margin-top: 8px;\n padding: 10px 20px;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n border-radius: 999px;\n cursor: pointer;\n font-weight: 600;\n font-size: 14px;\n font-family: inherit;\n}\n\n.authGateDisclaimer {\n margin-top: 16px;\n padding-top: 12px;\n border-top: 1px dashed var(--wac-border);\n font-size: 11px;\n color: var(--wac-muted);\n line-height: 1.5;\n text-align: left;\n width: 100%;\n}\n\n.authGateDisclaimerTitle {\n font-weight: 700;\n letter-spacing: 0.6px;\n font-size: 10px;\n margin-bottom: 4px;\n color: var(--wac-fg);\n}\n\n.errorBanner {\n background: #fef2f2;\n border: 1px solid #fecaca;\n color: #991b1b;\n padding: 8px 12px;\n font-size: 12px;\n border-radius: 8px;\n margin: 0 14px 8px;\n}\n\n/* ── Greeting popup bubble ─────────────────────────────────────── */\n\n.popupBubble {\n position: fixed;\n bottom: 24px;\n z-index: 2147483646;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border-radius: 12px;\n padding: 12px 36px 12px 14px;\n font-size: 13px;\n line-height: 1.45;\n box-shadow: var(--wac-shadow);\n border: none;\n max-width: 240px;\n animation: wacPopIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* Shared arrow base — direction is set per-position class below */\n.popupBubble::after {\n content: '';\n position: absolute;\n width: 12px;\n height: 12px;\n background: var(--wac-brand);\n}\n\n/* Popup to the LEFT of a right-positioned button — arrow points right */\n.popupBubbleRight {\n right: 94px;\n}\n\n.popupBubbleRight::after {\n right: -7px;\n top: 50%;\n border-top: 1px solid var(--wac-brand);\n border-right: 1px solid var(--wac-brand);\n transform: translateY(-50%) rotate(45deg);\n}\n\n/* Popup to the RIGHT of a left-positioned button — arrow points left */\n.popupBubbleLeft {\n left: 94px;\n}\n\n.popupBubbleLeft::after {\n left: -7px;\n top: 50%;\n border-bottom: 1px solid var(--wac-brand);\n border-left: 1px solid var(--wac-brand);\n transform: translateY(-50%) rotate(45deg);\n}\n\n.popupDismiss {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 14px;\n color: var(--wac-brand-contrast);\n line-height: 1;\n padding: 2px 4px;\n border-radius: 4px;\n font-family: inherit;\n opacity: 0.75;\n}\n\n.popupDismiss:hover {\n background: rgba(255, 255, 255, 0.15);\n opacity: 1;\n}\n\n@keyframes wacPopIn {\n 0% { opacity: 0; transform: scale(0.85) translateY(8px); }\n 100% { opacity: 1; transform: scale(1) translateY(0); }\n}\n","import styles from \"../styles/chat.module.css\";\n\ninterface AuthGateProps {\n brandName: string;\n loginUrl: string;\n onLoginClick?: () => void;\n}\n\nexport function AuthGate({ brandName, loginUrl, onLoginClick }: AuthGateProps) {\n const handleClick = () => {\n if (onLoginClick) {\n onLoginClick();\n return;\n }\n if (typeof window !== \"undefined\") {\n window.location.href = loginUrl;\n }\n };\n\n return (\n <div className={styles.authGate}>\n <div className={styles.authGateIcon} aria-hidden=\"true\">🔒</div>\n <div className={styles.authGateTitle}>Login required</div>\n <div className={styles.authGateText}>\n To access {brandName}, please sign in first.\n </div>\n <button type=\"button\" className={styles.authGateButton} onClick={handleClick}>\n Sign in / Register →\n </button>\n <div className={styles.authGateDisclaimer}>\n <div className={styles.authGateDisclaimerTitle}>DISCLAIMER</div>\n <div>• AI-assisted analysis for educational purposes only.</div>\n <div>• Not financial advice. Markets involve risk.</div>\n <div>• Consult a SEBI-registered advisor before investing.</div>\n </div>\n </div>\n );\n}\n","import type { Chip as ChipType } from \"../types\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChipProps {\n chip: ChipType;\n disabled?: boolean;\n active?: boolean;\n onClick: (chip: ChipType) => void;\n}\n\nexport function Chip({ chip, disabled, active, onClick }: ChipProps) {\n const classes = [\n styles.chip,\n active ? styles.chipActive : \"\",\n disabled ? styles.chipDisabled : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <button\n type=\"button\"\n className={classes}\n disabled={disabled}\n onClick={() => !disabled && onClick(chip)}\n >\n {chip.icon ? <span aria-hidden=\"true\">{chip.icon}</span> : null}\n <span>{chip.label}</span>\n </button>\n );\n}\n","import type { Chip as ChipType } from \"../types\";\nimport { Chip } from \"./Chip\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChipRowProps {\n chips: ChipType[];\n disabled?: boolean;\n onClick: (chip: ChipType) => void;\n}\n\nexport function ChipRow({ chips, disabled, onClick }: ChipRowProps) {\n if (!chips || chips.length === 0) return null;\n return (\n <div className={styles.chipRow}>\n {chips.map((c) => (\n <Chip key={c.id} chip={c} disabled={disabled} onClick={onClick} />\n ))}\n </div>\n );\n}\n","import DOMPurify from \"isomorphic-dompurify\";\n\n/**\n * Backend (chat_widget.py + chat_template_dispatch.py) returns Telegram-HTML in\n * BotResponse.message — e.g. `<b>Heading</b><br>Body<br><i>Note</i>`.\n *\n * We sanitize with DOMPurify against a tight allow-list and feed straight into\n * the bubble via dangerouslySetInnerHTML. This matches the exact look of the\n * Telegram bot for every response template.\n *\n * Markdown-it is intentionally NOT used here anymore — the backend handles all\n * formatting via the shared Telegram templates.\n */\n\nconst ALLOWED_TAGS = [\n \"b\", \"strong\",\n \"i\", \"em\",\n \"u\", \"ins\",\n \"s\", \"strike\", \"del\",\n \"br\",\n \"p\",\n \"code\", \"pre\",\n \"a\",\n \"ul\", \"ol\", \"li\",\n \"blockquote\",\n \"span\",\n];\n\nconst ALLOWED_ATTR = [\"href\", \"target\", \"rel\", \"class\"];\n\nconst SANITIZE_CFG = {\n ALLOWED_TAGS,\n ALLOWED_ATTR,\n // Block javascript: / data: hrefs by stripping URI schemes other than http(s) / mailto\n ALLOW_UNKNOWN_PROTOCOLS: false,\n ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.\\-:]|$))/i,\n};\n\n/**\n * Convert Telegram-style markdown shortcuts to HTML so chip prompts written\n * with `*bold*` / `_italic_` in Python source render the same way as the\n * template HTML output. Also handles the *standard* markdown that\n * AI-generated text (e.g. the sector-news `ai_verdict`) commonly emits.\n *\n * ## Heading → <b>Heading</b> (line-start ATX header, 1–6 #)\n * **text** → <b>text</b> (double asterisk, standard-bold)\n * __text__ → <b>text</b> (double underscore, standard-bold)\n * *text* → <b>text</b> (single asterisk, Telegram-bold)\n * _text_ → <i>text</i> (single underscore, italic)\n *\n * Order matters: double markers are converted before single ones so a `**`\n * pair isn't half-consumed by the single-asterisk rule. The single-marker\n * rules use lookbehind/ahead so they don't touch already-converted `<b>`\n * spans or dangling markers inside HTML attribute values.\n */\nfunction inlineMarkdownToHtml(text: string): string {\n return text\n // ATX headers at the start of a line → bold (verdict gap, no real <h*> here)\n .replace(/^[ \\t]*#{1,6}[ \\t]+(.+?)[ \\t]*$/gm, \"<b>$1</b>\")\n // Standard double-marker bold first, so the single-marker rules skip them.\n .replace(/\\*\\*([^\\n<>]+?)\\*\\*/g, \"<b>$1</b>\")\n .replace(/__([^\\n<>]+?)__/g, \"<b>$1</b>\")\n // Telegram single-asterisk bold / single-underscore italic.\n .replace(/(?<!\\*)\\*([^\\n*<>]+?)\\*(?!\\*)/g, \"<b>$1</b>\")\n .replace(/(?<![_a-zA-Z0-9])_([^\\n_<>]+?)_(?![_a-zA-Z0-9])/g, \"<i>$1</i>\");\n}\n\n/**\n * Render a Telegram-HTML or markdown-flavoured string from the backend as\n * sanitized HTML suitable for dangerouslySetInnerHTML.\n *\n * Pipeline:\n * 1. `*bold*` / `_italic_` markdown shortcuts → `<b>` / `<i>`\n * 2. Single `\\n` → `<br>`, `\\n\\n` → paragraph break (visual gap)\n * 3. DOMPurify sanitization against a tight allow-list\n */\nexport function renderMarkdown(text: string): string {\n if (!text) return \"\";\n\n const inlined = inlineMarkdownToHtml(text);\n\n // Split on blank lines into paragraphs, then within each paragraph turn \\n into <br>.\n const paragraphs = inlined\n .split(/\\n{2,}/)\n .map((para) => para.replace(/\\n/g, \"<br>\"))\n .filter((p) => p.length > 0);\n\n const html = paragraphs.length > 1\n ? paragraphs.map((p) => `<p>${p}</p>`).join(\"\")\n : paragraphs[0] ?? \"\";\n\n return DOMPurify.sanitize(html, SANITIZE_CFG);\n}\n","import type { Chip as ChipType, Message } from \"../types\";\nimport { ChipRow } from \"./ChipRow\";\nimport { renderMarkdown } from \"../utils/markdown\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface MessageBubbleProps {\n message: Message;\n onChipClick: (chip: ChipType) => void;\n}\n\nexport function MessageBubble({ message, onChipClick }: MessageBubbleProps) {\n const isBot = message.role === \"bot\";\n const bubbleClass = isBot\n ? `${styles.bubble} ${styles.bubbleBot}`\n : `${styles.bubble} ${styles.bubbleUser}`;\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\" }}>\n <div className={bubbleClass}>\n {isBot ? (\n <div\n className={styles.markdown}\n dangerouslySetInnerHTML={{ __html: renderMarkdown(message.content) }}\n />\n ) : (\n message.content\n )}\n </div>\n {isBot && message.chips && message.chips.length > 0 ? (\n <ChipRow\n chips={message.chips}\n disabled={!message.chipsActive}\n onClick={onChipClick}\n />\n ) : null}\n </div>\n );\n}\n","import styles from \"../styles/chat.module.css\";\n\nexport function TypingIndicator() {\n return (\n <div className={styles.typing} aria-live=\"polite\" aria-label=\"Assistant is typing\">\n <span className={styles.typingDot} />\n <span className={styles.typingDot} />\n <span className={styles.typingDot} />\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport type { Chip as ChipType, Message } from \"../types\";\nimport { AuthGate } from \"./AuthGate\";\nimport { MessageBubble } from \"./MessageBubble\";\nimport { TypingIndicator } from \"./TypingIndicator\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChatBodyProps {\n isLoggedIn: boolean;\n loading: boolean;\n messages: Message[];\n isTyping: boolean;\n brandName: string;\n loginUrl: string;\n error: string | null;\n onChipClick: (chip: ChipType) => void;\n onLoginClick?: () => void;\n}\n\nexport function ChatBody({\n isLoggedIn,\n loading,\n messages,\n isTyping,\n brandName,\n loginUrl,\n error,\n onChipClick,\n onLoginClick,\n}: ChatBodyProps) {\n const endRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n endRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages.length, isTyping]);\n\n if (loading) {\n return (\n <div className={styles.body}>\n <TypingIndicator />\n </div>\n );\n }\n\n if (!isLoggedIn) {\n return (\n <div className={styles.body}>\n <AuthGate\n brandName={brandName}\n loginUrl={loginUrl}\n onLoginClick={onLoginClick}\n />\n </div>\n );\n }\n\n return (\n <div className={styles.body}>\n {messages.map((m) => (\n <MessageBubble key={m.id} message={m} onChipClick={onChipClick} />\n ))}\n {isTyping ? <TypingIndicator /> : null}\n {error ? <div className={styles.errorBanner}>{error}</div> : null}\n <div ref={endRef} />\n </div>\n );\n}\n","export function formatCountdown(remainingMs: number): string {\n if (remainingMs <= 0) return \"expired\";\n const totalSeconds = Math.floor(remainingMs / 1000);\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n if (hours > 0) return `${hours}h ${minutes}m left`;\n if (minutes > 0) return `${minutes}m ${seconds}s left`;\n return `${seconds}s left`;\n}\n\nexport function formatRelativeTime(ts: number, now: number = Date.now()): string {\n const diff = Math.max(0, now - ts);\n const seconds = Math.floor(diff / 1000);\n if (seconds < 60) return \"just now\";\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n return `${days}d ago`;\n}\n","import styles from \"../styles/chat.module.css\";\nimport { formatCountdown } from \"../utils/time\";\n\ninterface ChatHeaderProps {\n brandName: string;\n remainingMs: number;\n showCountdown: boolean;\n onClose: () => void;\n onClear?: () => void;\n}\n\nexport function ChatHeader({\n brandName,\n remainingMs,\n showCountdown,\n onClose,\n onClear,\n}: ChatHeaderProps) {\n return (\n <div className={styles.header}>\n <div>\n <div className={styles.headerTitle}>{brandName}</div>\n {showCountdown && remainingMs > 0 ? (\n <div className={styles.headerMeta}>Session: {formatCountdown(remainingMs)}</div>\n ) : null}\n </div>\n <div className={styles.headerActions}>\n {onClear ? (\n <button\n type=\"button\"\n className={styles.iconButton}\n onClick={onClear}\n aria-label=\"Clear conversation\"\n title=\"Clear conversation\"\n >\n ↺\n </button>\n ) : null}\n <button\n type=\"button\"\n className={styles.iconButton}\n onClick={onClose}\n aria-label=\"Close chat\"\n title=\"Close\"\n >\n ✕\n </button>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChatInputProps {\n disabled?: boolean;\n placeholder?: string;\n onSend: (text: string) => void;\n}\n\nexport function ChatInput({ disabled, placeholder, onSend }: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (!disabled) {\n inputRef.current?.focus();\n }\n }, [disabled]);\n\n const submit = () => {\n const trimmed = value.trim();\n if (!trimmed || disabled) return;\n onSend(trimmed);\n setValue(\"\");\n inputRef.current?.focus();\n };\n\n return (\n <div className={styles.input}>\n <input\n ref={inputRef}\n type=\"text\"\n className={styles.inputBox}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n }}\n disabled={disabled}\n placeholder={placeholder ?? \"Type a message…\"}\n aria-label=\"Message input\"\n />\n <button\n type=\"button\"\n className={styles.sendButton}\n onClick={submit}\n disabled={disabled || value.trim().length === 0}\n >\n Send\n </button>\n </div>\n );\n}\n","import type { ChatPosition } from \"../types\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface FloatingButtonProps {\n position: ChatPosition;\n onClick: () => void;\n brandColor?: string;\n showPopup?: boolean;\n popupMessage?: string;\n onPopupDismiss?: () => void;\n}\n\nexport function FloatingButton({ position, onClick, brandColor, showPopup, popupMessage, onPopupDismiss }: FloatingButtonProps) {\n const posClass = position === \"bottom-left\" ? styles.positionLeft : styles.positionRight;\n const popupPosClass = position === \"bottom-left\" ? styles.popupBubbleLeft : styles.popupBubbleRight;\n return (\n <>\n {showPopup && popupMessage ? (\n <div\n className={`${styles.popupBubble} ${popupPosClass}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {popupMessage}\n <button\n type=\"button\"\n className={styles.popupDismiss}\n onClick={onPopupDismiss}\n aria-label=\"Dismiss greeting\"\n >\n ✕\n </button>\n </div>\n ) : null}\n <button\n type=\"button\"\n className={`${styles.floatingButton} ${posClass}`}\n onClick={onClick}\n aria-label=\"Open chat\"\n style={brandColor ? { background: brandColor } : undefined}\n >\n 💬\n </button>\n </>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAuth } from \"../hooks/useAuth\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useChip } from \"../hooks/useChip\";\nimport { useSession } from \"../hooks/useSession\";\nimport type { Chip, Message, WealthChatProps } from \"../types\";\nimport { DEFAULT_SESSION_TTL_SECONDS } from \"../utils/session\";\nimport { ChatBody } from \"./ChatBody\";\nimport { ChatHeader } from \"./ChatHeader\";\nimport { ChatInput } from \"./ChatInput\";\nimport { FloatingButton } from \"./FloatingButton\";\nimport styles from \"../styles/chat.module.css\";\n\nconst DEFAULT_BRAND_NAME = \"Wealth Alpha AI\";\nconst DEFAULT_BRAND_COLOR = \"#1a2d5a\";\nconst DEFAULT_AUTH_CHECK = \"/me\";\nconst DEFAULT_GREETING = \"Hi! I'm your Wealth Alpha AI assistant. How can I help you?\";\n\nconst DISCLAIMER_BLOCK =\n \"DISCLAIMER:\\n\" +\n \"• AI-assisted analysis for educational purposes only.\\n\" +\n \"• Not financial advice. Markets involve risk.\\n\" +\n \"• Consult a SEBI-registered advisor before investing.\";\n\nconst CTA_LINE =\n \"Select a quick command below — or type your query to ask our AI Research Analyst directly.\";\n\n/** Opens file picker in-widget; must match backend PORTFOLIO_CSV_PICK_CHIP.id */\nconst PORTFOLIO_CSV_CHIP_ID = \"__portfolio_csv_upload\";\n\nfunction buildWelcome(name: string | undefined, plan: string | undefined): string {\n const greeting = name\n ? `Welcome back, ${name}! You have ${plan ? plan : \"Premium\"} access.`\n : `Welcome! You have ${plan ? plan : \"Premium\"} access.`;\n return `${greeting}\\n\\n${DISCLAIMER_BLOCK}\\n\\n${CTA_LINE}`;\n}\n\nexport function WealthChat(props: WealthChatProps) {\n const {\n apiBase,\n authCheck = DEFAULT_AUTH_CHECK,\n loginUrl,\n sessionTTL = DEFAULT_SESSION_TTL_SECONDS,\n welcomeMessage,\n brandName = DEFAULT_BRAND_NAME,\n brandColor = DEFAULT_BRAND_COLOR,\n position = \"bottom-right\",\n defaultOpen = false,\n showCountdown = true,\n greetingMessage = DEFAULT_GREETING,\n onLogin,\n onLogout,\n onSessionExpire,\n onError,\n } = props;\n\n const [mounted, setMounted] = useState(false);\n const [open, setOpen] = useState(defaultOpen);\n const [showPopup, setShowPopup] = useState(false);\n const popupShownRef = useRef(defaultOpen);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!mounted || open || popupShownRef.current) return;\n const timer = setTimeout(() => {\n setShowPopup(true);\n popupShownRef.current = true;\n }, 1000);\n return () => clearTimeout(timer);\n }, [mounted, open]);\n\n const {\n session,\n remainingMs,\n setHistory,\n touch,\n clear: clearSessionState,\n } = useSession({\n ttlSeconds: sessionTTL,\n onExpire: onSessionExpire,\n });\n\n const { isLoggedIn, user, loading: authLoading } = useAuth({\n apiBase,\n authCheck,\n enabled: mounted && open,\n onError,\n });\n\n const handleAuthExpired = useCallback(() => {\n clearSessionState();\n onSessionExpire?.();\n }, [clearSessionState, onSessionExpire]);\n\n const handleHistoryChange = useCallback(\n (history: Message[]) => {\n if (!session) return;\n setHistory(history);\n },\n [session, setHistory],\n );\n\n const csvFileRef = useRef<HTMLInputElement>(null);\n\n const {\n state: chatState,\n sendText,\n uploadCsv,\n appendBotResponse,\n appendUserMessage,\n deactivatePriorChips,\n setTyping,\n loadHistory,\n clear: clearChat,\n } = useChat({\n apiBase,\n sessionId: session?.sessionId ?? null,\n initialMessages: session?.history,\n onHistoryChange: handleHistoryChange,\n onAuthExpired: handleAuthExpired,\n onError,\n });\n\n const { callChip } = useChip({\n apiBase,\n sessionId: session?.sessionId ?? null,\n onAuthExpired: handleAuthExpired,\n onError,\n });\n\n const welcomeShownRef = useMemo(() => ({ shown: false }), []);\n\n useEffect(() => {\n if (!isLoggedIn || !open) return;\n if (chatState.messages.length > 0) return;\n if (welcomeShownRef.shown) return;\n welcomeShownRef.shown = true;\n const messageText =\n welcomeMessage ??\n user?.welcomeMessage ??\n buildWelcome(user?.name, user?.plan);\n appendBotResponse({\n message: messageText,\n chips: user?.rootChips ?? [],\n sessionId: session?.sessionId ?? \"\",\n endOfFlow: false,\n });\n onLogin?.();\n }, [isLoggedIn, open, chatState.messages.length, welcomeMessage, session, user, appendBotResponse, onLogin, welcomeShownRef]);\n\n const handleChipClick = useCallback(\n async (chip: Chip) => {\n touch();\n deactivatePriorChips();\n\n if (chip.id === PORTFOLIO_CSV_CHIP_ID) {\n appendUserMessage(chip.label);\n csvFileRef.current?.click();\n return;\n }\n\n appendUserMessage(chip.label);\n setTyping(true);\n try {\n const resp = await callChip(chip);\n if (resp) appendBotResponse(resp);\n } finally {\n setTyping(false);\n }\n },\n [touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse],\n );\n\n const handleCsvFileSelected = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = \"\";\n if (file) {\n touch();\n void uploadCsv(file);\n }\n },\n [touch, uploadCsv],\n );\n\n const handleSend = useCallback(\n (text: string) => {\n touch();\n void sendText(text);\n },\n [touch, sendText],\n );\n\n const handleFloatingButtonClick = useCallback(() => {\n setOpen(true);\n setShowPopup(false);\n }, []);\n\n const handleClose = useCallback(() => setOpen(false), []);\n\n const handleClear = useCallback(() => {\n clearChat();\n welcomeShownRef.shown = false;\n setHistory([]);\n }, [clearChat, setHistory, welcomeShownRef]);\n\n const handleLoginClick = useCallback(() => {\n if (typeof window !== \"undefined\") {\n window.location.href = loginUrl;\n }\n }, [loginUrl]);\n\n if (!mounted) return null;\n\n const rootStyle = {\n [\"--wac-brand\" as string]: brandColor,\n } as React.CSSProperties;\n\n return (\n <div className={styles.root} style={rootStyle}>\n {!open ? (\n <FloatingButton\n position={position}\n onClick={handleFloatingButtonClick}\n brandColor={brandColor}\n showPopup={showPopup}\n popupMessage={greetingMessage}\n onPopupDismiss={() => setShowPopup(false)}\n />\n ) : null}\n {open ? (\n <div\n className={`${styles.widget} ${position === \"bottom-left\" ? styles.positionLeft : styles.positionRight}`}\n >\n <ChatHeader\n brandName={brandName}\n remainingMs={remainingMs}\n showCountdown={showCountdown && isLoggedIn}\n onClose={handleClose}\n onClear={isLoggedIn ? handleClear : undefined}\n />\n <ChatBody\n isLoggedIn={isLoggedIn}\n loading={authLoading}\n messages={chatState.messages}\n isTyping={chatState.isTyping}\n brandName={brandName}\n loginUrl={loginUrl}\n error={chatState.error}\n onChipClick={handleChipClick}\n onLoginClick={handleLoginClick}\n />\n <input\n ref={csvFileRef}\n type=\"file\"\n accept=\".csv,text/csv\"\n className={styles.hiddenFileInput}\n onChange={handleCsvFileSelected}\n aria-hidden\n tabIndex={-1}\n />\n {isLoggedIn ? (\n <ChatInput\n disabled={chatState.isTyping}\n onSend={handleSend}\n placeholder=\"Type a message…\"\n />\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/session.ts","../src/api/chatApi.ts","../src/hooks/useAuth.ts","../src/hooks/useChat.ts","../src/hooks/useChip.ts","../src/hooks/useSession.ts","../src/styles/chat.module.css","../src/components/AuthGate.tsx","../src/components/Chip.tsx","../src/components/ChipRow.tsx","../src/utils/markdown.ts","../src/components/MessageBubble.tsx","../src/components/TypingIndicator.tsx","../src/components/ChatBody.tsx","../src/components/ChatHeader.tsx","../src/components/ChatInput.tsx","../src/components/FloatingButton.tsx","../src/components/WealthChat.tsx"],"names":["fallback","useRef","useEffect","useCallback","useState","root","headerTitle","menuItemTitle","markdown","floatingButton","positionRight","positionLeft","widget","popupBubbleLeft","popupBubbleRight","header","headerMeta","headerActions","iconButton","body","bubble","bubbleBot","bubbleUser","bubbleCard","bubbleMeta","chipRow","chip","chipActive","chipDisabled","typing","typingDot","wacBlink","input","inputBox","sendButton","hiddenFileInput","csvButton","authGate","authGateIcon","authGateTitle","authGateText","authGateButton","authGateDisclaimer","authGateDisclaimerTitle","errorBanner","popupBubble","wacPopIn","popupDismiss","menuGrid","menuItem","menuItemIcon","menuItemSvg","menuItemSub","menuIconGreen","menuIconBlue","menuIconLeaf","menuIconRed","menuIconOrange","menuIconGold","menuIconTeal","menuIconPurple","chat_bubbleBot","jsxs","jsx"],"mappings":";;;;;;;AAEO,IAAM,WAAA,GAAc;AACpB,IAAM,2BAAA,GAA8B;AACpC,IAAM,WAAA,GAAc,GAAA;AAI3B,IAAM,mBAAA,GAAsB,CAAC,OAAA,EAAS,cAAA,EAAgB,cAAc,KAAK,CAAA;AAEzE,IAAM,YAAY,MAChB,OAAO,WAAW,WAAA,IAAe,OAAO,OAAO,YAAA,KAAiB,WAAA;AAElE,SAAS,gBAAgB,KAAA,EAAuB;AAC9C,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AACzD,EAAA,MAAM,SAAS,MAAA,GAAS,KAAA,CAAM,OAAO,MAAA,CAAO,MAAA,GAAS,KAAK,CAAC,CAAA;AAC3D,EAAA,OAAO,KAAK,MAAM,CAAA;AACpB;AAEA,SAAS,UAAU,KAAA,EAA+C;AAChE,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,MAAM,MAAA,KAAW,CAAA,IAAK,CAAC,KAAA,CAAM,CAAC,GAAG,OAAO,IAAA;AAC5C,IAAA,OAAO,KAAK,KAAA,CAAM,eAAA,CAAgB,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAAA,EAC7C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,aAAa,KAAA,EAA8B;AAClD,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,MAAM,GAAA,GAAM,UAAU,KAAK,CAAA;AAC3B,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,IAAA;AACpC,EAAA,OAAO,GAAA,GAAM,GAAA;AACf;AAEA,SAAS,UAAU,KAAA,EAAuB;AACxC,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,IAAI,CAAC,SAAS,OAAO,EAAA;AACrB,EAAA,MAAM,EAAA,GAAK,QAAQ,IAAI,CAAA,IAAK,QAAQ,KAAK,CAAA,IAAK,QAAQ,SAAS,CAAA;AAC/D,EAAA,OAAO,EAAA,IAAM,IAAA,GAAO,MAAA,CAAO,EAAE,CAAA,GAAI,EAAA;AACnC;AAEA,SAAS,iBAAA,GAA2D;AAClE,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,KAAA,MAAW,OAAO,mBAAA,EAAqB;AACrC,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAC7C,IAAA,IAAI,KAAA,IAAS,MAAM,MAAA,GAAS,EAAA,SAAW,EAAE,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,EAC7D;AACA,EAAA,OAAO,IAAA;AACT;AAEA,IAAM,UAAA,GAAa,CAAC,MAAA,KAA2B;AAC7C,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAA,CAAO,YAAY,CAAA,CAAA;AAAA,EACzC;AACA,EAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,KAAK,GAAA,EAAI,CAAE,SAAS,EAAE,CAAC,IAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AACxF,CAAA;AAEO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,WAAW,KAAK,CAAA;AACzB;AAEO,SAAS,YAAA,GAAuB;AACrC,EAAA,OAAO,WAAW,KAAK,CAAA;AACzB;AAEO,SAAS,WAAA,GAAiC;AAC/C,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,WAAW,CAAA;AACnD,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC9B,MAAA,MAAM,QACJ,OAAA,IACA,OAAO,OAAA,CAAQ,KAAA,KAAU,YACzB,OAAA,CAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,IACvB,OAAO,OAAA,CAAQ,SAAA,KAAc,YAC7B,IAAA,CAAK,GAAA,KAAQ,OAAA,CAAQ,SAAA;AACvB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,MAAMA,YAAW,iBAAA,EAAkB;AAGnC,QAAA,IAAI,CAACA,SAAAA,IAAY,OAAA,CAAQ,UAAA,KAAe,UAAA,EAAY;AAClD,UAAA,YAAA,EAAa;AACb,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,IAAIA,SAAAA,IAAYA,SAAAA,CAAS,KAAA,KAAU,OAAA,CAAQ,KAAA,EAAO;AAChD,UAAA,OAAO,kBAAA,CAAmBA,SAAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AAAA,QACnD;AACA,QAAA,OAAO,OAAA;AAAA,MACT;AAEA,MAAA,YAAA,EAAa;AAAA,IACf;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,YAAA,EAAa;AAAA,EACf;AAEA,EAAA,MAAM,WAAW,iBAAA,EAAkB;AACnC,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,EAAA,OAAO,kBAAA,CAAmB,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AAChD;AAEA,SAAS,kBAAA,CAAmB,OAAe,KAAA,EAA6C;AACtF,EAAA,MAAM,MAAA,GAAS,aAAa,KAAK,CAAA;AACjC,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,SAAA,GAAY,MAAA,IAAU,GAAA,GAAM,2BAAA,GAA8B,GAAA;AAChE,EAAA,IAAI,GAAA,IAAO,WAAW,OAAO,IAAA;AAC7B,EAAA,MAAM,OAAA,GAAsB;AAAA,IAC1B,KAAA;AAAA,IACA,MAAA,EAAQ,SAAA,CAAU,KAAK,CAAA,IAAK,OAAO,MAAA,IAAU,EAAA;AAAA,IAC7C,SAAA,EAAW,KAAA,EAAO,SAAA,IAAa,YAAA,EAAa;AAAA,IAC5C,SAAA;AAAA,IACA,UAAA,EAAY,GAAA;AAAA,IACZ,OAAA,EAAS,KAAA,EAAO,OAAA,IAAW,EAAC;AAAA,IAC5B,UAAA,EAAY;AAAA,GACd;AACA,EAAA,IAAI,WAAU,EAAG;AACf,IAAA,IAAI;AACF,MAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,WAAA,EAAa,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,IAClE,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,YAAA,CACd,IAAA,EACA,UAAA,GAAqB,2BAAA,EACF;AACnB,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,IAAA;AACzB,EAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,WAAW,WAAA,EAAY;AAC7B,EAAA,MAAM,OACJ,QAAA,IACA;AAAA,IACE,KAAA,EAAO,EAAA;AAAA,IACP,MAAA,EAAQ,EAAA;AAAA,IACR,WAAW,YAAA,EAAa;AAAA,IACxB,SAAA,EAAW,MAAM,UAAA,GAAa,GAAA;AAAA,IAC9B,UAAA,EAAY,GAAA;AAAA,IACZ,SAAS;AAAC,GACZ;AAEF,EAAA,MAAM,MAAA,GAAqB;AAAA,IACzB,GAAG,IAAA;AAAA,IACH,GAAG,IAAA;AAAA,IACH,SAAA,EAAW,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,aAAa,YAAA,EAAa;AAAA,IAC5D,UAAA,EAAY,GAAA;AAAA,IACZ,SAAA,EAAW,MAAM,UAAA,GAAa,GAAA;AAAA,IAC9B,OAAA,EAAS,WAAA,CAAY,IAAA,CAAK,OAAA,IAAW,KAAK,OAAO;AAAA,GACnD;AAEA,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,aAAa,OAAA,CAAQ,WAAA,EAAa,IAAA,CAAK,SAAA,CAAU,MAAM,CAAC,CAAA;AAC/D,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,YAAA,GAAqB;AACnC,EAAA,IAAI,CAAC,WAAU,EAAG;AAClB,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,YAAA,CAAa,WAAW,WAAW,CAAA;AAAA,EAC5C,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAEO,SAAS,YAAY,OAAA,EAA2C;AACrE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,SAAU,EAAC;AACrC,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,WAAA,EAAa,OAAO,OAAA;AAC1C,EAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,MAAA,GAAS,WAAW,CAAA;AACnD;AAEO,SAAS,YAAA,CACd,aAAqB,2BAAA,EACF;AACnB,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,OAAO,YAAA,CAAa,EAAC,EAAG,UAAU,CAAA;AACpC;;;ACtLA,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,eAAA,GAAkB,CAAA;AACxB,IAAM,mBAAA,GAAsB,GAAA;AAErB,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EAGlC,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,SAAA,EAAmB;AAC9D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AACF;AAEO,IAAM,gBAAA,GAAN,cAA+B,QAAA,CAAS;AAAA,EAC7C,YAAY,SAAA,EAAmB;AAC7B,IAAA,KAAA,CAAM,4BAAA,EAA8B,KAAK,SAAS,CAAA;AAClD,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF;AAWA,IAAM,oBAAoB,MAAc;AACtC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,MAAA,CAAO,eAAe,UAAA,EAAY;AAC5E,IAAA,OAAO,OAAO,UAAA,EAAW;AAAA,EAC3B;AACA,EAAA,OAAO,OAAO,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,GAAS,QAAA,CAAS,EAAE,EAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,CAAA;AAClF,CAAA;AAEA,IAAM,KAAA,GAAQ,CAAC,EAAA,KACb,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAElD,IAAM,OAAA,GAAU,CAAC,IAAA,EAAc,IAAA,KAAyB;AACtD,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC3C,EAAA,MAAM,cAAc,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAI,CAAA,CAAA;AAC1D,EAAA,OAAO,CAAA,EAAG,WAAW,CAAA,EAAG,WAAW,CAAA,CAAA;AACrC,CAAA;AAEA,eAAe,OAAA,CACb,OAAA,EACA,IAAA,EACA,IAAA,GAAuB,EAAC,EACZ;AACZ,EAAA,MAAM;AAAA,IACJ,MAAA,GAAS,KAAA;AAAA,IACT,IAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,OAAA,GAAU,eAAA;AAAA,IACV,IAAA,GAAO;AAAA,GACT,GAAI,IAAA;AAEJ,EAAA,MAAM,GAAA,GAAM,gBAAgB,IAAA,CAAK,IAAI,IAAI,IAAA,GAAO,OAAA,CAAQ,SAAS,IAAI,CAAA;AACrE,EAAA,MAAM,YAAY,iBAAA,EAAkB;AAEpC,EAAA,IAAI,SAAA,GAA0B,IAAA;AAE9B,EAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,OAAA,EAAS,OAAA,EAAA,EAAW;AACnD,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,SAAS,CAAA;AAEhE,IAAA,MAAM,WAAA,GAAc,MAAM,UAAA,CAAW,KAAA,EAAM;AAC3C,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,IAAI,OAAO,OAAA,EAAS;AAClB,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAA;AAAA,MAChD;AACA,MAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,WAAA,EAAa,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IAC9D;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,OAAA,GAAkC;AAAA,QACtC,cAAA,EAAgB,kBAAA;AAAA,QAChB,cAAA,EAAgB;AAAA,OAClB;AACA,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,QAAA,IAAI,SAAS,KAAA,EAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,QAAQ,KAAK,CAAA,CAAA;AAAA,MACxE;AAEA,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QAC3B,MAAA;AAAA,QACA,OAAA;AAAA,QACA,MAAM,IAAA,KAAS,KAAA,CAAA,GAAY,KAAA,CAAA,GAAY,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,QAC1D,QAAQ,UAAA,CAAW,MAAA;AAAA,QACnB,WAAA,EAAa;AAAA,OACd,CAAA;AAED,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,QAAA,YAAA,EAAa;AACb,QAAA,MAAM,IAAI,iBAAiB,SAAS,CAAA;AAAA,MACtC;AAEA,MAAA,IAAI,GAAA,CAAI,MAAA,IAAU,GAAA,IAAO,OAAA,GAAU,OAAA,EAAS;AAC1C,QAAA,SAAA,GAAY,IAAI,SAAS,CAAA,aAAA,EAAgB,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,QAAQ,SAAS,CAAA;AAC5E,QAAA,MAAM,SAAA;AAAA,MACR;AAEA,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,IAAI,SAAS,GAAA,CAAI,UAAA;AACjB,QAAA,IAAI;AACF,UAAA,MAAM,OAAA,GAAW,MAAM,GAAA,CAAI,IAAA,EAAK;AAChC,UAAA,MAAA,GAAS,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,MAAA,IAAU,MAAA;AAAA,QAChD,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,MAAM,IAAI,SAAS,MAAA,IAAU,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,MAAA,EAAQ,SAAS,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,EAAK,OAAO,KAAA,CAAA;AAC/B,MAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,IACzB,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,KAAA,GAAQ,GAAA;AACd,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,KAAS,YAAA;AAC/B,MAAA,MAAM,SAAS,KAAA,YAAiB,gBAAA;AAChC,MAAA,MAAM,WAAA,GACJ,CAAC,MAAA,IACD,CAAC,MAAA,EAAQ,YACR,OAAA,IAAW,KAAA,YAAiB,SAAA,IAAc,KAAA,CAAmB,MAAA,IAAU,GAAA,CAAA;AAE1E,MAAA,IAAI,MAAA,IAAU,CAAC,WAAA,IAAe,OAAA,KAAY,OAAA,EAAS;AACjD,QAAA,MAAM,KAAA;AAAA,MACR;AACA,MAAA,SAAA,GAAY,KAAA;AACZ,MAAA,MAAM,MAAM,mBAAA,GAAsB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAC,CAAA;AAAA,IACxD,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,IAAI,MAAA,EAAQ,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,WAAW,CAAA;AAAA,IAC7D;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,IAAa,IAAI,KAAA,CAAM,gBAAgB,CAAA;AAC/C;AAEA,eAAsB,SAAA,CACpB,OAAA,EACA,SAAA,EACA,MAAA,EACkB;AAClB,EAAA,OAAO,OAAA,CAAiB,SAAS,SAAA,EAAW;AAAA,IAC1C,MAAA,EAAQ,KAAA;AAAA,IACR,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACV,CAAA;AACH;AAEA,eAAsB,QAAA,CACpB,OAAA,EACA,IAAA,EACA,SAAA,EACA,MAAA,EACsB;AACtB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,IAAW,CAAA,MAAA,EAAS,KAAK,EAAE,CAAA,CAAA;AAC7C,EAAA,OAAO,OAAA,CAAqB,SAAS,IAAA,EAAM;AAAA,IACzC,MAAA,EAAQ,MAAA;AAAA,IACR,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,CAAK,IAAI,SAAA,EAAU;AAAA,IACnC;AAAA,GACD,CAAA;AACH;AAEA,eAAsB,WAAA,CACpB,OAAA,EACA,OAAA,EACA,SAAA,EACA,SACA,MAAA,EACsB;AACtB,EAAA,OAAO,OAAA,CAAqB,SAAS,UAAA,EAAY;AAAA,IAC/C,MAAA,EAAQ,MAAA;AAAA,IACR,IAAA,EAAM,EAAE,OAAA,EAAS,SAAA,EAAW,OAAA,EAAQ;AAAA,IACpC;AAAA,GACD,CAAA;AACH;AAEA,eAAsB,kBAAA,CACpB,OAAA,EACA,IAAA,EACA,SAAA,EACA,MAAA,EACsB;AACtB,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,EAAS,uBAAuB,CAAA;AACpD,EAAA,MAAM,YAAY,iBAAA,EAAkB;AACpC,EAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,EAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,EAAA,IAAA,CAAK,MAAA,CAAO,aAAa,SAAS,CAAA;AAClC,EAAA,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,IAAA,CAAK,IAAI,CAAA;AAEnC,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,YAAY,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,GAAK,CAAA;AAC5D,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,MAAM,IAAI,YAAA,CAAa,SAAA,EAAW,YAAY,CAAA;AAAA,IAChD;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,MAAM,UAAA,CAAW,OAAM,EAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AAAA,EAC3E;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAkC,EAAE,cAAA,EAAgB,SAAA,EAAU;AACpE,IAAA,IAAI,SAAS,KAAA,EAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,QAAQ,KAAK,CAAA,CAAA;AAEtE,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAC3B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA,EAAM,IAAA;AAAA,MACN,QAAQ,UAAA,CAAW,MAAA;AAAA,MACnB,WAAA,EAAa;AAAA,KACd,CAAA;AAED,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,GAAA,CAAI,WAAW,GAAA,EAAK;AAC5C,MAAA,YAAA,EAAa;AACb,MAAA,MAAM,IAAI,iBAAiB,SAAS,CAAA;AAAA,IACtC;AACA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,IAAI,SAAS,GAAA,CAAI,UAAA;AACjB,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAW,MAAM,GAAA,CAAI,IAAA,EAAK;AAChC,QAAA,MAAA,GAAS,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,MAAA,IAAU,MAAA;AAAA,MAChD,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,MAAM,IAAI,SAAS,MAAA,IAAU,CAAA,KAAA,EAAQ,IAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,MAAA,EAAQ,SAAS,CAAA;AAAA,IAC1E;AACA,IAAA,OAAQ,MAAM,IAAI,IAAA,EAAK;AAAA,EACzB,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,SAAS,CAAA;AAAA,EACxB;AACF;AAEA,eAAsB,MAAA,CAAO,SAAiB,MAAA,EAAqC;AACjF,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,CAAc,SAAS,cAAA,EAAgB;AAAA,MAC3C,MAAA,EAAQ,MAAA;AAAA,MACR,MAAA;AAAA,MACA,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,YAAA,EAAa;AAAA,EACf;AACF;;;ACvOO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,OAAA,GAAU,IAAA,EAAM,SAAQ,GAAI,IAAA;AACxD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAyB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAkB,IAAI,CAAA;AACpD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AACrD,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAClC,EAAA,MAAM,UAAA,GAAa,OAAO,OAAO,CAAA;AAEjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAAA,EACvB,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,IAAA,IAAI,CAAC,SAAS,KAAA,EAAO;AACnB,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,SAAA,CAAU,SAAS,SAAA,EAAW,UAAA,CAAW,MAAM,CAAA,CAC5C,IAAA,CAAK,CAAC,CAAA,KAAM;AACX,MAAA,OAAA,CAAQ,CAAC,CAAA;AACT,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAe;AACrB,MAAA,IAAI,GAAA,CAAI,SAAS,YAAA,EAAc;AAC/B,MAAA,IAAI,eAAe,gBAAA,EAAkB;AACnC,QAAA,YAAA,EAAa;AACb,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,CAAA,MAAO;AACL,QAAA,QAAA,CAAS,GAAG,CAAA;AACZ,QAAA,UAAA,CAAW,UAAU,GAAG,CAAA;AAAA,MAC1B;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,CAAC,UAAA,CAAW,MAAA,CAAO,OAAA,aAAoB,KAAK,CAAA;AAAA,IAClD,CAAC,CAAA;AAEH,IAAA,OAAO,MAAM,WAAW,KAAA,EAAM;AAAA,EAChC,GAAG,CAAC,OAAA,EAAS,SAAA,EAAW,OAAA,EAAS,IAAI,CAAC,CAAA;AAEtC,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,MAAM,OAAA,CAAQ,CAAC,MAAM,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAE3D,EAAA,OAAO;AAAA,IACL,YAAY,IAAA,KAAS,IAAA;AAAA,IACrB,IAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AACF;AC9DA,IAAM,YAAA,GAA0B;AAAA,EAC9B,UAAU,EAAC;AAAA,EACX,QAAA,EAAU,KAAA;AAAA,EACV,MAAA,EAAQ,MAAA;AAAA,EACR,KAAA,EAAO;AACT,CAAA;AAEA,SAAS,OAAA,CAAQ,OAAkB,MAAA,EAA+B;AAChE,EAAA,QAAQ,OAAO,IAAA;AAAM,IACnB,KAAK,aAAA,EAAe;AAClB,MAAA,MAAM,OAAO,CAAC,GAAG,KAAA,CAAM,QAAA,EAAU,OAAO,OAAO,CAAA;AAC/C,MAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,WAAA,GAAc,KAAK,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,WAAW,CAAA,GAAI,IAAA;AACpF,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAA,EAAQ;AAAA,IACvC;AAAA,IACA,KAAK,YAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAO,OAAA,EAAQ;AAAA,IAC9C,KAAK,YAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,OAAO,OAAA,EAAQ;AAAA,IAC5C,KAAK,WAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,KAAA,EAAO,OAAO,OAAA,EAAQ;AAAA,IAC3C,KAAK,kBAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,QAAA,EAAU,MAAM,QAAA,CAAS,GAAA;AAAA,UAAI,CAAC,CAAA,KAC5B,CAAA,CAAE,EAAA,KAAO,MAAA,CAAO,OAAA,CAAQ,QAAA,GAAW,CAAA,GAAI,EAAE,GAAG,CAAA,EAAG,WAAA,EAAa,KAAA;AAAM;AACpE,OACF;AAAA,IACF,KAAK,cAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,QAAA,EAAU,OAAO,OAAA,EAAQ;AAAA,IAC9C,KAAK,OAAA;AACH,MAAA,OAAO,YAAA;AAAA,IACT;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;AAuBO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,iBAAiB,eAAA,EAAiB,OAAA,EAAS,eAAc,GAAI,IAAA;AACzF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,UAAA,CAAW,SAAS,YAAY,CAAA;AAC1D,EAAA,MAAM,QAAA,GAAWC,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,kBAAA,GAAqBA,OAAO,eAAe,CAAA;AACjD,EAAA,MAAM,UAAA,GAAaA,OAAO,OAAO,CAAA;AACjC,EAAA,MAAM,gBAAA,GAAmBA,OAAO,aAAa,CAAA;AAE7C,EAAAC,UAAU,MAAM;AACd,IAAA,kBAAA,CAAmB,OAAA,GAAU,eAAA;AAC7B,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AACrB,IAAA,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAAA,EAC7B,CAAA,EAAG,CAAC,eAAA,EAAiB,OAAA,EAAS,aAAa,CAAC,CAAA;AAE5C,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,eAAA,IAAmB,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACjD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,iBAAiB,CAAA;AAAA,IAC7D;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,kBAAA,CAAmB,OAAA,GAAU,MAAM,QAAQ,CAAA;AAAA,EAC7C,CAAA,EAAG,CAAC,KAAA,CAAM,QAAQ,CAAC,CAAA;AAEnB,EAAAA,UAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,IAC1B,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,iBAAA,GAAoBC,WAAAA,CAAY,CAAC,OAAA,KAA6B;AAClE,IAAA,MAAM,GAAA,GAAe;AAAA,MACnB,IAAI,YAAA,EAAa;AAAA,MACjB,IAAA,EAAM,MAAA;AAAA,MACN,OAAA;AAAA,MACA,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AACA,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAA,EAAS,KAAK,CAAA;AAC9C,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,iBAAA,GAAoBA,WAAAA,CAAY,CAAC,IAAA,KAAsB;AAC3D,IAAA,MAAM,MAAA,GAAkB;AAAA,MACtB,IAAI,YAAA,EAAa;AAAA,MACjB,IAAA,EAAM,KAAA;AAAA,MACN,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,KAAA,EAAO,IAAA,CAAK,KAAA,IAAS,EAAC;AAAA,MACtB,WAAA,EAAA,CAAc,IAAA,CAAK,KAAA,IAAS,IAAI,MAAA,GAAS,CAAA;AAAA,MACzC,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AACA,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,aAAA,EAAe,OAAA,EAAS,QAAQ,CAAA;AAAA,EACnD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,oBAAA,GAAuBA,WAAAA,CAAY,CAAC,MAAA,KAAoB;AAC5D,IAAA,QAAA,CAAS,EAAE,MAAM,kBAAA,EAAoB,OAAA,EAAS,EAAE,QAAA,EAAU,MAAA,IAAU,CAAA;AAAA,EACtE,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,SAAA,GAAYA,WAAAA;AAAA,IAChB,OAAO,IAAA,KAAe;AACpB,MAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,oBAAA,EAAqB;AACrB,MAAA,iBAAA,CAAkB,CAAA,SAAA,EAAY,IAAA,CAAK,IAAI,CAAA,CAAE,CAAA;AACzC,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,MAAM,CAAA;AAC9C,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,WAAW,CAAA;AACnD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,MAAM,CAAA;AAE7C,MAAA,IAAI;AACF,QAAA,MAAM,OAAO,MAAM,kBAAA,CAAsB,SAAS,IAAA,EAAM,SAAA,EAAW,WAAW,MAAM,CAAA;AACpF,QAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,QAAQ,CAAA;AAAA,MAClD,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,SAAS,YAAA,EAAc;AACjC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAC1B,UAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,KAAA,CAAM,SAAS,CAAA;AAAA,QACxD;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,SAAS,CAAA;AAAA,MACnD,CAAA,SAAE;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,MACjD;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,SAAA,EAAW,iBAAA,EAAmB,mBAAmB,oBAAoB;AAAA,GACjF;AAEA,EAAA,MAAM,QAAA,GAAWA,WAAAA;AAAA,IACf,OAAO,IAAA,KAAiB;AACtB,MAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,MAAA,IAAI,CAAC,OAAA,IAAW,CAAC,SAAA,EAAW;AAE5B,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,oBAAA,EAAqB;AACrB,MAAA,iBAAA,CAAkB,OAAO,CAAA;AACzB,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,MAAM,CAAA;AAC9C,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,WAAW,CAAA;AACnD,MAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,MAAM,CAAA;AAE7C,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,CAAA;AACxC,QAAA,MAAM,IAAA,GAAO,MAAM,WAAA,CAAe,OAAA,EAAS,SAAS,SAAA,EAAW,OAAA,EAAS,WAAW,MAAM,CAAA;AACzF,QAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,QAAQ,CAAA;AAAA,MAClD,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,SAAS,YAAA,EAAc;AACjC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAC1B,UAAA,QAAA,CAAS,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAS,KAAA,CAAM,SAAS,CAAA;AAAA,QACxD;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,SAAS,CAAA;AAAA,MACnD,CAAA,SAAE;AACA,QAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,MACjD;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAA,EAAS,SAAA,EAAW,MAAM,QAAA,EAAU,iBAAA,EAAmB,mBAAmB,oBAAoB;AAAA,GACjG;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AAAA,EAC5B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,WAAA,GAAcA,WAAAA,CAAY,CAAC,OAAA,KAAuB;AACtD,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,SAAS,CAAA;AAAA,EACrD,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,SAAA,GAAYA,WAAAA,CAAY,CAAC,KAAA,KAAmB;AAChD,IAAA,QAAA,CAAS,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,OAAO,CAAA;AAAA,EACjD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,oBAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;ACtNO,SAAS,QAAQ,IAAA,EAAqC;AAC3D,EAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAW,aAAA,EAAe,SAAQ,GAAI,IAAA;AACvD,EAAA,MAAM,QAAA,GAAWF,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,gBAAA,GAAmBA,OAAO,aAAa,CAAA;AAC7C,EAAA,MAAM,UAAA,GAAaA,OAAO,OAAO,CAAA;AAEjC,EAAAC,UAAU,MAAM;AACd,IAAA,gBAAA,CAAiB,OAAA,GAAU,aAAA;AAC3B,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAAA,EACvB,CAAA,EAAG,CAAC,aAAA,EAAe,OAAO,CAAC,CAAA;AAE3B,EAAAA,UAAU,MAAM;AACd,IAAA,OAAO,MAAM,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,EACvC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAWC,WAAAA;AAAA,IACf,OAAO,IAAA,KAA4C;AACjD,MAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AACvB,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AACxB,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,QAAA,CAAS,OAAA,GAAU,UAAA;AAEnB,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,QAAA,CAAS,OAAA,EAAS,IAAA,EAAM,SAAA,EAAW,WAAW,MAAM,CAAA;AAAA,MACnE,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,KAAA,GAAQ,GAAA;AACd,QAAA,IAAI,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc,OAAO,IAAA;AACxC,QAAA,IAAI,iBAAiB,gBAAA,EAAkB;AACrC,UAAA,gBAAA,CAAiB,OAAA,IAAU;AAAA,QAC7B,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAAA,QAC5B;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAS,SAAS;AAAA,GACrB;AAEA,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB;AC7BO,SAAS,UAAA,CAAW,IAAA,GAA0B,EAAC,EAAqB;AACzE,EAAA,MAAM,EAAE,UAAA,GAAa,2BAAA,EAA6B,QAAA,EAAS,GAAI,IAAA;AAC/D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIC,SAA4B,IAAI,CAAA;AAC9D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIA,SAAS,CAAC,CAAA;AAChD,EAAA,MAAM,UAAA,GAAaH,OAAO,KAAK,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAcA,OAAO,QAAQ,CAAA;AAEnC,EAAAC,UAAU,MAAM;AACd,IAAA,WAAA,CAAY,OAAA,GAAU,QAAA;AAAA,EACxB,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAAA,UAAU,MAAM;AACd,IAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,IAAA,UAAA,CAAW,OAAO,CAAA;AAClB,IAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,EAC7D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,WAAA,CAAY,MAAM;AACxC,MAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AACvB,UAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,UAAA,WAAA,CAAY,OAAA,IAAU;AAAA,QACxB;AACA,QAAA,UAAA,CAAW,IAAI,CAAA;AACf,QAAA,cAAA,CAAe,CAAC,CAAA;AAChB,QAAA;AAAA,MACF;AACA,MAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAC/C,GAAG,IAAK,CAAA;AACR,IAAA,OAAO,MAAM,MAAA,CAAO,aAAA,CAAc,QAAQ,CAAA;AAAA,EAC5C,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACnC,IAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAoB;AACrC,MAAA,IAAI,CAAA,CAAE,GAAA,IAAO,CAAA,CAAE,GAAA,KAAQ,aAAA,EAAe;AACtC,MAAA,MAAM,UAAU,WAAA,EAAY;AAC5B,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,IAC7D,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC5C,IAAA,OAAO,MAAM,MAAA,CAAO,mBAAA,CAAoB,SAAA,EAAW,SAAS,CAAA;AAAA,EAC9D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAWC,WAAAA;AAAA,IACf,CAAC,OAAe,MAAA,KAAmB;AACjC,MAAA,UAAA,CAAW,OAAA,GAAU,KAAA;AACrB,MAAA,MAAM,OAAA,GAAU,YAAA;AAAA,QACd;AAAA,UACE,KAAA;AAAA,UACA,MAAA;AAAA,UACA,SAAA,EAAW,WAAA,EAAY,EAAG,SAAA,IAAa,YAAA,EAAa;AAAA,UACpD,OAAA,EAAS,WAAA,EAAY,EAAG,OAAA,IAAW;AAAC,SACtC;AAAA,QACA;AAAA,OACF;AACA,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,UAAU,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,KAAQ,CAAC,CAAA;AAAA,IAC7D,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,CAAC,OAAA,KAAuB;AACtB,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,EAAE,OAAA,IAAW,UAAU,CAAA;AACpD,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,UAAA,CAAW,OAAO,CAAA;AAClB,QAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,MAC/C;AAAA,IACF,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,MAAM,OAAA,GAAU,aAAa,UAAU,CAAA;AACvC,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,cAAA,CAAe,OAAA,CAAQ,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,CAAA;AAAA,IAC/C;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAM;AAC9B,IAAA,YAAA,EAAa;AACb,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,cAAA,CAAe,CAAC,CAAA;AAChB,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAAA,EACvB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,OAAA,EAAS,WAAA,EAAa,QAAA,EAAU,UAAA,EAAY,OAAO,KAAA,EAAM;AACpE;;;ACrHA,IAAA,YAAA,GAAA;AAAA,EAEC,IAAA,EAAAE,WAAAA;AAAA,EA2BA,WAAA,EAAAC,kBAAAA;AAAA,EACA,aAAA,EAAAC,oBAAAA;AAAA,EACA,QAAA,EAAAC,eAAAA;AAAA,EAMA,cAAA,EAAAC,qBAAAA;AAAA,EAwBA,aAAA,EAAAC,oBAAAA;AAAA,EAIA,YAAA,EAAAC,mBAAAA;AAAA,EAIA,MAAA,EAAAC,aAAAA;AAAA,EAkCE,eAAA,EAAAC,sBAAAA;AAAA,EACA,gBAAA,EAAAC,uBAAAA;AAAA,EAQF,MAAA,EAAAC,aAAAA;AAAA,EAgBA,UAAA,EAAAC,iBAAAA;AAAA,EAMA,aAAA,EAAAC,oBAAAA;AAAA,EAMA,UAAA,EAAAC,iBAAAA;AAAA,EAeA,IAAA,EAAAC,WAAAA;AAAA,EAoBA,MAAA,EAAAC,aAAAA;AAAA,EAyvCA,SAAA,EAAAC,gBAAAA;AAAA,EAOA,UAAA,EAAAC,iBAAAA;AAAA,EASA,UAAA,EAAAC,iBAAAA;AAAA,EAOA,UAAA,EAAAC,iBAAAA;AAAA,EAOA,OAAA,EAAAC,cAAAA;AAAA,EAOA,IAAA,EAAAC,WAAAA;AAAA,EAiBA,UAAA,EAAAC,iBAAAA;AAAA,EAKA,YAAA,EAAAC,mBAAAA;AAAA,EAKA,MAAA,EAAAC,aAAAA;AAAA,EAUA,SAAA,EAAAC,gBAAAA;AAAA,EAKY,QAAA,EAAAC,eAAAA;AAAA,EAeZ,KAAA,EAAAC,YAAAA;AAAA,EAQA,QAAA,EAAAC,eAAAA;AAAA,EAsBA,UAAA,EAAAC,iBAAAA;AAAA,EAiBA,eAAA,EAAAC,sBAAAA;AAAA,EASA,SAAA,EAAAC,gBAAAA;AAAA,EAmBA,QAAA,EAAAC,eAAAA;AAAA,EAWA,YAAA,EAAAC,mBAAAA;AAAA,EAIA,aAAA,EAAAC,oBAAAA;AAAA,EAKA,YAAA,EAAAC,mBAAAA;AAAA,EAMA,cAAA,EAAAC,qBAAAA;AAAA,EAaA,kBAAA,EAAAC,yBAAAA;AAAA,EAWA,uBAAA,EAAAC,8BAAAA;AAAA,EAQA,WAAA,EAAAC,kBAAAA;AAAA,EAYA,WAAA,EAAAC,kBAAAA;AAAA,EAaY,QAAA,EAAAC,eAAAA;AAAA,EAsCZ,YAAA,EAAAC,mBAAAA;AAAA,EA2BA,QAAA,EAAAC,eAAAA;AAAA,EAOA,QAAA,EAAAC,eAAAA;AAAA,EAiBA,YAAA,EAAAC,mBAAAA;AAAA,EAWA,WAAA,EAAAC,kBAAAA;AAAA,EAiBA,WAAA,EAAAC,kBAAAA;AAAA,EAOA,aAAA,EAAAC,oBAAAA;AAAA,EACA,YAAA,EAAAC,mBAAAA;AAAA,EACA,YAAA,EAAAC,mBAAAA;AAAA,EACA,WAAA,EAAAC,kBAAAA;AAAA,EACA,cAAA,EAAAC,qBAAAA;AAAA,EACA,YAAA,EAAAC,mBAAAA;AAAA,EACA,YAAA,EAAAC,mBAAAA;AAAA,EACA,cAAA,EAAAC,qBAAAA;AAAA,EAGA,cAAA,EAAAC;AAAA,CAAA;AClyDM,SAAS,QAAA,CAAS,EAAE,SAAA,EAAW,QAAA,EAAU,cAAa,EAAkB;AAC7E,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,YAAA,EAAa;AACb,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,IACzB;AAAA,EACF,CAAA;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,QAAA,EACrB,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,SAAI,SAAA,EAAW,YAAA,CAAO,YAAA,EAAc,aAAA,EAAY,QAAO,QAAA,EAAA,WAAA,EAAE,CAAA;AAAA,oBAC1D,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,eAAe,QAAA,EAAA,gBAAA,EAAc,CAAA;AAAA,oBACpD,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,YAAA,EAAc,QAAA,EAAA;AAAA,MAAA,YAAA;AAAA,MACxB,SAAA;AAAA,MAAU;AAAA,KAAA,EACvB,CAAA;AAAA,oBACA,GAAA,CAAC,YAAO,IAAA,EAAK,QAAA,EAAS,WAAW,YAAA,CAAO,cAAA,EAAgB,OAAA,EAAS,WAAA,EAAa,QAAA,EAAA,2BAAA,EAE9E,CAAA;AAAA,oBACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,kBAAA,EACrB,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,uBAAA,EAAyB,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,sBAC1D,GAAA,CAAC,SAAI,QAAA,EAAA,4DAAA,EAAqD,CAAA;AAAA,sBAC1D,GAAA,CAAC,SAAI,QAAA,EAAA,oDAAA,EAA6C,CAAA;AAAA,sBAClD,GAAA,CAAC,SAAI,QAAA,EAAA,4DAAA,EAAqD;AAAA,KAAA,EAC5D;AAAA,GAAA,EACF,CAAA;AAEJ;AC3BO,SAAS,KAAK,EAAE,IAAA,EAAM,QAAA,EAAU,MAAA,EAAQ,SAAQ,EAAc;AACnE,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,YAAA,CAAO,IAAA;AAAA,IACP,MAAA,GAAS,aAAO,UAAA,GAAa,EAAA;AAAA,IAC7B,QAAA,GAAW,aAAO,YAAA,GAAe;AAAA,GACnC,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,uBACEC,IAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,QAAA;AAAA,MACA,OAAA,EAAS,MAAM,CAAC,QAAA,IAAY,QAAQ,IAAI,CAAA;AAAA,MAEvC,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,IAAA,mBAAOC,GAAAA,CAAC,MAAA,EAAA,EAAK,eAAY,MAAA,EAAQ,QAAA,EAAA,IAAA,CAAK,MAAK,CAAA,GAAU,IAAA;AAAA,wBAC3DA,GAAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,IAAA,CAAK,KAAA,EAAM;AAAA;AAAA;AAAA,GACpB;AAEJ;ACpBO,SAAS,OAAA,CAAQ,EAAE,KAAA,EAAO,QAAA,EAAU,SAAQ,EAAiB;AAClE,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,IAAA;AACzC,EAAA,uBACEA,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,OAAA,EACpB,QAAA,EAAA,KAAA,CAAM,IAAI,CAAC,CAAA,qBACVA,GAAAA,CAAC,IAAA,EAAA,EAAgB,MAAM,CAAA,EAAG,QAAA,EAAoB,WAAnC,CAAA,CAAE,EAAmD,CACjE,CAAA,EACH,CAAA;AAEJ;ACLA,IAAM,YAAA,GAAe;AAAA,EACnB,GAAA;AAAA,EAAK,QAAA;AAAA,EACL,GAAA;AAAA,EAAK,IAAA;AAAA,EACL,GAAA;AAAA,EAAK,KAAA;AAAA,EACL,GAAA;AAAA,EAAK,QAAA;AAAA,EAAU,KAAA;AAAA,EACf,IAAA;AAAA,EACA,GAAA;AAAA,EACA,MAAA;AAAA,EAAQ,KAAA;AAAA,EACR,GAAA;AAAA,EACA,IAAA;AAAA,EAAM,IAAA;AAAA,EAAM,IAAA;AAAA,EACZ,YAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,eAAe,CAAC,MAAA,EAAQ,UAAU,KAAA,EAAO,OAAA,EAAS,SAAS,mBAAmB,CAAA;AAEpF,IAAM,YAAA,GAAe;AAAA,EACnB,YAAA;AAAA,EACA,YAAA;AAAA;AAAA,EAEA,uBAAA,EAAyB,KAAA;AAAA,EACzB,kBAAA,EAAoB;AACtB,CAAA;AAmBA,SAAS,qBAAqB,IAAA,EAAsB;AAClD,EAAA,OAAO,KAEJ,OAAA,CAAQ,mCAAA,EAAqC,WAAW,CAAA,CAExD,OAAA,CAAQ,wBAAwB,WAAW,CAAA,CAC3C,QAAQ,kBAAA,EAAoB,WAAW,EAEvC,OAAA,CAAQ,gCAAA,EAAkC,WAAW,CAAA,CACrD,OAAA,CAAQ,oDAAoD,WAAW,CAAA;AAC5E;AAcA,SAAS,kBAAkB,IAAA,EAAsB;AAC/C,EAAA,OAAO,IAAA,CAAK,OAAA;AAAA,IACV,iDAAA;AAAA,IACA,CAAC,EAAA,EAAY,IAAA,EAAc,OAAA,EAAiB,KAAA,KAC1C,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,sBAAA,EAAwB,EAAE,CAAA,CAAE,IAAA,EAAK,GAAI;AAAA,GAChE;AACF;AAEO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,IAAI,CAAC,MAAM,OAAO,EAAA;AAElB,EAAA,MAAM,OAAA,GAAU,qBAAqB,IAAI,CAAA;AAIzC,EAAA,IAAI,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA,EAAG;AAC9B,IAAA,OAAO,SAAA,CAAU,QAAA,CAAS,iBAAA,CAAkB,OAAO,GAAG,YAAY,CAAA;AAAA,EACpE;AAGA,EAAA,MAAM,aAAa,OAAA,CAChB,KAAA,CAAM,QAAQ,CAAA,CACd,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,QAAQ,KAAA,EAAO,MAAM,CAAC,CAAA,CACzC,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAE7B,EAAA,MAAM,OAAO,UAAA,CAAW,MAAA,GAAS,CAAA,GAC7B,UAAA,CAAW,IAAI,CAAC,CAAA,KAAM,CAAA,GAAA,EAAM,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAC5C,UAAA,CAAW,CAAC,CAAA,IAAK,EAAA;AAErB,EAAA,OAAO,SAAA,CAAU,QAAA,CAAS,iBAAA,CAAkB,IAAI,GAAG,YAAY,CAAA;AACjE;ACzGA,IAAM,kBAAA,uBAAyB,GAAA,CAAI;AAAA,EACjC,gBAAA;AAAA,EAAkB,iBAAA;AAAA,EAAmB,cAAA;AAAA,EAAgB,gBAAA;AAAA,EACrD,iBAAA;AAAA,EAAmB,QAAA;AAAA,EAAU,gBAAA;AAAA,EAAkB;AACjD,CAAC,CAAA;AAED,IAAM,cAAA,GAAyC;AAAA,EAC7C,cAAA,EAAiB,yBAAA;AAAA,EACjB,eAAA,EAAiB,uBAAA;AAAA,EACjB,YAAA,EAAiB,yBAAA;AAAA,EACjB,cAAA,EAAiB,wBAAA;AAAA,EACjB,eAAA,EAAiB,sBAAA;AAAA,EACjB,MAAA,EAAiB,mBAAA;AAAA,EACjB,cAAA,EAAiB,mBAAA;AAAA,EACjB,YAAA,EAAiB;AACnB,CAAA;AAEA,IAAM,aAAA,GAAwC;AAAA,EAC5C,cAAA,EAAiB,eAAA;AAAA,EACjB,eAAA,EAAiB,cAAA;AAAA,EACjB,YAAA,EAAiB,cAAA;AAAA,EACjB,cAAA,EAAiB,aAAA;AAAA,EACjB,eAAA,EAAiB,gBAAA;AAAA,EACjB,MAAA,EAAiB,cAAA;AAAA,EACjB,cAAA,EAAiB,cAAA;AAAA,EACjB,YAAA,EAAiB;AACnB,CAAA;AAIA,IAAM,aAAA,GAAwC;AAAA,EAC5C,cAAA,EAAiB,iFAAA;AAAA,EACjB,eAAA,EAAiB,2DAAA;AAAA,EACjB,YAAA,EAAiB,0FAAA;AAAA,EACjB,cAAA,EAAiB,yDAAA;AAAA,EACjB,eAAA,EAAiB,4CAAA;AAAA,EACjB,MAAA,EAAiB,gDAAA;AAAA,EACjB,cAAA,EAAiB,iGAAA;AAAA,EACjB,YAAA,EAAiB;AACnB,CAAA;AAEA,SAAS,gBAAgB,KAAA,EAA4B;AAKnD,EAAA,OAAO,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,KAAM,kBAAA,CAAmB,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAC5E;AAOO,SAAS,aAAA,CAAc,EAAE,OAAA,EAAS,WAAA,EAAY,EAAuB;AAC1E,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,KAAS,KAAA;AAI/B,EAAA,MAAM,MAAA,GAAS,KAAA,IAAS,OAAA,CAAQ,OAAA,CAAQ,SAAS,MAAM,CAAA;AACvD,EAAA,MAAM,cAAc,KAAA,GAChB,CAAA,EAAG,YAAA,CAAO,MAAM,IAAI,MAAA,GAAS,YAAA,CAAO,UAAA,GAAa,YAAA,CAAO,SAAS,CAAA,CAAA,GACjE,CAAA,EAAG,aAAO,MAAM,CAAA,CAAA,EAAI,aAAO,UAAU,CAAA,CAAA;AAEzC,EAAA,MAAM,mBAAA,GAAsB,CAAC,CAAA,KAAwC;AACnE,IAAA,MAAM,MAAA,GAAU,CAAA,CAAE,MAAA,CAAuB,OAAA,CAAQ,GAAG,CAAA;AACpD,IAAA,IAAI,CAAC,QAAQ,IAAA,EAAM;AACnB,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAAA,EACpC,CAAA;AAEA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,IAAS,EAAC;AAChC,EAAA,MAAM,YAAA,GAAe,KAAA,IAAS,OAAA,CAAQ,WAAA,IAAe,gBAAgB,KAAK,CAAA;AAE1E,EAAA,uBACED,KAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,aAAA,EAAe,QAAA,EAAS,EACrD,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,WAAA,EACb,kCACCA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,WAAW,YAAA,CAAO,QAAA;AAAA,QAClB,yBAAyB,EAAE,MAAA,EAAQ,cAAA,CAAe,OAAA,CAAQ,OAAO,CAAA,EAAE;AAAA,QACnE,OAAA,EAAS;AAAA;AAAA,KACX,GAEA,QAAQ,OAAA,EAEZ,CAAA;AAAA,IACC,YAAA,mBACCA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,QAAA,EACpB,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACnB,MAAA,MAAM,OAAA,GAAU,aAAA,CAAc,IAAA,CAAK,EAAE,CAAA;AACrC,MAAA,MAAM,SAAA,GAAa,OAAA,IAAW,YAAA,CAAO,OAAO,CAAA,IAAM,EAAA;AAClD,MAAA,MAAM,OAAA,GAAU,aAAA,CAAc,IAAA,CAAK,EAAE,CAAA;AACrC,MAAA,uBACED,IAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAEC,IAAA,EAAK,QAAA;AAAA,UACL,WAAW,YAAA,CAAO,QAAA;AAAA,UAClB,OAAA,EAAS,MAAM,WAAA,CAAY,IAAI,CAAA;AAAA,UAE/B,QAAA,EAAA;AAAA,4BAAAC,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,YAAY,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAChD,QAAA,EAAA,OAAA,mBACCA,GAAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBACC,WAAW,YAAA,CAAO,WAAA;AAAA,gBAClB,OAAA,EAAQ,WAAA;AAAA,gBACR,aAAA,EAAY,MAAA;AAAA,gBACZ,uBAAA,EAAyB,EAAE,MAAA,EAAQ,OAAA;AAAQ;AAAA,aAC7C,mBAEAA,GAAAA,CAAC,MAAA,EAAA,EAAK,eAAY,MAAA,EAAQ,QAAA,EAAA,IAAA,CAAK,MAAK,CAAA,EAExC,CAAA;AAAA,4BACAA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAO,aAAA,EAAgB,eAAK,KAAA,EAAM,CAAA;AAAA,4BAClDA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,aAAc,QAAA,EAAA,cAAA,CAAe,IAAA,CAAK,EAAE,CAAA,IAAK,EAAA,EAAG;AAAA;AAAA,SAAA;AAAA,QAlB9D,IAAA,CAAK;AAAA,OAmBZ;AAAA,IAEJ,CAAC,CAAA,EACH,CAAA,GACE,SAAS,KAAA,CAAM,MAAA,GAAS,oBAC1BA,GAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,QAAA,EAAU,CAAC,OAAA,CAAQ,WAAA;AAAA,QACnB,OAAA,EAAS;AAAA;AAAA,KACX,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;ACjIO,SAAS,eAAA,GAAkB;AAChC,EAAA,uBACED,KAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,MAAA,EAAQ,WAAA,EAAU,QAAA,EAAS,YAAA,EAAW,qBAAA,EAC3D,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,YAAA,CAAO,SAAA,EAAW,CAAA;AAAA,oBACnCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,aAAO,SAAA,EAAW,CAAA;AAAA,oBACnCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,aAAO,SAAA,EAAW;AAAA,GAAA,EACrC,CAAA;AAEJ;ACSO,SAAS,QAAA,CAAS;AAAA,EACvB,UAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAAkB;AAChB,EAAA,MAAM,MAAA,GAAS9D,OAA8B,IAAI,CAAA;AAEjD,EAAAC,UAAU,MAAM;AACd,IAAA,MAAA,CAAO,OAAA,EAAS,cAAA,CAAe,EAAE,QAAA,EAAU,UAAU,CAAA;AAAA,EACvD,CAAA,EAAG,CAAC,QAAA,CAAS,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAE9B,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACE6D,IAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,IAAA,EACrB,QAAA,kBAAAA,GAAAA,CAAC,eAAA,EAAA,EAAgB,CAAA,EACnB,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAO,MACrB,QAAA,kBAAAA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,SAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA;AAAA,KACF,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,IAAA,EACpB,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,qBACbC,GAAAA,CAAC,aAAA,EAAA,EAAyB,OAAA,EAAS,CAAA,EAAG,WAAA,EAAA,EAAlB,CAAA,CAAE,EAA0C,CACjE,CAAA;AAAA,IACA,QAAA,mBAAWA,GAAAA,CAAC,eAAA,EAAA,EAAgB,CAAA,GAAK,IAAA;AAAA,IACjC,KAAA,mBAAQA,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAO,WAAA,EAAc,iBAAM,CAAA,GAAS,IAAA;AAAA,oBAC7DA,GAAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,MAAA,EAAQ;AAAA,GAAA,EACpB,CAAA;AAEJ;ACvDO,SAAS,UAAA,CAAW;AAAA,EACzB,SAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,uBACED,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,MAAA,EACrB,QAAA,EAAA;AAAA,oBAAAC,GAAAA,CAAC,SACC,QAAA,kBAAAA,GAAAA,CAAC,SAAI,SAAA,EAAW,YAAA,CAAO,WAAA,EAAc,QAAA,EAAA,SAAA,EAAU,CAAA,EAIjD,CAAA;AAAA,oBACAD,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,aAAA,EACpB,QAAA,EAAA;AAAA,MAAA,OAAA,mBACCC,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,WAAW,YAAA,CAAO,UAAA;AAAA,UAClB,OAAA,EAAS,OAAA;AAAA,UACT,YAAA,EAAW,oBAAA;AAAA,UACX,KAAA,EAAM,oBAAA;AAAA,UACP,QAAA,EAAA;AAAA;AAAA,OAED,GACE,IAAA;AAAA,sBACJA,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,WAAW,YAAA,CAAO,UAAA;AAAA,UAClB,OAAA,EAAS,OAAA;AAAA,UACT,YAAA,EAAW,YAAA;AAAA,UACX,KAAA,EAAM,OAAA;AAAA,UACP,QAAA,EAAA;AAAA;AAAA;AAED,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;ACzCO,SAAS,SAAA,CAAU,EAAE,QAAA,EAAU,WAAA,EAAa,QAAO,EAAmB;AAC3E,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI3D,SAAS,EAAE,CAAA;AACrC,EAAA,MAAM,QAAA,GAAWH,OAAyB,IAAI,CAAA;AAE9C,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,IAC1B;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,WAAW,QAAA,EAAU;AAC1B,IAAA,MAAA,CAAO,OAAO,CAAA;AACd,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,QAAA,CAAS,SAAS,KAAA,EAAM;AAAA,EAC1B,CAAA;AAEA,EAAA,uBACE4D,IAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,aAAO,KAAA,EACrB,QAAA,EAAA;AAAA,oBAAAC,GAAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,MAAA;AAAA,QACL,WAAW,YAAA,CAAO,QAAA;AAAA,QAClB,KAAA;AAAA,QACA,UAAU,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,CAAE,OAAO,KAAK,CAAA;AAAA,QACxC,SAAA,EAAW,CAAC,CAAA,KAAM;AAChB,UAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,OAAA,IAAW,CAAC,EAAE,QAAA,EAAU;AACpC,YAAA,CAAA,CAAE,cAAA,EAAe;AACjB,YAAA,MAAA,EAAO;AAAA,UACT;AAAA,QACF,CAAA;AAAA,QACA,QAAA;AAAA,QACA,aAAa,WAAA,IAAe,sBAAA;AAAA,QAC5B,YAAA,EAAW;AAAA;AAAA,KACb;AAAA,oBACAA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,WAAW,YAAA,CAAO,UAAA;AAAA,QAClB,OAAA,EAAS,MAAA;AAAA,QACT,QAAA,EAAU,QAAA,IAAY,KAAA,CAAM,IAAA,GAAO,MAAA,KAAW,CAAA;AAAA,QAC/C,QAAA,EAAA;AAAA;AAAA;AAED,GAAA,EACF,CAAA;AAEJ;AC3CO,SAAS,cAAA,CAAe,EAAE,QAAA,EAAU,OAAA,EAAS,YAAY,SAAA,EAAW,YAAA,EAAc,gBAAe,EAAwB;AAC9H,EAAA,MAAM,QAAA,GAAW,QAAA,KAAa,aAAA,GAAgB,YAAA,CAAO,eAAe,YAAA,CAAO,aAAA;AAC3E,EAAA,MAAM,aAAA,GAAgB,QAAA,KAAa,aAAA,GAAgB,YAAA,CAAO,kBAAkB,YAAA,CAAO,gBAAA;AACnF,EAAA,uBACED,KAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,SAAA,IAAa,+BACZA,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,WAAW,IAAI,aAAa,CAAA,CAAA;AAAA,QACjD,IAAA,EAAK,QAAA;AAAA,QACL,WAAA,EAAU,QAAA;AAAA,QAET,QAAA,EAAA;AAAA,UAAA,YAAA;AAAA,0BACDC,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,WAAW,YAAA,CAAO,YAAA;AAAA,cAClB,OAAA,EAAS,cAAA;AAAA,cACT,YAAA,EAAW,kBAAA;AAAA,cACZ,QAAA,EAAA;AAAA;AAAA;AAED;AAAA;AAAA,KACF,GACE,IAAA;AAAA,oBACJA,GAAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,cAAc,IAAI,QAAQ,CAAA,CAAA;AAAA,QAC/C,OAAA;AAAA,QACA,YAAA,EAAW,WAAA;AAAA,QACX,KAAA,EAAO,UAAA,GAAa,EAAE,UAAA,EAAY,YAAW,GAAI,MAAA;AAAA,QAClD,QAAA,EAAA;AAAA;AAAA;AAED,GAAA,EACF,CAAA;AAEJ;AC9BA,IAAM,kBAAA,GAAqB,iBAAA;AAC3B,IAAM,mBAAA,GAAsB,SAAA;AAC5B,IAAM,kBAAA,GAAqB,KAAA;AAC3B,IAAM,gBAAA,GAAmB,6DAAA;AAEzB,IAAM,QAAA,GACJ,8BAAA;AAGF,IAAM,qBAAA,GAAwB,wBAAA;AAE9B,IAAM,uBAAA,GAA0B,qBAAA;AAEhC,SAAS,kBAAkB,UAAA,EAA6B;AACtD,EAAA,IAAI,YAAY,OAAO,UAAA;AACvB,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAO,CAAA,EAAG,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,QAAA,CAAA;AAAA,EAClC;AACA,EAAA,OAAO,EAAA;AACT;AAEA,SAAS,YAAA,CAAa,MAA0B,IAAA,EAAkC;AAChF,EAAA,MAAM,QAAA,GAAW,IAAA,GACb,CAAA,cAAA,EAAiB,IAAI,CAAA,WAAA,EAAc,IAAA,GAAO,IAAA,GAAO,SAAS,CAAA,QAAA,CAAA,GAC1D,CAAA,kBAAA,EAAqB,IAAA,GAAO,IAAA,GAAO,SAAS,CAAA,QAAA,CAAA;AAChD,EAAA,OAAO,GAAG,QAAQ;;AAAA,EAAO,QAAQ,CAAA,CAAA;AACnC;AAEO,SAAS,WAAW,KAAA,EAAwB;AACjD,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,QAAA;AAAA,IACA,UAAA,GAAa,2BAAA;AAAA,IACb,cAAA;AAAA,IACA,SAAA,GAAY,kBAAA;AAAA,IACZ,UAAA,GAAa,mBAAA;AAAA,IACb,QAAA,GAAW,cAAA;AAAA,IACX,WAAA,GAAc,KAAA;AAAA,IACd,aAAA,GAAgB,IAAA;AAAA,IAChB,eAAA,GAAkB,gBAAA;AAAA,IAClB,OAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AAEJ,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI3D,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,SAAS,WAAW,CAAA;AAC5C,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,aAAA,GAAgBH,OAAO,WAAW,CAAA;AAExC,EAAAC,UAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAML,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,IAAA,MAAM,EAAA,GAAK,kBAAA;AACX,IAAA,IAAI,QAAA,CAAS,cAAA,CAAe,EAAE,CAAA,EAAG;AACjC,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC1C,IAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AACV,IAAA,IAAA,CAAK,GAAA,GAAM,YAAA;AACX,IAAA,IAAA,CAAK,IAAA,GACH,qHAAA;AACF,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAAA,EAChC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,IAAA,IAAQ,aAAA,CAAc,OAAA,EAAS;AAC/C,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AAAA,IAC1B,GAAG,GAAI,CAAA;AACP,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,CAAA,EAAG,CAAC,OAAA,EAAS,IAAI,CAAC,CAAA;AAElB,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA,EAAO;AAAA,MACL,UAAA,CAAW;AAAA,IACb,UAAA,EAAY,UAAA;AAAA,IACZ,QAAA,EAAU;AAAA,GACX,CAAA;AAED,EAAA,MAAM,EAAE,UAAA,EAAY,IAAA,EAAM,OAAA,EAAS,WAAA,KAAgB,OAAA,CAAQ;AAAA,IACzD,OAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAS,OAAA,IAAW,IAAA;AAAA,IACpB;AAAA,GACD,CAAA;AAED,EAAA,MAAM,iBAAA,GAAoBC,YAAY,MAAM;AAC1C,IAAA,iBAAA,EAAkB;AAClB,IAAA,eAAA,IAAkB;AAAA,EACpB,CAAA,EAAG,CAAC,iBAAA,EAAmB,eAAe,CAAC,CAAA;AAEvC,EAAA,MAAM,mBAAA,GAAsBA,WAAAA;AAAA,IAC1B,CAAC,OAAA,KAAuB;AACtB,MAAA,IAAI,CAAC,OAAA,EAAS;AACd,MAAA,UAAA,CAAW,OAAO,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,SAAS,UAAU;AAAA,GACtB;AAEA,EAAA,MAAM,UAAA,GAAaF,OAAyB,IAAI,CAAA;AAEhD,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,SAAA;AAAA,IACP,QAAA;AAAA,IACA,SAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,oBAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,KAAA,EAAO;AAAA,MACL,OAAA,CAAQ;AAAA,IACV,OAAA;AAAA,IACA,SAAA,EAAW,SAAS,SAAA,IAAa,IAAA;AAAA,IACjC,iBAAiB,OAAA,EAAS,OAAA;AAAA,IAC1B,eAAA,EAAiB,mBAAA;AAAA,IACjB,aAAA,EAAe,iBAAA;AAAA,IACf;AAAA,GACD,CAAA;AAED,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,OAAA,CAAQ;AAAA,IAC3B,OAAA;AAAA,IACA,SAAA,EAAW,SAAS,SAAA,IAAa,IAAA;AAAA,IACjC,aAAA,EAAe,iBAAA;AAAA,IACf;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,QAAQ,OAAO,EAAE,OAAO,KAAA,EAAM,CAAA,EAAI,EAAE,CAAA;AAE5D,EAAAC,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,IAAc,CAAC,IAAA,EAAM;AAC1B,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AACnC,IAAA,IAAI,gBAAgB,KAAA,EAAO;AAC3B,IAAA,eAAA,CAAgB,KAAA,GAAQ,IAAA;AACxB,IAAA,MAAM,WAAA,GACJ,kBACA,IAAA,EAAM,cAAA,IACN,aAAa,IAAA,EAAM,IAAA,EAAM,MAAM,IAAI,CAAA;AACrC,IAAA,iBAAA,CAAkB;AAAA,MAChB,OAAA,EAAS,WAAA;AAAA,MACT,KAAA,EAAO,IAAA,EAAM,SAAA,IAAa,EAAC;AAAA,MAC3B,SAAA,EAAW,SAAS,SAAA,IAAa,EAAA;AAAA,MACjC,SAAA,EAAW;AAAA,KACZ,CAAA;AACD,IAAA,OAAA,IAAU;AAAA,EACZ,CAAA,EAAG,CAAC,UAAA,EAAY,IAAA,EAAM,SAAA,CAAU,QAAA,CAAS,MAAA,EAAQ,cAAA,EAAgB,OAAA,EAAS,IAAA,EAAM,iBAAA,EAAmB,OAAA,EAAS,eAAe,CAAC,CAAA;AAE5H,EAAA,MAAM,eAAA,GAAkBC,WAAAA;AAAA,IACtB,OAAO,IAAA,KAAe;AACpB,MAAA,KAAA,EAAM;AACN,MAAA,oBAAA,EAAqB;AAErB,MAAA,IAAI,IAAA,CAAK,OAAO,qBAAA,EAAuB;AACrC,QAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAC5B,QAAA,UAAA,CAAW,SAAS,KAAA,EAAM;AAC1B,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,IAAA,CAAK,OAAO,uBAAA,EAAyB;AACvC,QAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAC5B,QAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,IAAA,EAAM,UAAU,CAAA;AACrD,QAAA,IAAI,UAAA,IAAc,OAAO,MAAA,KAAW,WAAA,EAAa;AAC/C,UAAA,MAAA,CAAO,QAAA,CAAS,OAAO,UAAU,CAAA;AAAA,QACnC;AACA,QAAA;AAAA,MACF;AAEA,MAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAC5B,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAI,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA,EAAM;AACX,QAAA,MAAM,WAAA,GAAc,KAAK,QAAA,EAAU,WAAA;AACnC,QAAA,IAAI,OAAO,WAAA,KAAgB,QAAA,IAAY,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACnF,UAAA,MAAA,CAAO,QAAA,CAAS,OAAO,WAAW,CAAA;AAClC,UAAA;AAAA,QACF;AACA,QAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,MACxB,CAAA,SAAE;AACA,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAO,oBAAA,EAAsB,iBAAA,EAAmB,UAAU,SAAA,EAAW,iBAAA,EAAmB,MAAM,UAAU;AAAA,GAC3G;AAEA,EAAA,MAAM,qBAAA,GAAwBA,WAAAA;AAAA,IAC5B,CAAC,CAAA,KAA2C;AAC1C,MAAA,MAAM,IAAA,GAAO,CAAA,CAAE,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAA;AAC/B,MAAA,CAAA,CAAE,OAAO,KAAA,GAAQ,EAAA;AACjB,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,KAAA,EAAM;AACN,QAAA,KAAK,UAAU,IAAI,CAAA;AAAA,MACrB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,OAAO,SAAS;AAAA,GACnB;AAEA,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,CAAC,IAAA,KAAiB;AAChB,MAAA,KAAA,EAAM;AACN,MAAA,KAAK,SAAS,IAAI,CAAA;AAAA,IACpB,CAAA;AAAA,IACA,CAAC,OAAO,QAAQ;AAAA,GAClB;AAEA,EAAA,MAAM,yBAAA,GAA4BA,YAAY,MAAM;AAClD,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,cAAcA,WAAAA,CAAY,MAAM,QAAQ,KAAK,CAAA,EAAG,EAAE,CAAA;AAExD,EAAA,MAAM,WAAA,GAAcA,YAAY,MAAM;AACpC,IAAA,SAAA,EAAU;AACV,IAAA,eAAA,CAAgB,KAAA,GAAQ,KAAA;AACxB,IAAA,UAAA,CAAW,EAAE,CAAA;AAAA,EACf,CAAA,EAAG,CAAC,SAAA,EAAW,UAAA,EAAY,eAAe,CAAC,CAAA;AAE3C,EAAA,MAAM,gBAAA,GAAmBA,YAAY,MAAM;AACzC,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,IACzB;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,MAAM,SAAA,GAAY;AAAA,IAChB,CAAC,aAAuB,GAAG;AAAA,GAC7B;AAEA,EAAA,uBACE2D,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAO,IAAA,EAAM,OAAO,SAAA,EACjC,QAAA,EAAA;AAAA,IAAA,CAAC,uBACAC,GAAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,QAAA;AAAA,QACA,OAAA,EAAS,yBAAA;AAAA,QACT,UAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA,EAAc,eAAA;AAAA,QACd,cAAA,EAAgB,MAAM,YAAA,CAAa,KAAK;AAAA;AAAA,KAC1C,GACE,IAAA;AAAA,IACH,uBACCD,IAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,CAAA,EAAG,YAAA,CAAO,MAAM,CAAA,CAAA,EAAI,aAAa,aAAA,GAAgB,YAAA,CAAO,YAAA,GAAe,YAAA,CAAO,aAAa,CAAA,CAAA;AAAA,QAEtG,QAAA,EAAA;AAAA,0BAAAC,GAAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,SAAA;AAAA,cACA,WAAA;AAAA,cACA,eAAe,aAAA,IAAiB,UAAA;AAAA,cAChC,OAAA,EAAS,WAAA;AAAA,cACT,OAAA,EAAS,aAAa,WAAA,GAAc;AAAA;AAAA,WACtC;AAAA,0BACAA,GAAAA;AAAA,YAAC,QAAA;AAAA,YAAA;AAAA,cACC,UAAA;AAAA,cACA,OAAA,EAAS,WAAA;AAAA,cACT,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,SAAA;AAAA,cACA,QAAA;AAAA,cACA,OAAO,SAAA,CAAU,KAAA;AAAA,cACjB,WAAA,EAAa,eAAA;AAAA,cACb,YAAA,EAAc;AAAA;AAAA,WAChB;AAAA,0BACAA,GAAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,UAAA;AAAA,cACL,IAAA,EAAK,MAAA;AAAA,cACL,MAAA,EAAO,eAAA;AAAA,cACP,WAAW,YAAA,CAAO,eAAA;AAAA,cAClB,QAAA,EAAU,qBAAA;AAAA,cACV,aAAA,EAAW,IAAA;AAAA,cACX,QAAA,EAAU;AAAA;AAAA,WACZ;AAAA,UACC,6BACCA,GAAAA;AAAA,YAAC,SAAA;AAAA,YAAA;AAAA,cACC,UAAU,SAAA,CAAU,QAAA;AAAA,cACpB,MAAA,EAAQ,UAAA;AAAA,cACR,WAAA,EAAY;AAAA;AAAA,WACd,GACE;AAAA;AAAA;AAAA,KACN,GACE;AAAA,GAAA,EACN,CAAA;AAEJ","file":"index.mjs","sourcesContent":["import type { Message, WACSession } from \"../types\";\n\nexport const SESSION_KEY = \"wac_session\";\nexport const DEFAULT_SESSION_TTL_SECONDS = 1800;\nexport const MAX_HISTORY = 100;\n\n// Fallback localStorage keys checked in order when wac_session is empty.\n// Host apps that already store a JWT under one of these keys get auth for free.\nconst FALLBACK_TOKEN_KEYS = [\"token\", \"access_token\", \"auth_token\", \"jwt\"];\n\nconst isBrowser = (): boolean =>\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\";\n\nfunction base64UrlDecode(input: string): string {\n const base64 = input.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = base64 + \"===\".slice((base64.length + 3) % 4);\n return atob(padded);\n}\n\nfunction decodeJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3 || !parts[1]) return null;\n return JSON.parse(base64UrlDecode(parts[1])) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction jwtExpiresAt(token: string): number | null {\n const payload = decodeJwt(token);\n const exp = payload?.[\"exp\"];\n if (typeof exp !== \"number\") return null;\n return exp * 1000;\n}\n\nfunction jwtUserId(token: string): string {\n const payload = decodeJwt(token);\n if (!payload) return \"\";\n const id = payload[\"id\"] ?? payload[\"sub\"] ?? payload[\"user_id\"];\n return id != null ? String(id) : \"\";\n}\n\nfunction readFallbackToken(): { token: string; key: string } | null {\n if (!isBrowser()) return null;\n for (const key of FALLBACK_TOKEN_KEYS) {\n const value = window.localStorage.getItem(key);\n if (value && value.length > 20) return { token: value, key };\n }\n return null;\n}\n\nconst generateId = (prefix: string): string => {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return `${prefix}_${crypto.randomUUID()}`;\n }\n return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n};\n\nexport function newSessionId(): string {\n return generateId(\"ses\");\n}\n\nexport function newMessageId(): string {\n return generateId(\"msg\");\n}\n\nexport function readSession(): WACSession | null {\n if (!isBrowser()) return null;\n try {\n const raw = window.localStorage.getItem(SESSION_KEY);\n if (raw) {\n const session = JSON.parse(raw) as WACSession;\n const valid =\n session &&\n typeof session.token === \"string\" &&\n session.token.length > 0 &&\n typeof session.expiresAt === \"number\" &&\n Date.now() < session.expiresAt;\n if (valid) {\n const fallback = readFallbackToken();\n // If this session was adopted from a fallback key but that key is now gone,\n // the host app has logged out — drop the cached session.\n if (!fallback && session.bootSource === \"fallback\") {\n clearSession();\n return null;\n }\n // If the host app's raw token has rotated (re-login), prefer that one.\n if (fallback && fallback.token !== session.token) {\n return adoptFallbackToken(fallback.token, session);\n }\n return session;\n }\n // Stale wac_session — drop it and try fallback below.\n clearSession();\n }\n } catch {\n clearSession();\n }\n\n const fallback = readFallbackToken();\n if (!fallback) return null;\n return adoptFallbackToken(fallback.token, null);\n}\n\nfunction adoptFallbackToken(token: string, prior: WACSession | null): WACSession | null {\n const jwtExp = jwtExpiresAt(token);\n const now = Date.now();\n const expiresAt = jwtExp ?? now + DEFAULT_SESSION_TTL_SECONDS * 1000;\n if (now >= expiresAt) return null;\n const session: WACSession = {\n token,\n userId: jwtUserId(token) || prior?.userId || \"\",\n sessionId: prior?.sessionId ?? newSessionId(),\n expiresAt,\n lastActive: now,\n history: prior?.history ?? [],\n bootSource: \"fallback\",\n };\n if (isBrowser()) {\n try {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify(session));\n } catch {\n /* ignore quota */\n }\n }\n return session;\n}\n\nexport function writeSession(\n data: Partial<WACSession>,\n ttlSeconds: number = DEFAULT_SESSION_TTL_SECONDS,\n): WACSession | null {\n if (!isBrowser()) return null;\n const now = Date.now();\n const existing = readSession();\n const base: WACSession =\n existing ??\n {\n token: \"\",\n userId: \"\",\n sessionId: newSessionId(),\n expiresAt: now + ttlSeconds * 1000,\n lastActive: now,\n history: [],\n };\n\n const merged: WACSession = {\n ...base,\n ...data,\n sessionId: data.sessionId ?? base.sessionId ?? newSessionId(),\n lastActive: now,\n expiresAt: now + ttlSeconds * 1000,\n history: trimHistory(data.history ?? base.history),\n };\n\n try {\n window.localStorage.setItem(SESSION_KEY, JSON.stringify(merged));\n return merged;\n } catch {\n return null;\n }\n}\n\nexport function clearSession(): void {\n if (!isBrowser()) return;\n try {\n window.localStorage.removeItem(SESSION_KEY);\n } catch {\n /* ignore */\n }\n}\n\nexport function trimHistory(history: Message[] | undefined): Message[] {\n if (!Array.isArray(history)) return [];\n if (history.length <= MAX_HISTORY) return history;\n return history.slice(history.length - MAX_HISTORY);\n}\n\nexport function touchSession(\n ttlSeconds: number = DEFAULT_SESSION_TTL_SECONDS,\n): WACSession | null {\n const current = readSession();\n if (!current) return null;\n return writeSession({}, ttlSeconds);\n}\n","import type { BotResponse, Chip, Message, WACUser } from \"../types\";\nimport { clearSession, newMessageId, readSession } from \"../utils/session\";\n\nconst DEFAULT_TIMEOUT_MS = 20000;\nconst DEFAULT_RETRIES = 2;\nconst RETRY_BASE_DELAY_MS = 400;\n\nexport class ApiError extends Error {\n status: number;\n requestId: string;\n constructor(message: string, status: number, requestId: string) {\n super(message);\n this.name = \"ApiError\";\n this.status = status;\n this.requestId = requestId;\n }\n}\n\nexport class AuthExpiredError extends ApiError {\n constructor(requestId: string) {\n super(\"Session expired or invalid\", 401, requestId);\n this.name = \"AuthExpiredError\";\n }\n}\n\ninterface RequestOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n body?: unknown;\n signal?: AbortSignal;\n timeoutMs?: number;\n retries?: number;\n auth?: boolean;\n}\n\nconst generateRequestId = (): string => {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n};\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\nconst joinUrl = (base: string, path: string): string => {\n const trimmedBase = base.replace(/\\/+$/, \"\");\n const trimmedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${trimmedBase}${trimmedPath}`;\n};\n\nasync function request<T>(\n apiBase: string,\n path: string,\n opts: RequestOptions = {},\n): Promise<T> {\n const {\n method = \"GET\",\n body,\n signal,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n retries = DEFAULT_RETRIES,\n auth = true,\n } = opts;\n\n const url = /^https?:\\/\\//i.test(path) ? path : joinUrl(apiBase, path);\n const requestId = generateRequestId();\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n const onUserAbort = () => controller.abort();\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeoutId);\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n signal.addEventListener(\"abort\", onUserAbort, { once: true });\n }\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Request-Id\": requestId,\n };\n if (auth) {\n const session = readSession();\n if (session?.token) headers[\"Authorization\"] = `Bearer ${session.token}`;\n }\n\n const res = await fetch(url, {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n credentials: \"same-origin\",\n });\n\n if (res.status === 401 || res.status === 403) {\n clearSession();\n throw new AuthExpiredError(requestId);\n }\n\n if (res.status >= 500 && attempt < retries) {\n lastError = new ApiError(`Server error ${res.status}`, res.status, requestId);\n throw lastError;\n }\n\n if (!res.ok) {\n let detail = res.statusText;\n try {\n const errBody = (await res.json()) as { message?: string; detail?: string };\n detail = errBody.message ?? errBody.detail ?? detail;\n } catch {\n /* ignore body parse */\n }\n throw new ApiError(detail || `HTTP ${res.status}`, res.status, requestId);\n }\n\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n } catch (err) {\n const error = err as Error;\n const isAbort = error.name === \"AbortError\";\n const isAuth = error instanceof AuthExpiredError;\n const isRetryable =\n !isAuth &&\n !signal?.aborted &&\n (isAbort || error instanceof TypeError || (error as ApiError).status >= 500);\n\n if (isAuth || !isRetryable || attempt === retries) {\n throw error;\n }\n lastError = error;\n await sleep(RETRY_BASE_DELAY_MS * Math.pow(2, attempt));\n } finally {\n clearTimeout(timeoutId);\n if (signal) signal.removeEventListener(\"abort\", onUserAbort);\n }\n }\n\n throw lastError ?? new Error(\"Request failed\");\n}\n\nexport async function checkAuth(\n apiBase: string,\n authCheck: string,\n signal?: AbortSignal,\n): Promise<WACUser> {\n return request<WACUser>(apiBase, authCheck, {\n method: \"GET\",\n signal,\n retries: 1,\n });\n}\n\nexport async function sendChip(\n apiBase: string,\n chip: Chip,\n sessionId: string,\n signal?: AbortSignal,\n): Promise<BotResponse> {\n const path = chip.apiPath ?? `/chip/${chip.id}`;\n return request<BotResponse>(apiBase, path, {\n method: \"POST\",\n body: { chipId: chip.id, sessionId },\n signal,\n });\n}\n\nexport async function sendMessage(\n apiBase: string,\n message: string,\n sessionId: string,\n context: Message[],\n signal?: AbortSignal,\n): Promise<BotResponse> {\n return request<BotResponse>(apiBase, \"/message\", {\n method: \"POST\",\n body: { message, sessionId, context },\n signal,\n });\n}\n\nexport async function uploadPortfolioCsv(\n apiBase: string,\n file: File,\n sessionId: string,\n signal?: AbortSignal,\n): Promise<BotResponse> {\n const url = joinUrl(apiBase, \"/upload-portfolio-csv\");\n const requestId = generateRequestId();\n const session = readSession();\n const form = new FormData();\n form.append(\"sessionId\", sessionId);\n form.append(\"file\", file, file.name);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 60000);\n if (signal) {\n if (signal.aborted) {\n clearTimeout(timeoutId);\n throw new DOMException(\"Aborted\", \"AbortError\");\n }\n signal.addEventListener(\"abort\", () => controller.abort(), { once: true });\n }\n\n try {\n const headers: Record<string, string> = { \"X-Request-Id\": requestId };\n if (session?.token) headers[\"Authorization\"] = `Bearer ${session.token}`;\n\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: form,\n signal: controller.signal,\n credentials: \"same-origin\",\n });\n\n if (res.status === 401 || res.status === 403) {\n clearSession();\n throw new AuthExpiredError(requestId);\n }\n if (!res.ok) {\n let detail = res.statusText;\n try {\n const errBody = (await res.json()) as { message?: string; detail?: string };\n detail = errBody.message ?? errBody.detail ?? detail;\n } catch {\n /* ignore */\n }\n throw new ApiError(detail || `HTTP ${res.status}`, res.status, requestId);\n }\n return (await res.json()) as BotResponse;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nexport async function logout(apiBase: string, signal?: AbortSignal): Promise<void> {\n try {\n await request<void>(apiBase, \"/auth/logout\", {\n method: \"POST\",\n signal,\n retries: 0,\n });\n } finally {\n clearSession();\n }\n}\n\nexport { generateRequestId };\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { AuthExpiredError, checkAuth } from \"../api/chatApi\";\nimport type { WACUser } from \"../types\";\nimport { clearSession, readSession } from \"../utils/session\";\n\ninterface UseAuthOptions {\n apiBase: string;\n authCheck: string;\n enabled?: boolean;\n onError?: (err: Error) => void;\n}\n\ninterface UseAuthReturn {\n isLoggedIn: boolean;\n user: WACUser | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n}\n\nexport function useAuth(opts: UseAuthOptions): UseAuthReturn {\n const { apiBase, authCheck, enabled = true, onError } = opts;\n const [user, setUser] = useState<WACUser | null>(null);\n const [loading, setLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n const [tick, setTick] = useState(0);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n\n const session = readSession();\n if (!session?.token) {\n setUser(null);\n setLoading(false);\n return;\n }\n\n const controller = new AbortController();\n setLoading(true);\n setError(null);\n\n checkAuth(apiBase, authCheck, controller.signal)\n .then((u) => {\n setUser(u);\n setError(null);\n })\n .catch((err: Error) => {\n if (err.name === \"AbortError\") return;\n if (err instanceof AuthExpiredError) {\n clearSession();\n setUser(null);\n } else {\n setError(err);\n onErrorRef.current?.(err);\n }\n })\n .finally(() => {\n if (!controller.signal.aborted) setLoading(false);\n });\n\n return () => controller.abort();\n }, [apiBase, authCheck, enabled, tick]);\n\n const refresh = useCallback(() => setTick((t) => t + 1), []);\n\n return {\n isLoggedIn: user !== null,\n user,\n loading,\n error,\n refresh,\n };\n}\n","import { useCallback, useEffect, useReducer, useRef } from \"react\";\nimport {\n AuthExpiredError,\n sendMessage as apiSendMessage,\n uploadPortfolioCsv as apiUploadPortfolioCsv,\n} from \"../api/chatApi\";\nimport type { BotResponse, ChatState, Message } from \"../types\";\nimport { MAX_HISTORY, newMessageId } from \"../utils/session\";\n\ntype ChatAction =\n | { type: \"ADD_MESSAGE\"; payload: Message }\n | { type: \"SET_TYPING\"; payload: boolean }\n | { type: \"SET_STATUS\"; payload: ChatState[\"status\"] }\n | { type: \"SET_ERROR\"; payload: string | null }\n | { type: \"DEACTIVATE_CHIPS\"; payload: { exceptId?: string } }\n | { type: \"LOAD_HISTORY\"; payload: Message[] }\n | { type: \"CLEAR\" };\n\nconst initialState: ChatState = {\n messages: [],\n isTyping: false,\n status: \"idle\",\n error: null,\n};\n\nfunction reducer(state: ChatState, action: ChatAction): ChatState {\n switch (action.type) {\n case \"ADD_MESSAGE\": {\n const next = [...state.messages, action.payload];\n const trimmed = next.length > MAX_HISTORY ? next.slice(next.length - MAX_HISTORY) : next;\n return { ...state, messages: trimmed };\n }\n case \"SET_TYPING\":\n return { ...state, isTyping: action.payload };\n case \"SET_STATUS\":\n return { ...state, status: action.payload };\n case \"SET_ERROR\":\n return { ...state, error: action.payload };\n case \"DEACTIVATE_CHIPS\":\n return {\n ...state,\n messages: state.messages.map((m) =>\n m.id === action.payload.exceptId ? m : { ...m, chipsActive: false },\n ),\n };\n case \"LOAD_HISTORY\":\n return { ...state, messages: action.payload };\n case \"CLEAR\":\n return initialState;\n default:\n return state;\n }\n}\n\ninterface UseChatOptions {\n apiBase: string;\n sessionId: string | null;\n initialMessages?: Message[];\n onHistoryChange?: (history: Message[]) => void;\n onError?: (err: Error) => void;\n onAuthExpired?: () => void;\n}\n\ninterface UseChatReturn {\n state: ChatState;\n sendText: (text: string) => Promise<void>;\n uploadCsv: (file: File) => Promise<void>;\n appendBotResponse: (resp: BotResponse) => void;\n appendUserMessage: (content: string) => Message;\n deactivatePriorChips: (keepId?: string) => void;\n setTyping: (value: boolean) => void;\n clear: () => void;\n loadHistory: (history: Message[]) => void;\n}\n\nexport function useChat(opts: UseChatOptions): UseChatReturn {\n const { apiBase, sessionId, initialMessages, onHistoryChange, onError, onAuthExpired } = opts;\n const [state, dispatch] = useReducer(reducer, initialState);\n const abortRef = useRef<AbortController | null>(null);\n const onHistoryChangeRef = useRef(onHistoryChange);\n const onErrorRef = useRef(onError);\n const onAuthExpiredRef = useRef(onAuthExpired);\n\n useEffect(() => {\n onHistoryChangeRef.current = onHistoryChange;\n onErrorRef.current = onError;\n onAuthExpiredRef.current = onAuthExpired;\n }, [onHistoryChange, onError, onAuthExpired]);\n\n useEffect(() => {\n if (initialMessages && initialMessages.length > 0) {\n dispatch({ type: \"LOAD_HISTORY\", payload: initialMessages });\n }\n }, []);\n\n useEffect(() => {\n onHistoryChangeRef.current?.(state.messages);\n }, [state.messages]);\n\n useEffect(() => {\n return () => {\n abortRef.current?.abort();\n };\n }, []);\n\n const appendUserMessage = useCallback((content: string): Message => {\n const msg: Message = {\n id: newMessageId(),\n role: \"user\",\n content,\n timestamp: Date.now(),\n };\n dispatch({ type: \"ADD_MESSAGE\", payload: msg });\n return msg;\n }, []);\n\n const appendBotResponse = useCallback((resp: BotResponse) => {\n const botMsg: Message = {\n id: newMessageId(),\n role: \"bot\",\n content: resp.message,\n chips: resp.chips ?? [],\n chipsActive: (resp.chips ?? []).length > 0,\n timestamp: Date.now(),\n };\n dispatch({ type: \"ADD_MESSAGE\", payload: botMsg });\n }, []);\n\n const deactivatePriorChips = useCallback((keepId?: string) => {\n dispatch({ type: \"DEACTIVATE_CHIPS\", payload: { exceptId: keepId } });\n }, []);\n\n const uploadCsv = useCallback(\n async (file: File) => {\n if (!sessionId) return;\n\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n deactivatePriorChips();\n appendUserMessage(`Uploaded ${file.name}`);\n dispatch({ type: \"SET_TYPING\", payload: true });\n dispatch({ type: \"SET_STATUS\", payload: \"sending\" });\n dispatch({ type: \"SET_ERROR\", payload: null });\n\n try {\n const resp = await apiUploadPortfolioCsv(apiBase, file, sessionId, controller.signal);\n appendBotResponse(resp);\n dispatch({ type: \"SET_STATUS\", payload: \"idle\" });\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n dispatch({ type: \"SET_ERROR\", payload: error.message });\n }\n dispatch({ type: \"SET_STATUS\", payload: \"error\" });\n } finally {\n dispatch({ type: \"SET_TYPING\", payload: false });\n }\n },\n [apiBase, sessionId, appendUserMessage, appendBotResponse, deactivatePriorChips],\n );\n\n const sendText = useCallback(\n async (text: string) => {\n const trimmed = text.trim();\n if (!trimmed || !sessionId) return;\n\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n deactivatePriorChips();\n appendUserMessage(trimmed);\n dispatch({ type: \"SET_TYPING\", payload: true });\n dispatch({ type: \"SET_STATUS\", payload: \"sending\" });\n dispatch({ type: \"SET_ERROR\", payload: null });\n\n try {\n const context = state.messages.slice(-20);\n const resp = await apiSendMessage(apiBase, trimmed, sessionId, context, controller.signal);\n appendBotResponse(resp);\n dispatch({ type: \"SET_STATUS\", payload: \"idle\" });\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n dispatch({ type: \"SET_ERROR\", payload: error.message });\n }\n dispatch({ type: \"SET_STATUS\", payload: \"error\" });\n } finally {\n dispatch({ type: \"SET_TYPING\", payload: false });\n }\n },\n [apiBase, sessionId, state.messages, appendUserMessage, appendBotResponse, deactivatePriorChips],\n );\n\n const clear = useCallback(() => {\n abortRef.current?.abort();\n dispatch({ type: \"CLEAR\" });\n }, []);\n\n const loadHistory = useCallback((history: Message[]) => {\n dispatch({ type: \"LOAD_HISTORY\", payload: history });\n }, []);\n\n /** Toggle the typing dots externally — used by WealthChat around chip clicks. */\n const setTyping = useCallback((value: boolean) => {\n dispatch({ type: \"SET_TYPING\", payload: value });\n }, []);\n\n return {\n state,\n sendText,\n uploadCsv,\n appendBotResponse,\n appendUserMessage,\n deactivatePriorChips,\n clear,\n loadHistory,\n setTyping,\n };\n}\n","import { useCallback, useEffect, useRef } from \"react\";\nimport { AuthExpiredError, sendChip } from \"../api/chatApi\";\nimport type { BotResponse, Chip } from \"../types\";\n\ninterface UseChipOptions {\n apiBase: string;\n sessionId: string | null;\n onAuthExpired?: () => void;\n onError?: (err: Error) => void;\n}\n\ninterface UseChipReturn {\n callChip: (chip: Chip) => Promise<BotResponse | null>;\n}\n\nexport function useChip(opts: UseChipOptions): UseChipReturn {\n const { apiBase, sessionId, onAuthExpired, onError } = opts;\n const abortRef = useRef<AbortController | null>(null);\n const onAuthExpiredRef = useRef(onAuthExpired);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onAuthExpiredRef.current = onAuthExpired;\n onErrorRef.current = onError;\n }, [onAuthExpired, onError]);\n\n useEffect(() => {\n return () => abortRef.current?.abort();\n }, []);\n\n const callChip = useCallback(\n async (chip: Chip): Promise<BotResponse | null> => {\n if (!sessionId) return null;\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n return await sendChip(apiBase, chip, sessionId, controller.signal);\n } catch (err) {\n const error = err as Error;\n if (error.name === \"AbortError\") return null;\n if (error instanceof AuthExpiredError) {\n onAuthExpiredRef.current?.();\n } else {\n onErrorRef.current?.(error);\n }\n return null;\n }\n },\n [apiBase, sessionId],\n );\n\n return { callChip };\n}\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Message, WACSession } from \"../types\";\nimport {\n DEFAULT_SESSION_TTL_SECONDS,\n clearSession,\n newSessionId,\n readSession,\n touchSession,\n writeSession,\n} from \"../utils/session\";\n\ninterface UseSessionOptions {\n ttlSeconds?: number;\n onExpire?: () => void;\n}\n\ninterface UseSessionReturn {\n session: WACSession | null;\n remainingMs: number;\n setToken: (token: string, userId: string) => void;\n setHistory: (history: Message[]) => void;\n touch: () => void;\n clear: () => void;\n}\n\nexport function useSession(opts: UseSessionOptions = {}): UseSessionReturn {\n const { ttlSeconds = DEFAULT_SESSION_TTL_SECONDS, onExpire } = opts;\n const [session, setSession] = useState<WACSession | null>(null);\n const [remainingMs, setRemainingMs] = useState(0);\n const expiredRef = useRef(false);\n const onExpireRef = useRef(onExpire);\n\n useEffect(() => {\n onExpireRef.current = onExpire;\n }, [onExpire]);\n\n useEffect(() => {\n const current = readSession();\n setSession(current);\n setRemainingMs(current ? current.expiresAt - Date.now() : 0);\n }, []);\n\n useEffect(() => {\n if (!session) return;\n const interval = window.setInterval(() => {\n const current = readSession();\n if (!current) {\n if (!expiredRef.current) {\n expiredRef.current = true;\n onExpireRef.current?.();\n }\n setSession(null);\n setRemainingMs(0);\n return;\n }\n setRemainingMs(current.expiresAt - Date.now());\n }, 15000);\n return () => window.clearInterval(interval);\n }, [session]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const onStorage = (e: StorageEvent) => {\n if (e.key && e.key !== \"wac_session\") return;\n const current = readSession();\n setSession(current);\n setRemainingMs(current ? current.expiresAt - Date.now() : 0);\n };\n window.addEventListener(\"storage\", onStorage);\n return () => window.removeEventListener(\"storage\", onStorage);\n }, []);\n\n const setToken = useCallback(\n (token: string, userId: string) => {\n expiredRef.current = false;\n const updated = writeSession(\n {\n token,\n userId,\n sessionId: readSession()?.sessionId ?? newSessionId(),\n history: readSession()?.history ?? [],\n },\n ttlSeconds,\n );\n setSession(updated);\n setRemainingMs(updated ? updated.expiresAt - Date.now() : 0);\n },\n [ttlSeconds],\n );\n\n const setHistory = useCallback(\n (history: Message[]) => {\n const updated = writeSession({ history }, ttlSeconds);\n if (updated) {\n setSession(updated);\n setRemainingMs(updated.expiresAt - Date.now());\n }\n },\n [ttlSeconds],\n );\n\n const touch = useCallback(() => {\n const updated = touchSession(ttlSeconds);\n if (updated) {\n setSession(updated);\n setRemainingMs(updated.expiresAt - Date.now());\n }\n }, [ttlSeconds]);\n\n const clear = useCallback(() => {\n clearSession();\n setSession(null);\n setRemainingMs(0);\n expiredRef.current = true;\n }, []);\n\n return { session, remainingMs, setToken, setHistory, touch, clear };\n}\n","@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@600;700;800&display=swap');\n\n.root {\n --wac-brand: #1a2d5a;\n --wac-brand-contrast: #ffffff;\n --wac-bg: #ffffff;\n --wac-fg: #1f2937;\n --wac-muted: #6b7280;\n --wac-border: #e5e7eb;\n --wac-bot-bg: #f3f4f6;\n --wac-user-bg: var(--wac-brand);\n --wac-chip-bg: #e7ebf7;\n --wac-chip-fg: #1c2c5b;\n --wac-chip-active-bg: var(--wac-brand);\n --wac-chip-active-fg: #ffffff;\n --wac-radius: 14px;\n --wac-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);\n font-family: 'Manrope', system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n color: var(--wac-fg);\n box-sizing: border-box;\n}\n\n.root *,\n.root *::before,\n.root *::after {\n box-sizing: inherit;\n}\n\n/* Sora for headings/labels/symbols — mirrors the HTML prototype */\n.headerTitle,\n.menuItemTitle,\n.markdown :global(.wa-card-sym),\n.markdown :global(.sec) :global(.lbl),\n.markdown :global(.wa-verdict-lbl) {\n font-family: 'Sora', 'Manrope', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n}\n\n.floatingButton {\n position: fixed;\n bottom: 24px;\n z-index: 2147483646;\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n cursor: pointer;\n box-shadow: var(--wac-shadow);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 26px;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.floatingButton:hover {\n transform: translateY(-2px);\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.22);\n}\n\n.positionRight {\n right: 24px;\n}\n\n.positionLeft {\n left: 24px;\n}\n\n.widget {\n position: fixed;\n bottom: 24px;\n z-index: 2147483647;\n width: 420px;\n max-width: calc(100vw - 24px);\n height: min(760px, calc(100vh - 48px));\n background: var(--wac-bg);\n color: var(--wac-fg);\n border-radius: 24px;\n box-shadow: 0 18px 50px -18px rgba(28, 44, 91, 0.45);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--wac-border);\n}\n\n@media (max-width: 640px) {\n .widget {\n width: calc(100vw - 12px);\n height: calc(100vh - 24px);\n bottom: 12px;\n }\n .positionRight,\n .positionLeft {\n right: 6px;\n left: auto;\n }\n .floatingButton {\n width: 56px;\n height: 56px;\n bottom: 16px;\n }\n /* Both positions collapse to right: 6px on mobile, so sync popup */\n .popupBubbleLeft,\n .popupBubbleRight {\n right: 72px;\n left: auto;\n bottom: 16px;\n max-width: calc(100vw - 84px);\n }\n}\n\n.header {\n background: linear-gradient(135deg, var(--wac-brand) 0%, #15224a 100%);\n color: var(--wac-brand-contrast);\n padding: 15px 18px 13px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.headerTitle {\n font-weight: 700;\n font-size: 17px;\n line-height: 1.2;\n}\n\n.headerMeta {\n font-size: 11px;\n opacity: 0.85;\n margin-top: 2px;\n}\n\n.headerActions {\n display: flex;\n gap: 4px;\n align-items: center;\n}\n\n.iconButton {\n background: transparent;\n color: inherit;\n border: none;\n cursor: pointer;\n font-size: 18px;\n padding: 4px 8px;\n border-radius: 6px;\n line-height: 1;\n}\n\n.iconButton:hover {\n background: rgba(255, 255, 255, 0.15);\n}\n\n.body {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background: #fafafa;\n scroll-behavior: smooth;\n}\n\n.body::-webkit-scrollbar {\n width: 6px;\n}\n\n.body::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 3px;\n}\n\n.bubble {\n /* max-width: 80%; */\n padding: 10px 14px;\n border-radius: 12px;\n font-size: 14px;\n line-height: 1.45;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n/* markdown-it output inside a bot bubble.\n markdown-it (breaks: true) emits a <br> for every \\n in the source,\n so we MUST NOT also apply white-space: pre-wrap here — otherwise every\n newline gets rendered twice (once via <br>, once via the literal \\n in\n CSS) and the bubble looks double-spaced. */\n.markdown {\n white-space: normal;\n --card-bg: #ffffff;\n --text: var(--wac-fg);\n --text-muted: var(--wac-muted);\n --green: #16a34a;\n --red: #dc2626;\n}\n.markdown p {\n margin: 0 0 6px 0;\n}\n.markdown p:last-child {\n margin-bottom: 0;\n}\n.markdown br {\n /* Make consecutive <br>s collapse a bit — keeps line rhythm tight. */\n line-height: 1.4;\n}\n.markdown strong {\n font-weight: 700;\n color: var(--wac-fg);\n letter-spacing: 0.2px;\n}\n.markdown em {\n font-style: italic;\n color: var(--wac-muted);\n}\n.markdown ul,\n.markdown ol {\n margin: 4px 0 6px 0;\n padding-left: 22px;\n}\n.markdown li {\n margin: 1px 0;\n}\n.markdown a {\n color: var(--wac-brand);\n text-decoration: underline;\n}\n.markdown code {\n background: rgba(0, 0, 0, 0.06);\n padding: 1px 4px;\n border-radius: 4px;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n}\n.markdown h1,\n.markdown h2,\n.markdown h3 {\n margin: 6px 0 2px 0;\n font-size: 14px;\n font-weight: 700;\n}\n\n/* Price snapshot grid (backend: price_snapshot_template.py) */\n.markdown :global(.mgrid) {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n margin-top: 8px;\n}\n\n.markdown :global(.mgrid) :global(.wa-price) {\n background: var(--card-bg, #fff);\n border: 1px solid #e6e9f5;\n border-radius: 12px;\n padding: 12px 14px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.markdown :global(.mgrid) :global(.k) {\n font-size: 11px;\n color: var(--text-muted, #888);\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.markdown :global(.mgrid) :global(.wa-price-value) {\n font-size: 18px;\n font-weight: 700;\n color: var(--text, #111);\n}\n\n.markdown :global(.mgrid) :global(.wa-price-value.up) {\n color: var(--green);\n}\n\n.markdown :global(.mgrid) :global(.wa-price-value.down) {\n color: var(--red);\n}\n\n.markdown :global(.mgrid) :global(.n) {\n font-size: 12px;\n font-weight: 500;\n color: var(--text-muted, #888);\n}\n\n.markdown :global(.mgrid) :global(.n.up) {\n color: var(--green);\n}\n\n.markdown :global(.mgrid) :global(.n.down) {\n color: var(--red);\n}\n\n.markdown :global(.sec) :global(.lbl) {\n font-size: 13px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--text-muted, #666);\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.markdown :global(.mgrid) :global(.wa-price.full-width) {\n grid-column: 1 / -1;\n text-align: center;\n align-items: center;\n justify-content: center;\n}\n/* ── Stock Analysis Card — existing investor flow ────────────────────────── */\n\n/* Outer card wrapper */\n.markdown :global(.wa-analysis-card) {\n background: #fff;\n border: 1px solid #e6e9f5;\n border-radius: 18px;\n overflow: hidden;\n box-shadow: 0 12px 34px -24px rgba(28, 44, 91, 0.4);\n margin-bottom: 4px;\n}\n\n/* Card header — navy gradient */\n.markdown :global(.wa-card-head) {\n background: linear-gradient(135deg, #22356e 0%, #15224a 100%);\n color: #fff;\n padding: 14px 16px 13px;\n position: relative;\n}\n.markdown :global(.wa-card-date) {\n float: right;\n font-size: 11px;\n opacity: 0.7;\n font-weight: 600;\n}\n.markdown :global(.wa-card-tag) {\n display: inline-block;\n font-size: 9.5px;\n font-weight: 800;\n letter-spacing: 1px;\n background: rgba(255, 255, 255, 0.16);\n padding: 3px 9px;\n border-radius: 6px;\n margin-bottom: 8px;\n}\n.markdown :global(.wa-card-sym) {\n font-weight: 700;\n font-size: 17px;\n line-height: 1.2;\n}\n.markdown :global(.wa-card-meta) {\n font-size: 11.5px;\n opacity: 0.8;\n margin-top: 3px;\n}\n\n/* Section container */\n.markdown :global(.sec) {\n padding: 12px 14px;\n border-top: 1px solid #eceffa;\n}\n\n/* Metric grid — flat variant (gap = 1px divider line effect) */\n.markdown :global(.mgrid.flat) {\n border: none;\n gap: 10px;\n background: transparent;\n margin-top: 9px;\n}\n\n/* Metric cell */\n.markdown :global(.mgrid) :global(.m) {\n background: #fff;\n border: 1px solid #e6e9f5;\n border-radius: 10px;\n padding: 12px 13px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.markdown :global(.mgrid) :global(.m) :global(.k) {\n font-size: 9.5px;\n color: #737b97;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-weight: 700;\n}\n.markdown :global(.mgrid) :global(.m) :global(.v) {\n font-size: 14px;\n font-weight: 700;\n color: #1c2438;\n margin-top: 2px;\n}\n.markdown :global(.mgrid) :global(.m) :global(.n) {\n font-size: 10.5px;\n font-weight: 700;\n color: #737b97;\n margin-top: 1px;\n}\n/* Score colour modifiers on .n inside metric cells */\n.markdown :global(.mgrid) :global(.m) :global(.n.good) {\n color: #16a34a;\n}\n.markdown :global(.mgrid) :global(.m) :global(.n.avg) {\n color: #737b97;\n}\n.markdown :global(.mgrid) :global(.m) :global(.n.low) {\n color: #b45309;\n}\n\n/* Regime label inside metric cell */\n.markdown :global(.wa-regime) {\n font-size: 12px;\n}\n\n/* Your Position block */\n.markdown :global(.wa-pos) {\n margin-top: 9px;\n border-radius: 12px;\n padding: 12px 14px;\n border: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n.markdown :global(.wa-pos.profit) {\n background: linear-gradient(135deg, #ecfdf3, #f7fef9);\n border-color: #bbf7d0;\n}\n.markdown :global(.wa-pos.loss) {\n background: linear-gradient(135deg, #fef2f2, #fff5f5);\n border-color: #fecaca;\n}\n.markdown :global(.wa-pl) {\n font-weight: 800;\n font-size: 22px;\n line-height: 1;\n color: #1c2438;\n}\n.markdown :global(.wa-pl.up) {\n color: #16a34a;\n}\n.markdown :global(.wa-pl.down) {\n color: #dc2626;\n}\n.markdown :global(.wa-zone) {\n font-size: 11px;\n font-weight: 700;\n color: #737b97;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n margin-top: 4px;\n}\n.markdown :global(.wa-summ) {\n font-size: 12.5px;\n line-height: 1.5;\n margin-top: 8px;\n color: #3a4159;\n}\n\n/* Key-value rows (Trend Structure, Indicators) */\n.markdown :global(.kv) {\n display: flex;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.5;\n margin-bottom: 7px;\n}\n.markdown :global(.kv:last-child) {\n margin-bottom: 0;\n}\n.markdown :global(.kk) {\n font-weight: 700;\n color: #1c2c5b;\n flex: 0 0 auto;\n min-width: 90px;\n}\n.markdown :global(.vv) {\n color: #3a4159;\n}\n\n/* Recovery level value */\n.markdown :global(.wa-recovery) {\n font-size: 11.5px;\n color: #3a4159;\n}\n\n/* Verdict block */\n.markdown :global(.wa-verdict) {\n padding: 13px 16px;\n border-top: 1px solid #eceffa;\n background: #fafbff;\n}\n.markdown :global(.wa-verdict-lbl) {\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.7px;\n text-transform: uppercase;\n color: #1c2c5b;\n margin-bottom: 8px;\n}\n.markdown :global(.wa-verdict-list) {\n margin: 0;\n padding-left: 20px;\n list-style-type: disc;\n list-style-position: outside;\n font-size: 12.5px;\n line-height: 1.55;\n color: #3a4159;\n}\n.markdown :global(.wa-verdict-list) li {\n display: list-item;\n margin-bottom: 6px;\n padding-left: 2px;\n}\n.markdown :global(.wa-verdict-list) li:last-child {\n margin-bottom: 0;\n}\n\n/* Business Health bullets and scale note */\n.markdown :global(.wa-bullets) {\n margin: 8px 0 4px 0;\n padding-left: 17px;\n font-size: 12px;\n line-height: 1.5;\n color: #3a4159;\n}\n.markdown :global(.wa-bullets) li {\n margin-bottom: 4px;\n}\n.markdown :global(.wa-scale-note) {\n font-size: 10.5px;\n color: #737b97;\n margin-top: 6px;\n line-height: 1.4;\n}\n\n/* VS Peers */\n.markdown :global(.wa-peer-ctx) {\n font-size: 12px;\n color: #737b97;\n margin-bottom: 8px;\n font-weight: bold;\n}\n.markdown :global(.wa-peer-row) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 7px 10px;\n border-radius: 8px;\n background: #f8f9fc;\n border: 1px solid #eceffa;\n margin-bottom: 6px;\n font-size: 12px;\n}\n.markdown :global(.wa-peer-sym) {\n font-weight: 700;\n color: #1c2c5b;\n}\n.markdown :global(.wa-peer-detail) {\n color: #3a4159;\n}\n.markdown :global(.wa-peer-detail) :global(.up) {\n color: #16a34a;\n font-weight: 700;\n}\n.markdown :global(.wa-peer-detail) :global(.down) {\n color: #dc2626;\n font-weight: 700;\n}\n.markdown :global(.wa-peer-empty) {\n font-size: 12px;\n color: #737b97;\n line-height: 1.5;\n padding: 4px 0;\n}\n.markdown :global(.wa-top-peer) {\n font-size: 11.5px;\n color: #1c2c5b;\n font-weight: 600;\n margin-top: 4px;\n padding: 6px 10px;\n background: #eef2ff;\n border-radius: 8px;\n}\n\n/* ── New Investor Flow — Signal, AI Lens, Indicators, Invalidation ───────── */\n\n/* Signal badge + label row */\n.markdown :global(.wa-signal-header) {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n margin-bottom: 10px;\n}\n.markdown :global(.wa-signal-lbl) {\n font-size: 13px;\n font-weight: 600;\n color: #3a4159;\n flex: 1;\n}\n.markdown :global(.wa-signal-level) {\n padding: 10px 0;\n}\n.markdown :global(.wa-signal-level) :global(.kv) {\n gap: 4px;\n align-items: center;\n margin-bottom: 0;\n}\n.markdown :global(.wa-signal-level) :global(.kk) {\n min-width: auto;\n}\n\n/* Direction / action badges (shared across flows) */\n.markdown :global(.wa-badge) {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 6px 13px;\n border-radius: 999px;\n font-size: 12px;\n font-weight: 800;\n letter-spacing: 0.3px;\n white-space: nowrap;\n}\n.markdown :global(.wa-b-buy) {\n background: #dcfce7;\n color: #16a34a;\n}\n.markdown :global(.wa-b-sell) {\n background: #fee2e2;\n color: #dc2626;\n}\n.markdown :global(.wa-b-wait) {\n background: #fef3e0;\n color: #b45309;\n}\n.markdown :global(.wa-b-info) {\n background: #e0ecff;\n color: #2563eb;\n}\n\n/* ── Macro Event card (.evt) ─────────────────────────────────────────────── */\n.markdown :global(.evt) {\n border: 1px solid #e6e9f5;\n border-radius: 16px;\n overflow: hidden;\n margin-bottom: 12px;\n background: #fff;\n box-shadow: 0 12px 30px -24px rgba(28, 44, 91, 0.4);\n}\n.markdown :global(.evt .top) {\n padding: 13px 15px;\n display: flex;\n gap: 11px;\n align-items: flex-start;\n}\n.markdown :global(.evt .num) {\n width: 26px;\n height: 26px;\n flex: 0 0 auto;\n border-radius: 8px;\n background: #1c2c5b;\n color: #fff;\n display: grid;\n place-items: center;\n font-weight: 700;\n font-size: 13px;\n}\n.markdown :global(.evt .ti) {\n font-weight: 700;\n font-size: 13.5px;\n line-height: 1.25;\n color: #1c2438;\n}\n.markdown :global(.evt .dt) {\n font-size: 11px;\n color: #737b97;\n margin-top: 2px;\n}\n.markdown :global(.evt .news) {\n padding: 0 15px 12px;\n font-size: 12.5px;\n line-height: 1.5;\n color: #3a4159;\n}\n.markdown :global(.evt .news .imp) {\n display: inline-block;\n margin-top: 7px;\n}\n.markdown :global(.evt .body) {\n padding: 11px 15px;\n border-top: 1px solid #eceffa;\n background: #fbfcff;\n}\n.markdown :global(.evt .body) :global(.lbl) {\n font-size: 13px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--text-muted, #666);\n margin-top: 8px;\n margin-bottom: 6px;\n}\n.markdown :global(.evt .body) :global(.wa-verdict-text) {\n margin: 4px 0 0;\n}\n\n/* ── Sector impact block (.impact) ──────────────────────────────────────── */\n.markdown :global(.impact) {\n margin-top: 8px;\n}\n.markdown :global(.ih) {\n font-size: 10.5px;\n font-weight: 800;\n letter-spacing: 0.4px;\n text-transform: uppercase;\n margin-bottom: 7px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n.markdown :global(.ih.neg) { color: #dc2626; }\n.markdown :global(.ih.mod) { color: #b45309; }\n.markdown :global(.ih.pos) { color: #16a34a; }\n\n/* ── Sector impact pill (.pill) ─────────────────────────────────────────── */\n.markdown :global(.pill) {\n display: block;\n font-size: 12px;\n line-height: 1.45;\n padding: 8px 11px;\n border-radius: 10px;\n margin-bottom: 6px;\n border: 1px solid;\n}\n.markdown :global(.pill b) { font-weight: 700; }\n.markdown :global(.pill.neg) {\n background: #fee2e2;\n border-color: #fecaca;\n color: #7f1d1d;\n}\n.markdown :global(.pill.mod) {\n background: #fef3e0;\n border-color: #fde2b8;\n color: #7c4a03;\n}\n.markdown :global(.pill.pos) {\n background: #dcfce7;\n border-color: #bbf7d0;\n color: #14532d;\n}\n\n/* Confidence score row */\n.markdown :global(.wa-conf-row) {\n display: flex;\n align-items: center;\n gap: 9px;\n margin-top: 10px;\n padding: 8px 12px;\n background: #f8f9fc;\n border-radius: 10px;\n border: 1px solid #eceffa;\n}\n.markdown :global(.wa-conf-badge) {\n font-size: 13px;\n font-weight: 800;\n padding: 4px 10px;\n border-radius: 999px;\n background: #eceffa;\n color: #1c2c5b;\n}\n.markdown :global(.wa-conf-badge.good) {\n background: #dcfce7;\n color: #16a34a;\n}\n.markdown :global(.wa-conf-badge.low) {\n background: #fee2e2;\n color: #dc2626;\n}\n.markdown :global(.wa-conf-badge.avg) {\n background: #fef3e0;\n color: #b45309;\n}\n.markdown :global(.wa-conf-text) {\n font-size: 12px;\n color: #3a4159;\n flex: 1;\n}\n\n/* AI Lens */\n.markdown :global(.wa-ai-heading) {\n font-size: 13.5px;\n font-weight: 700;\n color: #1c2c5b;\n margin-bottom: 5px;\n}\n.markdown :global(.wa-ai-insight) {\n font-size: 12.5px;\n line-height: 1.55;\n color: #3a4159;\n margin-bottom: 6px;\n}\n\n/* Invalidation */\n.markdown :global(.wa-inv-text) {\n font-size: 12.5px;\n line-height: 1.5;\n color: #3a4159;\n}\n.markdown :global(.wa-inv-status) {\n margin-top: 8px;\n}\n\n/* Text verdict (new investor flow — single string, not a bullet list) */\n.markdown :global(.wa-verdict-text) {\n font-size: 12.5px;\n line-height: 1.55;\n color: #3a4159;\n}\n\n/* ── Portfolio Risk — Gauge, Action Rows, Clist, Allocation Bars ────────── */\n\n/* Health score gauge (red → amber → green gradient) */\n.markdown :global(.gauge) {\n height: 10px;\n border-radius: 6px;\n background: linear-gradient(90deg, #dc2626 0%, #f59e0b 50%, #16a34a 100%);\n position: relative;\n margin: 6px 0 28px;\n}\n.markdown :global(.wa-portfolio-gauge-wrap) {\n padding: 4px 22px 32px;\n overflow: visible;\n}\n.markdown :global(.wa-portfolio-health-gauge) {\n margin: 6px 0 0;\n}\n.markdown :global(.gauge) :global(.pin),\n.markdown :global(.wa-portfolio-gauge-pin) {\n position: absolute;\n top: -4px;\n width: 5px;\n height: 18px;\n border-radius: 3px;\n background: #1c2c5b;\n box-shadow: 0 0 0 3px #fff;\n transform: translateX(-50%);\n}\n.markdown :global(.gauge) :global(.lab),\n.markdown :global(.wa-portfolio-gauge-score) {\n position: absolute;\n top: 17px;\n font-size: 11px;\n font-weight: 800;\n color: #1c2c5b;\n transform: translateX(-50%);\n white-space: nowrap;\n}\n\n/* Portfolio performance header — two-line summary */\n.markdown :global(.wa-portfolio-performance-head) :global(.wa-portfolio-header-title) {\n margin-top: 2px;\n line-height: 1.25;\n}\n.markdown :global(.wa-portfolio-header-meta) {\n margin-top: 8px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.markdown :global(.wa-portfolio-header-summary) {\n font-size: 11.5px;\n line-height: 1.45;\n opacity: 0.92;\n color: #fff;\n}\n.markdown :global(.wa-portfolio-header-risk) {\n font-size: 11px;\n line-height: 1.4;\n opacity: 0.75;\n color: #fff;\n}\n\n/* Portfolio health section spacing */\n.markdown :global(.wa-portfolio-health-section) {\n overflow: visible;\n}\n.markdown :global(.wa-portfolio-health-verdict) {\n margin-top: 2px;\n}\n\n/* CAGR / Risk metric rows */\n.markdown :global(.wa-portfolio-metrics-block) {\n padding: 10px 0 6px;\n margin-top: 4px;\n}\n.markdown :global(.wa-portfolio-metric-row) {\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 6px;\n}\n.markdown :global(.wa-portfolio-metric-row):last-child {\n margin-bottom: 0;\n}\n.markdown :global(.wa-portfolio-metric-label) {\n min-width: 48px;\n flex-shrink: 0;\n}\n.markdown :global(.wa-portfolio-metric-value) {\n flex: 1;\n line-height: 1.45;\n}\n\n/* Portfolio optimization bullet lists */\n.markdown :global(.wa-portfolio-bullet-list) {\n margin: 0;\n padding-left: 20px;\n list-style-type: disc;\n list-style-position: outside;\n font-size: 12.5px;\n line-height: 1.55;\n color: #3a4159;\n}\n.markdown :global(.wa-portfolio-bullet-list) li {\n display: list-item;\n margin-bottom: 6px;\n padding-left: 2px;\n}\n.markdown :global(.wa-portfolio-bullet-list) li:last-child {\n margin-bottom: 0;\n}\n.markdown :global(.wa-portfolio-concerns-list),\n.markdown :global(.wa-portfolio-actions-needed-list) {\n margin-top: 2px;\n}\n.markdown :global(.wa-portfolio-verdict-block) :global(.wa-portfolio-verdict-list) {\n margin-top: 0;\n}\n\n/* Health check — Current Mix vs Target (Stocks row full-width centered) */\n.markdown :global(.wa-portfolio-mix-grid) :global(.wa-portfolio-mix-stocks-full) {\n grid-column: 1 / -1;\n text-align: center;\n align-items: center;\n justify-content: center;\n}\n.markdown :global(.wa-portfolio-mix-stocks-full) :global(.v) {\n text-align: center;\n}\n\n/* Health check — Stock / ETF deviation rows */\n.markdown :global(.wa-portfolio-deviation-block) {\n padding: 10px 0 4px;\n margin-top: 6px;\n}\n.markdown :global(.wa-portfolio-deviation-row) {\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 8px;\n}\n.markdown :global(.wa-portfolio-deviation-row):last-child {\n margin-bottom: 0;\n}\n.markdown :global(.wa-portfolio-deviation-label) {\n min-width: 108px;\n flex-shrink: 0;\n}\n.markdown :global(.wa-portfolio-deviation-value) {\n flex: 1;\n line-height: 1.45;\n}\n\n/* Health check — Structure Points cards */\n.markdown :global(.wa-portfolio-structure-section) {\n padding-bottom: 14px;\n}\n.markdown :global(.wa-portfolio-structure-card) {\n border: 1px solid #e6e9f5;\n border-radius: 12px;\n padding: 11px 13px;\n margin-bottom: 8px;\n background: #f8f9fc;\n}\n.markdown :global(.wa-portfolio-structure-card):last-child {\n margin-bottom: 0;\n}\n.markdown :global(.wa-portfolio-structure-card-head) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 6px;\n}\n.markdown :global(.wa-portfolio-structure-symbol) {\n font-weight: 800;\n font-size: 13px;\n color: #1c2c5b;\n letter-spacing: 0.02em;\n}\n.markdown :global(.wa-portfolio-structure-score-badge) {\n font-size: 10px;\n font-weight: 700;\n padding: 3px 8px;\n border-radius: 999px;\n background: #eceffa;\n color: #1c2c5b;\n white-space: nowrap;\n}\n.markdown :global(.wa-portfolio-structure-line) {\n font-size: 12px;\n line-height: 1.45;\n color: #3a4159;\n margin-bottom: 4px;\n}\n.markdown :global(.wa-portfolio-structure-line) :global(.up) {\n color: var(--green);\n font-weight: 700;\n}\n.markdown :global(.wa-portfolio-structure-line) :global(.down) {\n color: var(--red);\n font-weight: 700;\n}\n.markdown :global(.wa-portfolio-structure-line):last-of-type {\n margin-bottom: 0;\n}\n.markdown :global(.wa-portfolio-structure-meta) {\n font-size: 11.5px;\n line-height: 1.4;\n color: #737b97;\n margin-top: 4px;\n}\n\n/* Portfolio build — Sector Allocation card layout */\n.markdown :global(.wa-portfolio-sector-card-head) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n margin-bottom: 8px;\n}\n.markdown :global(.wa-portfolio-sector-return) {\n flex: 1;\n text-align: center;\n font-size: 11px;\n font-weight: 600;\n color: #3a4159;\n white-space: nowrap;\n}\n.markdown :global(.wa-portfolio-sector-return) :global(.up) {\n color: var(--green);\n font-weight: 700;\n}\n.markdown :global(.wa-portfolio-sector-return) :global(.down) {\n color: var(--red);\n font-weight: 700;\n}\n.markdown :global(.wa-portfolio-sector-capital-line) {\n font-size: 12px;\n font-weight: 700;\n color: #3a4159;\n margin-bottom: 6px;\n}\n.markdown :global(.wa-portfolio-sector-bullet-list) {\n list-style: none;\n padding-left: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n}\n.markdown :global(.wa-portfolio-sector-bullet-list) li {\n margin-bottom: 4px;\n padding-left: 0;\n}\n.markdown :global(.wa-portfolio-sector-bullet-list) li::before {\n content: \"· \";\n font-weight: 700;\n color: #737b97;\n}\n.markdown :global(.wa-portfolio-sector-bullet-list) li:last-child {\n margin-bottom: 0;\n}\n\n/* Health verdict text */\n.markdown :global(.wa-health-text) {\n font-size: 12px;\n font-weight: 600;\n color: #dc2626;\n line-height: 1.5;\n margin-top: 4px;\n}\n.markdown :global(.wa-health-text.ok) {\n color: #16a34a;\n}\n.markdown :global(.wa-health-text.warn) {\n color: #b45309;\n}\n\n/* Action rows — EXIT / TRIM / ADD / HOLD / SWITCH / REVIEW */\n.markdown :global(.act) {\n display: flex;\n gap: 10px;\n align-items: flex-start;\n padding: 10px 12px;\n border-radius: 12px;\n margin-bottom: 8px;\n border: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n.markdown :global(.act):last-child {\n margin-bottom: 0;\n}\n.markdown :global(.act.exit) {\n background: #fee2e2;\n border-color: #fecaca;\n}\n.markdown :global(.act.trim) {\n background: #fef3e0;\n border-color: #fde2b8;\n}\n.markdown :global(.act.add) {\n background: #dcfce7;\n border-color: #bbf7d0;\n}\n.markdown :global(.act.hold) {\n background: #f1f3fa;\n border-color: #e0e4f0;\n}\n.markdown :global(.act.switch) {\n background: #e0ecff;\n border-color: #bfdbfe;\n}\n/* Action type label pill */\n.markdown :global(.act) :global(.at) {\n flex: 0 0 auto;\n font-size: 10px;\n font-weight: 800;\n letter-spacing: 0.5px;\n padding: 4px 8px;\n border-radius: 6px;\n color: #fff;\n white-space: nowrap;\n}\n.markdown :global(.act.exit) :global(.at) { background: #dc2626; }\n.markdown :global(.act.trim) :global(.at) { background: #b45309; }\n.markdown :global(.act.add) :global(.at) { background: #16a34a; }\n.markdown :global(.act.hold) :global(.at) { background: #737b97; }\n.markdown :global(.act.switch) :global(.at) { background: #2563eb; }\n/* Action description */\n.markdown :global(.act) :global(.ad) {\n font-size: 12.5px;\n line-height: 1.45;\n}\n.markdown :global(.act) :global(.ad) b {\n font-weight: 700;\n color: #1c2c5b;\n}\n.markdown :global(.act) :global(.ad) :global(.r) {\n color: #3a4159;\n display: block;\n margin-top: 2px;\n}\n\n/* Concerns / actions bullet list */\n.markdown :global(.clist) {\n margin: 0;\n padding-left: 17px;\n font-size: 12px;\n line-height: 1.5;\n color: #3a4159;\n}\n.markdown :global(.clist) li {\n margin-bottom: 5px;\n}\n.markdown :global(.clist) li:last-child {\n margin-bottom: 0;\n}\n\n/* Asset allocation bars */\n.markdown :global(.alloc) {\n margin-top: 6px;\n}\n.markdown :global(.alloc) :global(.row) {\n display: flex;\n align-items: center;\n gap: 9px;\n margin-bottom: 9px;\n font-size: 12px;\n}\n.markdown :global(.alloc) :global(.row):last-child {\n margin-bottom: 0;\n}\n.markdown :global(.alloc) :global(.nm) {\n width: 54px;\n font-weight: 700;\n color: #1c2c5b;\n flex-shrink: 0;\n}\n.markdown :global(.alloc) :global(.bar) {\n flex: 1;\n height: 8px;\n border-radius: 5px;\n background: #eef0f7;\n overflow: hidden;\n}\n.markdown :global(.alloc) :global(.bar) i {\n display: block;\n height: 100%;\n border-radius: 5px;\n background: #1c2c5b;\n}\n.markdown :global(.alloc) :global(.pct) {\n width: 42px;\n text-align: right;\n font-weight: 700;\n color: #1c2438;\n flex-shrink: 0;\n}\n\n/* Return value colour helpers inside metric grid .v cells */\n.markdown :global(.mgrid) :global(.v.up) {\n color: var(--green);\n}\n.markdown :global(.mgrid) :global(.v.down) {\n color: var(--red);\n}\n.markdown :global(.mgrid) :global(.m) :global(.n.up) {\n color: var(--green);\n}\n.markdown :global(.mgrid) :global(.m) :global(.n.down) {\n color: var(--red);\n}\n.markdown :global(.mgrid) :global(.v.low) {\n color: #b45309;\n}\n\n/* Signal score emphasis inside kv rows (Tradable Candidate) */\n.markdown :global(.kv) :global(.vv) :global(b.up) {\n color: var(--green);\n}\n.markdown :global(.kv) :global(.vv) :global(b.down) {\n color: var(--red);\n}\n.markdown :global(.kv) :global(.vv) :global(b.low) {\n color: #b45309;\n}\n\n/* ── Crypto Analysis — stance row, metric notes, kv stacks ──────────────── */\n.markdown :global(.wa-crypto-stance-row) {\n margin-top: 8px;\n}\n.markdown :global(.wa-crypto-stance-row-lg) {\n margin-top: 11px;\n}\n.markdown :global(.wa-crypto-stance-reason) {\n font-size: 12px;\n color: #3a4159;\n margin-top: 8px;\n line-height: 1.5;\n}\n.markdown :global(.mgrid) :global(.m) :global(.n.wa-crypto-metric-detail) {\n font-weight: 500;\n line-height: 1.35;\n}\n.markdown :global(.wa-crypto-kv-primary) {\n display: block;\n font-size: 14px;\n font-weight: 700;\n}\n.markdown :global(.wa-crypto-kv-note) {\n display: block;\n font-size: 10.5px;\n font-weight: 700;\n margin-top: 2px;\n}\n.markdown :global(.wa-crypto-kv-note.up) {\n color: var(--green);\n}\n.markdown :global(.wa-crypto-kv-note.down) {\n color: var(--red);\n}\n.markdown :global(.wa-crypto-kv-note.low) {\n color: #b45309;\n}\n.markdown :global(.wa-crypto-kv-note.avg) {\n color: #737b97;\n}\n.markdown :global(.wa-crypto-kv-detail) {\n display: block;\n font-size: 10.5px;\n font-weight: 500;\n color: #737b97;\n margin-top: 2px;\n line-height: 1.35;\n}\n\n/* ── Stock Discovery & New Listings Card Components ─────────────────────── */\n\n/* Individual stock card */\n.markdown :global(.dstock) {\n border: 1px solid #e6e9f5;\n border-radius: 14px;\n padding: 12px 13px;\n margin-bottom: 10px;\n background: #fff;\n}\n.markdown :global(.dstock):last-child {\n margin-bottom: 0;\n}\n\n/* Stock card header row */\n.markdown :global(.dh) {\n display: flex;\n align-items: center;\n gap: 9px;\n margin-bottom: 9px;\n}\n\n/* Rank number chip */\n.markdown :global(.rank) {\n width: 24px;\n height: 24px;\n flex: 0 0 auto;\n border-radius: 6px;\n background: #e7ebf7;\n color: #1c2c5b;\n display: grid;\n place-items: center;\n font-weight: 800;\n font-size: 12px;\n}\n\n/* Stock symbol + company name */\n.markdown :global(.nm) {\n font-weight: 700;\n font-size: 13.5px;\n line-height: 1.2;\n color: #1c2438;\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n/* Inline badge inside .nm — smaller than the standalone badge */\n.markdown :global(.nm) :global(.wa-badge) {\n font-size: 10px;\n padding: 3px 8px;\n vertical-align: middle;\n}\n.markdown :global(.co) {\n font-size: 10.5px;\n color: #737b97;\n margin-top: 2px;\n}\n\n/* Fundamental score (right-aligned) */\n.markdown :global(.dstock) :global(.fs) {\n margin-left: auto;\n text-align: right;\n flex-shrink: 0;\n}\n.markdown :global(.dstock) :global(.fs) :global(.num) {\n font-weight: 800;\n font-size: 18px;\n color: #1c2c5b;\n line-height: 1;\n}\n.markdown :global(.dstock) :global(.fs) :global(.cap) {\n font-size: 8.5px;\n color: #737b97;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n margin-top: 2px;\n}\n\n/* Quality/Value/Growth/Confidence tag row */\n.markdown :global(.qrow) {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n align-items: center;\n}\n.markdown :global(.qrow.qrow-grid) {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n}\n.markdown :global(.qrow.qrow-grid) :global(.qtag) {\n min-height: 38px;\n width: 100%;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n line-height: 1.2;\n padding: 4px 6px;\n}\n.markdown :global(.qtag) {\n font-size: 10.5px;\n font-weight: 700;\n padding: 4px 9px;\n border-radius: 7px;\n border: 1px solid #e0e4f0;\n background: #f1f3fa;\n color: #475069;\n}\n.markdown :global(.qtag) :global(.qk) {\n opacity: 0.55;\n font-weight: 600;\n margin-right: 3px;\n}\n.markdown :global(.qtag.good) {\n background: #dcfce7;\n border-color: #bbf7d0;\n color: #14532d;\n}\n.markdown :global(.qtag.avg) {\n background: #f1f3fa;\n border-color: #e0e4f0;\n color: #475069;\n}\n.markdown :global(.qtag.low) {\n background: #fef3e0;\n border-color: #fde2b8;\n color: #7c4a03;\n}\n\n/* 3M return line below score tags (Peer Analysis dstock cards) */\n.markdown :global(.dstock) :global(.wa-peer-detail) {\n margin-top: 6px;\n font-size: 11.5px;\n}\n\n/* Scoring note footer */\n.markdown :global(.wa-disc-footer) {\n font-size: 11px;\n color: #737b97;\n line-height: 1.5;\n padding: 10px 14px;\n border-top: 1px solid #eceffa;\n}\n\n.bubbleBot {\n align-self: flex-start;\n background: var(--wac-bot-bg);\n color: #1c2438;\n border-bottom-left-radius: 4px;\n}\n\n.bubbleUser {\n align-self: flex-end;\n background: var(--wac-user-bg);\n color: var(--wac-brand-contrast);\n border-bottom-right-radius: 4px;\n}\n\n/* Card responses: the card supplies its own bg/border/radius, so the bubble\n must add no frame, padding or background around it. */\n.bubbleCard {\n align-self: stretch;\n background: transparent;\n padding: 0;\n border-radius: 0;\n}\n\n.bubbleMeta {\n font-size: 10px;\n color: var(--wac-muted);\n margin-top: 4px;\n text-align: right;\n}\n\n.chipRow {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 8px;\n}\n\n.chip {\n padding: 7px 12px;\n background: var(--wac-chip-bg);\n color: var(--wac-chip-fg);\n border: 1px solid transparent;\n border-radius: 999px;\n font-size: 13px;\n cursor: pointer;\n transition: background 0.15s ease, transform 0.15s ease;\n font-family: inherit;\n}\n\n.chip:hover:not(:disabled) {\n background: #d8def2;\n transform: translateY(-1px);\n}\n\n.chipActive {\n background: var(--wac-chip-active-bg);\n color: var(--wac-chip-active-fg);\n}\n\n.chipDisabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.typing {\n align-self: flex-start;\n display: inline-flex;\n gap: 4px;\n padding: 10px 14px;\n background: var(--wac-bot-bg);\n border-radius: 12px;\n border-bottom-left-radius: 4px;\n}\n\n.typingDot {\n width: 7px;\n height: 7px;\n background: var(--wac-muted);\n border-radius: 50%;\n animation: wacBlink 1.2s infinite ease-in-out both;\n}\n\n.typingDot:nth-child(2) {\n animation-delay: 0.18s;\n}\n.typingDot:nth-child(3) {\n animation-delay: 0.36s;\n}\n\n@keyframes wacBlink {\n 0%, 80%, 100% { opacity: 0.3; transform: scale(0.85); }\n 40% { opacity: 1; transform: scale(1); }\n}\n\n.input {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--wac-border);\n background: var(--wac-bg);\n}\n\n.inputBox {\n flex: 1;\n padding: 12px 16px;\n border: 1.6px solid var(--wac-brand);\n border-radius: 14px;\n font-size: 14px;\n outline: none;\n font-family: inherit;\n background: var(--wac-bg);\n color: var(--wac-fg);\n}\n\n.inputBox:focus {\n border-color: var(--wac-brand);\n background: var(--wac-bg);\n}\n\n.inputBox:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.sendButton {\n padding: 0 20px;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n border-radius: 14px;\n font-weight: 700;\n cursor: pointer;\n font-size: 14px;\n font-family: inherit;\n}\n\n.sendButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.hiddenFileInput {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n overflow: hidden;\n pointer-events: none;\n}\n\n.csvButton {\n flex-shrink: 0;\n padding: 0 12px;\n background: var(--wac-chip-bg);\n color: var(--wac-chip-fg);\n border: 1px solid var(--wac-border);\n border-radius: 999px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n font-family: inherit;\n white-space: nowrap;\n}\n\n.csvButton:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.authGate {\n margin: auto;\n text-align: center;\n padding: 32px 24px;\n max-width: 280px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.authGateIcon {\n font-size: 36px;\n}\n\n.authGateTitle {\n font-size: 16px;\n font-weight: 600;\n}\n\n.authGateText {\n font-size: 13px;\n color: var(--wac-muted);\n line-height: 1.5;\n}\n\n.authGateButton {\n margin-top: 8px;\n padding: 10px 20px;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border: none;\n border-radius: 999px;\n cursor: pointer;\n font-weight: 600;\n font-size: 14px;\n font-family: inherit;\n}\n\n.authGateDisclaimer {\n margin-top: 16px;\n padding-top: 12px;\n border-top: 1px dashed var(--wac-border);\n font-size: 11px;\n color: var(--wac-muted);\n line-height: 1.5;\n text-align: left;\n width: 100%;\n}\n\n.authGateDisclaimerTitle {\n font-weight: 700;\n letter-spacing: 0.6px;\n font-size: 10px;\n margin-bottom: 4px;\n color: var(--wac-fg);\n}\n\n.errorBanner {\n background: #fef2f2;\n border: 1px solid #fecaca;\n color: #991b1b;\n padding: 8px 12px;\n font-size: 12px;\n border-radius: 8px;\n margin: 0 14px 8px;\n}\n\n/* ── Greeting popup bubble ─────────────────────────────────────── */\n\n.popupBubble {\n position: fixed;\n bottom: 24px;\n z-index: 2147483646;\n background: var(--wac-brand);\n color: var(--wac-brand-contrast);\n border-radius: 12px;\n padding: 12px 36px 12px 14px;\n font-size: 13px;\n line-height: 1.45;\n box-shadow: var(--wac-shadow);\n border: none;\n max-width: 240px;\n animation: wacPopIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* Shared arrow base — direction is set per-position class below */\n.popupBubble::after {\n content: '';\n position: absolute;\n width: 12px;\n height: 12px;\n background: var(--wac-brand);\n}\n\n/* Popup to the LEFT of a right-positioned button — arrow points right */\n.popupBubbleRight {\n right: 94px;\n}\n\n.popupBubbleRight::after {\n right: -7px;\n top: 50%;\n border-top: 1px solid var(--wac-brand);\n border-right: 1px solid var(--wac-brand);\n transform: translateY(-50%) rotate(45deg);\n}\n\n/* Popup to the RIGHT of a left-positioned button — arrow points left */\n.popupBubbleLeft {\n left: 94px;\n}\n\n.popupBubbleLeft::after {\n left: -7px;\n top: 50%;\n border-bottom: 1px solid var(--wac-brand);\n border-left: 1px solid var(--wac-brand);\n transform: translateY(-50%) rotate(45deg);\n}\n\n.popupDismiss {\n position: absolute;\n top: 8px;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n font-size: 14px;\n color: var(--wac-brand-contrast);\n line-height: 1;\n padding: 2px 4px;\n border-radius: 4px;\n font-family: inherit;\n opacity: 0.75;\n}\n\n.popupDismiss:hover {\n background: rgba(255, 255, 255, 0.15);\n opacity: 1;\n}\n\n@keyframes wacPopIn {\n 0% { opacity: 0; transform: scale(0.85) translateY(8px); }\n 100% { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n/* ── Menu grid (root chips rendered as cards) ───────────────────── */\n.menuGrid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 6px;\n margin-top: 6px;\n}\n\n.menuItem {\n background: #fff;\n border: 1px solid #e6e9f5;\n border-radius: 14px;\n padding: 14px;\n cursor: pointer;\n text-align: left;\n font-family: inherit;\n transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;\n}\n\n.menuItem:hover {\n transform: translateY(-2px);\n box-shadow: 0 8px 20px -12px rgba(28, 44, 91, 0.45);\n border-color: #d4d9ee;\n}\n\n.menuItemIcon {\n width: 46px;\n height: 46px;\n border-radius: 12px;\n display: grid;\n place-items: center;\n font-size: 22px;\n margin-bottom: 12px;\n}\n\n/* Main-menu SVG icon — mirrors wealth-alpha-final.html .cmd .ico svg */\n.menuItemSvg {\n width: 24px;\n height: 24px;\n stroke: #fff;\n fill: none;\n stroke-width: 2.2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.menuItemTitle {\n font-size: 14px;\n font-weight: 700;\n color: #1c2438;\n line-height: 1.2;\n}\n\n.menuItemSub {\n font-size: 11.5px;\n color: #737b97;\n margin-top: 3px;\n line-height: 1.3;\n}\n\n.menuIconGreen { background: linear-gradient(135deg, #10b981, #059669); }\n.menuIconBlue { background: linear-gradient(135deg, #3b82f6, #2563eb); }\n.menuIconLeaf { background: linear-gradient(135deg, #65c466, #3f9c43); }\n.menuIconRed { background: linear-gradient(135deg, #f43f5e, #e11d48); }\n.menuIconOrange { background: linear-gradient(135deg, #fb923c, #ea580c); }\n.menuIconGold { background: linear-gradient(135deg, #fbbf24, #d97706); }\n.menuIconTeal { background: linear-gradient(135deg, #14b8a6, #0d9488); }\n.menuIconPurple { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }\n\n\n.chat_bubbleBot {\n background-color: var(--wac-bg) !important; \n}","import styles from \"../styles/chat.module.css\";\n\ninterface AuthGateProps {\n brandName: string;\n loginUrl: string;\n onLoginClick?: () => void;\n}\n\nexport function AuthGate({ brandName, loginUrl, onLoginClick }: AuthGateProps) {\n const handleClick = () => {\n if (onLoginClick) {\n onLoginClick();\n return;\n }\n if (typeof window !== \"undefined\") {\n window.location.href = loginUrl;\n }\n };\n\n return (\n <div className={styles.authGate}>\n <div className={styles.authGateIcon} aria-hidden=\"true\">🔒</div>\n <div className={styles.authGateTitle}>Login required</div>\n <div className={styles.authGateText}>\n To access {brandName}, please sign in first.\n </div>\n <button type=\"button\" className={styles.authGateButton} onClick={handleClick}>\n Sign in / Register →\n </button>\n <div className={styles.authGateDisclaimer}>\n <div className={styles.authGateDisclaimerTitle}>DISCLAIMER</div>\n <div>• AI-assisted analysis for educational purposes only.</div>\n <div>• Not financial advice. Markets involve risk.</div>\n <div>• Consult a SEBI-registered advisor before investing.</div>\n </div>\n </div>\n );\n}\n","import type { Chip as ChipType } from \"../types\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChipProps {\n chip: ChipType;\n disabled?: boolean;\n active?: boolean;\n onClick: (chip: ChipType) => void;\n}\n\nexport function Chip({ chip, disabled, active, onClick }: ChipProps) {\n const classes = [\n styles.chip,\n active ? styles.chipActive : \"\",\n disabled ? styles.chipDisabled : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <button\n type=\"button\"\n className={classes}\n disabled={disabled}\n onClick={() => !disabled && onClick(chip)}\n >\n {chip.icon ? <span aria-hidden=\"true\">{chip.icon}</span> : null}\n <span>{chip.label}</span>\n </button>\n );\n}\n","import type { Chip as ChipType } from \"../types\";\nimport { Chip } from \"./Chip\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChipRowProps {\n chips: ChipType[];\n disabled?: boolean;\n onClick: (chip: ChipType) => void;\n}\n\nexport function ChipRow({ chips, disabled, onClick }: ChipRowProps) {\n if (!chips || chips.length === 0) return null;\n return (\n <div className={styles.chipRow}>\n {chips.map((c) => (\n <Chip key={c.id} chip={c} disabled={disabled} onClick={onClick} />\n ))}\n </div>\n );\n}\n","import DOMPurify from \"isomorphic-dompurify\";\n\n/**\n * Backend (chat_widget.py + chat_template_dispatch.py) returns Telegram-HTML in\n * BotResponse.message — e.g. `<b>Heading</b><br>Body<br><i>Note</i>`.\n *\n * We sanitize with DOMPurify against a tight allow-list and feed straight into\n * the bubble via dangerouslySetInnerHTML. This matches the exact look of the\n * Telegram bot for every response template.\n *\n * Markdown-it is intentionally NOT used here anymore — the backend handles all\n * formatting via the shared Telegram templates.\n */\n\nconst ALLOWED_TAGS = [\n \"b\", \"strong\",\n \"i\", \"em\",\n \"u\", \"ins\",\n \"s\", \"strike\", \"del\",\n \"br\",\n \"p\",\n \"code\", \"pre\",\n \"a\",\n \"ul\", \"ol\", \"li\",\n \"blockquote\",\n \"span\",\n \"div\",\n];\n\nconst ALLOWED_ATTR = [\"href\", \"target\", \"rel\", \"class\", \"style\", \"data-wa-gauge-pct\"];\n\nconst SANITIZE_CFG = {\n ALLOWED_TAGS,\n ALLOWED_ATTR,\n // Block javascript: / data: hrefs by stripping URI schemes other than http(s) / mailto\n ALLOW_UNKNOWN_PROTOCOLS: false,\n ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.\\-:]|$))/i,\n};\n\n/**\n * Convert Telegram-style markdown shortcuts to HTML so chip prompts written\n * with `*bold*` / `_italic_` in Python source render the same way as the\n * template HTML output. Also handles the *standard* markdown that\n * AI-generated text (e.g. the sector-news `ai_verdict`) commonly emits.\n *\n * ## Heading → <b>Heading</b> (line-start ATX header, 1–6 #)\n * **text** → <b>text</b> (double asterisk, standard-bold)\n * __text__ → <b>text</b> (double underscore, standard-bold)\n * *text* → <b>text</b> (single asterisk, Telegram-bold)\n * _text_ → <i>text</i> (single underscore, italic)\n *\n * Order matters: double markers are converted before single ones so a `**`\n * pair isn't half-consumed by the single-asterisk rule. The single-marker\n * rules use lookbehind/ahead so they don't touch already-converted `<b>`\n * spans or dangling markers inside HTML attribute values.\n */\nfunction inlineMarkdownToHtml(text: string): string {\n return text\n // ATX headers at the start of a line → bold (verdict gap, no real <h*> here)\n .replace(/^[ \\t]*#{1,6}[ \\t]+(.+?)[ \\t]*$/gm, \"<b>$1</b>\")\n // Standard double-marker bold first, so the single-marker rules skip them.\n .replace(/\\*\\*([^\\n<>]+?)\\*\\*/g, \"<b>$1</b>\")\n .replace(/__([^\\n<>]+?)__/g, \"<b>$1</b>\")\n // Telegram single-asterisk bold / single-underscore italic.\n .replace(/(?<!\\*)\\*([^\\n*<>]+?)\\*(?!\\*)/g, \"<b>$1</b>\")\n .replace(/(?<![_a-zA-Z0-9])_([^\\n_<>]+?)_(?![_a-zA-Z0-9])/g, \"<i>$1</i>\");\n}\n\n/**\n * Render a Telegram-HTML or markdown-flavoured string from the backend as\n * sanitized HTML suitable for dangerouslySetInnerHTML.\n *\n * Pipeline:\n * 1. `*bold*` / `_italic_` markdown shortcuts → `<b>` / `<i>`\n * 2. Single `\\n` → `<br>`, `\\n\\n` → paragraph break (visual gap)\n * 3. DOMPurify sanitization against a tight allow-list\n */\n/** Card date headers arrive from the backend as \"09 Jun 2026, 06:55 PM\".\n * Show the date only — strip the trailing \", HH:MM …\" time (display-only;\n * the backend response is unchanged). */\nfunction stripCardDateTime(html: string): string {\n return html.replace(\n /(<span class=\"wa-card-date\">)([^<]*)(<\\/span>)/g,\n (_m: string, open: string, content: string, close: string) =>\n open + content.replace(/,\\s*\\d{1,2}:\\d{2}.*$/, \"\").trim() + close,\n );\n}\n\nexport function renderMarkdown(text: string): string {\n if (!text) return \"\";\n\n const inlined = inlineMarkdownToHtml(text);\n\n // Backend block templates (e.g. price snapshot .mgrid) must not be wrapped in <p>\n // or have \\n → <br>; that breaks display:grid and card layout.\n if (/<div[\\s>]/i.test(inlined)) {\n return DOMPurify.sanitize(stripCardDateTime(inlined), SANITIZE_CFG);\n }\n\n // Split on blank lines into paragraphs, then within each paragraph turn \\n into <br>.\n const paragraphs = inlined\n .split(/\\n{2,}/)\n .map((para) => para.replace(/\\n/g, \"<br>\"))\n .filter((p) => p.length > 0);\n\n const html = paragraphs.length > 1\n ? paragraphs.map((p) => `<p>${p}</p>`).join(\"\")\n : paragraphs[0] ?? \"\";\n\n return DOMPurify.sanitize(stripCardDateTime(html), SANITIZE_CFG);\n}\n","import type { Chip as ChipType, Message } from \"../types\";\nimport { ChipRow } from \"./ChipRow\";\nimport { renderMarkdown } from \"../utils/markdown\";\nimport styles from \"../styles/chat.module.css\";\n\nconst ROOT_MENU_CHIP_IDS = new Set([\n \"stock_analysis\", \"stock_discovery\", \"new_listings\", \"portfolio_risk\",\n \"market_forecast\", \"crypto\", \"tradable_picks\", \"peer_compare\",\n]);\n\nconst MENU_SUBTITLES: Record<string, string> = {\n stock_analysis: \"Fundamental & technical\",\n stock_discovery: \"Find promising stocks\",\n new_listings: \"Track IPOs & new stocks\",\n portfolio_risk: \"Analyze your portfolio\",\n market_forecast: \"Outlook & key events\",\n crypto: \"BTC, ETH & trends\",\n tradable_picks: \"Short-term setups\",\n peer_compare: \"Compare peer stocks\",\n};\n\nconst MENU_ICON_KEY: Record<string, string> = {\n stock_analysis: \"menuIconGreen\",\n stock_discovery: \"menuIconBlue\",\n new_listings: \"menuIconLeaf\",\n portfolio_risk: \"menuIconRed\",\n market_forecast: \"menuIconOrange\",\n crypto: \"menuIconGold\",\n tradable_picks: \"menuIconTeal\",\n peer_compare: \"menuIconPurple\",\n};\n\n/** Inline SVG icons for the main-menu grid — paths copied from\n * wealth-alpha-final.html `.cmd .ico svg` (24×24, white stroke). */\nconst MENU_ICON_SVG: Record<string, string> = {\n stock_analysis: ' <path d=\"M4 16L9 11L13 15L20 8\" /> <path d=\"M20 8V13\" /> <path d=\"M20 8H15\" />',\n stock_discovery: '<circle cx=\"11\" cy=\"11\" r=\"7\"/><path d=\"m21 21-4.3-4.3\"/>',\n new_listings: '<rect x=\"5\" y=\"5\" width=\"14\" height=\"14\" rx=\"3\"/><path d=\"M12 8v8\"/> <path d=\"M8 12h8\"/>',\n portfolio_risk: '<path d=\"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z\"/>',\n market_forecast: '<path d=\"M13 2 4 14h7l-1 8 9-12h-7l1-8Z\"/>',\n crypto: '<path d=\"M4 20V10M10 20V4M16 20v-7M22 20v-4\"/>',\n tradable_picks: '<circle cx=\"12\" cy=\"12\" r=\"9\"/><circle cx=\"12\" cy=\"12\" r=\"5\"/><circle cx=\"12\" cy=\"12\" r=\"1.5\"/>',\n peer_compare: '<path d=\"M12 3v18\"/><path d=\"M5 8l-3 6h6z\"/><path d=\"M19 8l-3 6h6z\"/>',\n};\n\nfunction isRootMenuChips(chips: ChipType[]): boolean {\n // The welcome \"command grid\" should render ONLY when this is the pure main\n // menu — i.e. every chip is a root command. A results list (stock tickers +\n // a single \"Tradeable candidate\"/\"Main menu\" nav chip) must stay as normal\n // chips, not flip into the big grid.\n return chips.length > 0 && chips.every((c) => ROOT_MENU_CHIP_IDS.has(c.id));\n}\n\ninterface MessageBubbleProps {\n message: Message;\n onChipClick: (chip: ChipType) => void;\n}\n\nexport function MessageBubble({ message, onChipClick }: MessageBubbleProps) {\n const isBot = message.role === \"bot\";\n // Card responses are block HTML (start with <div>). They carry their own\n // background/border, so render them in a \"bare\" bubble — no lavender frame,\n // padding or radius. Plain-text/list replies keep the normal bot bubble.\n const isCard = isBot && message.content.includes(\"<div\");\n const bubbleClass = isBot\n ? `${styles.bubble} ${isCard ? styles.bubbleCard : styles.bubbleBot}`\n : `${styles.bubble} ${styles.bubbleUser}`;\n\n const handleMarkdownClick = (e: React.MouseEvent<HTMLDivElement>) => {\n const anchor = (e.target as HTMLElement).closest(\"a\");\n if (!anchor?.href) return;\n e.preventDefault();\n window.location.assign(anchor.href);\n };\n\n const chips = message.chips ?? [];\n const showMenuGrid = isBot && message.chipsActive && isRootMenuChips(chips);\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\" }}>\n <div className={bubbleClass}>\n {isBot ? (\n <div\n className={styles.markdown}\n dangerouslySetInnerHTML={{ __html: renderMarkdown(message.content) }}\n onClick={handleMarkdownClick}\n />\n ) : (\n message.content\n )}\n </div>\n {showMenuGrid ? (\n <div className={styles.menuGrid}>\n {chips.map((chip) => {\n const iconKey = MENU_ICON_KEY[chip.id];\n const iconClass = (iconKey && styles[iconKey]) || \"\";\n const svgIcon = MENU_ICON_SVG[chip.id];\n return (\n <button\n key={chip.id}\n type=\"button\"\n className={styles.menuItem}\n onClick={() => onChipClick(chip)}\n >\n <div className={`${styles.menuItemIcon} ${iconClass}`}>\n {svgIcon ? (\n <svg\n className={styles.menuItemSvg}\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n dangerouslySetInnerHTML={{ __html: svgIcon }}\n />\n ) : (\n <span aria-hidden=\"true\">{chip.icon}</span>\n )}\n </div>\n <div className={styles.menuItemTitle}>{chip.label}</div>\n <div className={styles.menuItemSub}>{MENU_SUBTITLES[chip.id] ?? \"\"}</div>\n </button>\n );\n })}\n </div>\n ) : isBot && chips.length > 0 ? (\n <ChipRow\n chips={chips}\n disabled={!message.chipsActive}\n onClick={onChipClick}\n />\n ) : null}\n </div>\n );\n}\n","import styles from \"../styles/chat.module.css\";\n\nexport function TypingIndicator() {\n return (\n <div className={styles.typing} aria-live=\"polite\" aria-label=\"Assistant is typing\">\n <span className={styles.typingDot} />\n <span className={styles.typingDot} />\n <span className={styles.typingDot} />\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport type { Chip as ChipType, Message } from \"../types\";\nimport { AuthGate } from \"./AuthGate\";\nimport { MessageBubble } from \"./MessageBubble\";\nimport { TypingIndicator } from \"./TypingIndicator\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChatBodyProps {\n isLoggedIn: boolean;\n loading: boolean;\n messages: Message[];\n isTyping: boolean;\n brandName: string;\n loginUrl: string;\n error: string | null;\n onChipClick: (chip: ChipType) => void;\n onLoginClick?: () => void;\n}\n\nexport function ChatBody({\n isLoggedIn,\n loading,\n messages,\n isTyping,\n brandName,\n loginUrl,\n error,\n onChipClick,\n onLoginClick,\n}: ChatBodyProps) {\n const endRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n endRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages.length, isTyping]);\n\n if (loading) {\n return (\n <div className={styles.body}>\n <TypingIndicator />\n </div>\n );\n }\n\n if (!isLoggedIn) {\n return (\n <div className={styles.body}>\n <AuthGate\n brandName={brandName}\n loginUrl={loginUrl}\n onLoginClick={onLoginClick}\n />\n </div>\n );\n }\n\n return (\n <div className={styles.body}>\n {messages.map((m) => (\n <MessageBubble key={m.id} message={m} onChipClick={onChipClick} />\n ))}\n {isTyping ? <TypingIndicator /> : null}\n {error ? <div className={styles.errorBanner}>{error}</div> : null}\n <div ref={endRef} />\n </div>\n );\n}\n","import styles from \"../styles/chat.module.css\";\nimport { formatCountdown } from \"../utils/time\";\n\ninterface ChatHeaderProps {\n brandName: string;\n remainingMs: number;\n showCountdown: boolean;\n onClose: () => void;\n onClear?: () => void;\n}\n\nexport function ChatHeader({\n brandName,\n remainingMs,\n showCountdown,\n onClose,\n onClear,\n}: ChatHeaderProps) {\n return (\n <div className={styles.header}>\n <div>\n <div className={styles.headerTitle}>{brandName}</div>\n {/* {showCountdown && remainingMs > 0 ? (\n <div className={styles.headerMeta}>Session: {formatCountdown(remainingMs)}</div>\n ) : null} */}\n </div>\n <div className={styles.headerActions}>\n {onClear ? (\n <button\n type=\"button\"\n className={styles.iconButton}\n onClick={onClear}\n aria-label=\"Clear conversation\"\n title=\"Clear conversation\"\n >\n ↺\n </button>\n ) : null}\n <button\n type=\"button\"\n className={styles.iconButton}\n onClick={onClose}\n aria-label=\"Close chat\"\n title=\"Close\"\n >\n ✕\n </button>\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface ChatInputProps {\n disabled?: boolean;\n placeholder?: string;\n onSend: (text: string) => void;\n}\n\nexport function ChatInput({ disabled, placeholder, onSend }: ChatInputProps) {\n const [value, setValue] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (!disabled) {\n inputRef.current?.focus();\n }\n }, [disabled]);\n\n const submit = () => {\n const trimmed = value.trim();\n if (!trimmed || disabled) return;\n onSend(trimmed);\n setValue(\"\");\n inputRef.current?.focus();\n };\n\n return (\n <div className={styles.input}>\n <input\n ref={inputRef}\n type=\"text\"\n className={styles.inputBox}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n }}\n disabled={disabled}\n placeholder={placeholder ?? \"Type a message…\"}\n aria-label=\"Message input\"\n />\n <button\n type=\"button\"\n className={styles.sendButton}\n onClick={submit}\n disabled={disabled || value.trim().length === 0}\n >\n Send\n </button>\n </div>\n );\n}\n","import type { ChatPosition } from \"../types\";\nimport styles from \"../styles/chat.module.css\";\n\ninterface FloatingButtonProps {\n position: ChatPosition;\n onClick: () => void;\n brandColor?: string;\n showPopup?: boolean;\n popupMessage?: string;\n onPopupDismiss?: () => void;\n}\n\nexport function FloatingButton({ position, onClick, brandColor, showPopup, popupMessage, onPopupDismiss }: FloatingButtonProps) {\n const posClass = position === \"bottom-left\" ? styles.positionLeft : styles.positionRight;\n const popupPosClass = position === \"bottom-left\" ? styles.popupBubbleLeft : styles.popupBubbleRight;\n return (\n <>\n {showPopup && popupMessage ? (\n <div\n className={`${styles.popupBubble} ${popupPosClass}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {popupMessage}\n <button\n type=\"button\"\n className={styles.popupDismiss}\n onClick={onPopupDismiss}\n aria-label=\"Dismiss greeting\"\n >\n ✕\n </button>\n </div>\n ) : null}\n <button\n type=\"button\"\n className={`${styles.floatingButton} ${posClass}`}\n onClick={onClick}\n aria-label=\"Open chat\"\n style={brandColor ? { background: brandColor } : undefined}\n >\n 💬\n </button>\n </>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAuth } from \"../hooks/useAuth\";\nimport { useChat } from \"../hooks/useChat\";\nimport { useChip } from \"../hooks/useChip\";\nimport { useSession } from \"../hooks/useSession\";\nimport type { Chip, Message, WealthChatProps } from \"../types\";\nimport { DEFAULT_SESSION_TTL_SECONDS } from \"../utils/session\";\nimport { ChatBody } from \"./ChatBody\";\nimport { ChatHeader } from \"./ChatHeader\";\nimport { ChatInput } from \"./ChatInput\";\nimport { FloatingButton } from \"./FloatingButton\";\nimport styles from \"../styles/chat.module.css\";\n\nconst DEFAULT_BRAND_NAME = \"Wealth Alpha AI\";\nconst DEFAULT_BRAND_COLOR = \"#1a2d5a\";\nconst DEFAULT_AUTH_CHECK = \"/me\";\nconst DEFAULT_GREETING = \"Hi! I'm your Wealth Alpha AI assistant. How can I help you?\";\n\nconst CTA_LINE =\n \"Select a quick command below\";\n\n/** Opens file picker in-widget; must match backend PORTFOLIO_CSV_PICK_CHIP.id */\nconst PORTFOLIO_CSV_CHIP_ID = \"__portfolio_csv_upload\";\n/** Opens pricing page; must match backend UPGRADE_PREMIUM_CHIP.id */\nconst UPGRADE_PREMIUM_CHIP_ID = \"__upgrade_premium__\";\n\nfunction resolvePricingUrl(upgradeUrl?: string): string {\n if (upgradeUrl) return upgradeUrl;\n if (typeof window !== \"undefined\") {\n return `${window.location.origin}/pricing`;\n }\n return \"\";\n}\n\nfunction buildWelcome(name: string | undefined, plan: string | undefined): string {\n const greeting = name\n ? `Welcome back, ${name}! You have ${plan ? plan : \"Premium\"} access.`\n : `Welcome! You have ${plan ? plan : \"Premium\"} access.`;\n return `${greeting}\\n\\n${CTA_LINE}`;\n}\n\nexport function WealthChat(props: WealthChatProps) {\n const {\n apiBase,\n authCheck = DEFAULT_AUTH_CHECK,\n loginUrl,\n sessionTTL = DEFAULT_SESSION_TTL_SECONDS,\n welcomeMessage,\n brandName = DEFAULT_BRAND_NAME,\n brandColor = DEFAULT_BRAND_COLOR,\n position = \"bottom-right\",\n defaultOpen = false,\n showCountdown = true,\n greetingMessage = DEFAULT_GREETING,\n onLogin,\n onLogout,\n onSessionExpire,\n onError,\n } = props;\n\n const [mounted, setMounted] = useState(false);\n const [open, setOpen] = useState(defaultOpen);\n const [showPopup, setShowPopup] = useState(false);\n const popupShownRef = useRef(defaultOpen);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n // Load the widget fonts (Manrope + Sora) the same way the HTML prototype does\n // — via a <link> in <head>. CSS @import is unreliable once the bundled\n // stylesheet is merged into the host app (browsers ignore non-leading @import),\n // so inject the link at runtime to guarantee the fonts render everywhere.\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const id = \"wac-google-fonts\";\n if (document.getElementById(id)) return;\n const link = document.createElement(\"link\");\n link.id = id;\n link.rel = \"stylesheet\";\n link.href =\n \"https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@600;700;800&display=swap\";\n document.head.appendChild(link);\n }, []);\n\n useEffect(() => {\n if (!mounted || open || popupShownRef.current) return;\n const timer = setTimeout(() => {\n setShowPopup(true);\n popupShownRef.current = true;\n }, 1000);\n return () => clearTimeout(timer);\n }, [mounted, open]);\n\n const {\n session,\n remainingMs,\n setHistory,\n touch,\n clear: clearSessionState,\n } = useSession({\n ttlSeconds: sessionTTL,\n onExpire: onSessionExpire,\n });\n\n const { isLoggedIn, user, loading: authLoading } = useAuth({\n apiBase,\n authCheck,\n enabled: mounted && open,\n onError,\n });\n\n const handleAuthExpired = useCallback(() => {\n clearSessionState();\n onSessionExpire?.();\n }, [clearSessionState, onSessionExpire]);\n\n const handleHistoryChange = useCallback(\n (history: Message[]) => {\n if (!session) return;\n setHistory(history);\n },\n [session, setHistory],\n );\n\n const csvFileRef = useRef<HTMLInputElement>(null);\n\n const {\n state: chatState,\n sendText,\n uploadCsv,\n appendBotResponse,\n appendUserMessage,\n deactivatePriorChips,\n setTyping,\n loadHistory,\n clear: clearChat,\n } = useChat({\n apiBase,\n sessionId: session?.sessionId ?? null,\n initialMessages: session?.history,\n onHistoryChange: handleHistoryChange,\n onAuthExpired: handleAuthExpired,\n onError,\n });\n\n const { callChip } = useChip({\n apiBase,\n sessionId: session?.sessionId ?? null,\n onAuthExpired: handleAuthExpired,\n onError,\n });\n\n const welcomeShownRef = useMemo(() => ({ shown: false }), []);\n\n useEffect(() => {\n if (!isLoggedIn || !open) return;\n if (chatState.messages.length > 0) return;\n if (welcomeShownRef.shown) return;\n welcomeShownRef.shown = true;\n const messageText =\n welcomeMessage ??\n user?.welcomeMessage ??\n buildWelcome(user?.name, user?.plan);\n appendBotResponse({\n message: messageText,\n chips: user?.rootChips ?? [],\n sessionId: session?.sessionId ?? \"\",\n endOfFlow: false,\n });\n onLogin?.();\n }, [isLoggedIn, open, chatState.messages.length, welcomeMessage, session, user, appendBotResponse, onLogin, welcomeShownRef]);\n\n const handleChipClick = useCallback(\n async (chip: Chip) => {\n touch();\n deactivatePriorChips();\n\n if (chip.id === PORTFOLIO_CSV_CHIP_ID) {\n appendUserMessage(chip.label);\n csvFileRef.current?.click();\n return;\n }\n\n if (chip.id === UPGRADE_PREMIUM_CHIP_ID) {\n appendUserMessage(chip.label);\n const pricingUrl = resolvePricingUrl(user?.upgradeUrl);\n if (pricingUrl && typeof window !== \"undefined\") {\n window.location.assign(pricingUrl);\n }\n return;\n }\n\n appendUserMessage(chip.label);\n setTyping(true);\n try {\n const resp = await callChip(chip);\n if (!resp) return;\n const redirectUrl = resp.metadata?.redirectUrl;\n if (typeof redirectUrl === \"string\" && redirectUrl && typeof window !== \"undefined\") {\n window.location.assign(redirectUrl);\n return;\n }\n appendBotResponse(resp);\n } finally {\n setTyping(false);\n }\n },\n [touch, deactivatePriorChips, appendUserMessage, callChip, setTyping, appendBotResponse, user?.upgradeUrl],\n );\n\n const handleCsvFileSelected = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = \"\";\n if (file) {\n touch();\n void uploadCsv(file);\n }\n },\n [touch, uploadCsv],\n );\n\n const handleSend = useCallback(\n (text: string) => {\n touch();\n void sendText(text);\n },\n [touch, sendText],\n );\n\n const handleFloatingButtonClick = useCallback(() => {\n setOpen(true);\n setShowPopup(false);\n }, []);\n\n const handleClose = useCallback(() => setOpen(false), []);\n\n const handleClear = useCallback(() => {\n clearChat();\n welcomeShownRef.shown = false;\n setHistory([]);\n }, [clearChat, setHistory, welcomeShownRef]);\n\n const handleLoginClick = useCallback(() => {\n if (typeof window !== \"undefined\") {\n window.location.href = loginUrl;\n }\n }, [loginUrl]);\n\n if (!mounted) return null;\n\n const rootStyle = {\n [\"--wac-brand\" as string]: brandColor,\n } as React.CSSProperties;\n\n return (\n <div className={styles.root} style={rootStyle}>\n {!open ? (\n <FloatingButton\n position={position}\n onClick={handleFloatingButtonClick}\n brandColor={brandColor}\n showPopup={showPopup}\n popupMessage={greetingMessage}\n onPopupDismiss={() => setShowPopup(false)}\n />\n ) : null}\n {open ? (\n <div\n className={`${styles.widget} ${position === \"bottom-left\" ? styles.positionLeft : styles.positionRight}`}\n >\n <ChatHeader\n brandName={brandName}\n remainingMs={remainingMs}\n showCountdown={showCountdown && isLoggedIn}\n onClose={handleClose}\n onClear={isLoggedIn ? handleClear : undefined}\n />\n <ChatBody\n isLoggedIn={isLoggedIn}\n loading={authLoading}\n messages={chatState.messages}\n isTyping={chatState.isTyping}\n brandName={brandName}\n loginUrl={loginUrl}\n error={chatState.error}\n onChipClick={handleChipClick}\n onLoginClick={handleLoginClick}\n />\n <input\n ref={csvFileRef}\n type=\"file\"\n accept=\".csv,text/csv\"\n className={styles.hiddenFileInput}\n onChange={handleCsvFileSelected}\n aria-hidden\n tabIndex={-1}\n />\n {isLoggedIn ? (\n <ChatInput\n disabled={chatState.isTyping}\n onSend={handleSend}\n placeholder=\"Type a message…\"\n />\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n"]}