@relaya-chat/react 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/AdminPanel-CBs17LkG.js +3159 -0
- package/dist/AdminPanel-DqI4RFt9.cjs +1 -0
- package/dist/admin.cjs +1 -0
- package/dist/admin.js +2 -0
- package/dist/index.cjs +1 -0
- package/dist/index.js +3224 -0
- package/dist/relaya.css +2 -0
- package/package.json +54 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("react");c=s(c,1);let l=require("react/jsx-runtime");var u={READ:`chat.read`,POST:`chat.post`,EDIT_OWN:`chat.edit_own`,DELETE_OWN:`chat.delete_own`,DELETE_ANY:`chat.delete_any`,REPORT:`chat.report`,BAN_USER:`chat.ban_user`,MANAGE_ROLES:`chat.manage_roles`,MENTION_CHANNEL:`chat.mention_channel`},d=class{baseUrl;getToken;constructor(e,t){this.baseUrl=e,this.getToken=t}authHeaders(){let e=this.getToken();return e?{Authorization:`Bearer ${e}`}:{}}async request(e,t,n){let r=`${this.baseUrl}${t}`,i={...this.authHeaders()};n!==void 0&&(i[`Content-Type`]=`application/json`);let a=await fetch(r,{method:e,headers:i,body:n===void 0?void 0:JSON.stringify(n)});if(a.status!==204){if(!a.ok){let e={};try{e=await a.json()}catch{}let t=e?.error;throw{status:a.status,code:(typeof t==`object`?t?.code:void 0)??`API_ERROR`,message:(typeof t==`object`?t?.message:t)??a.statusText}}return a.json()}}async parseResponse(e){if(e.status!==204){if(!e.ok){let t={};try{t=await e.json()}catch{}let n=t?.error;throw{status:e.status,code:(typeof n==`object`?n?.code:void 0)??`API_ERROR`,message:(typeof n==`object`?n?.message:n)??e.statusText}}return e.json()}}async login(e,t){return this.request(`POST`,`/auth/login`,{email:e,stationSlug:t})}async requestCode(e,t){return this.request(`POST`,`/auth/request-code`,{email:e,stationSlug:t})}async verifyCode(e,t,n){return this.request(`POST`,`/auth/verify-code`,{pendingId:e,code:t,stationSlug:n})}async verify(e,t){return this.request(`GET`,`/auth/verify?token=${encodeURIComponent(e)}&station=${encodeURIComponent(t)}`)}async refresh(e){return this.request(`POST`,`/auth/refresh`,{refreshToken:e})}async getStation(e){return this.request(`GET`,`/api/chat/stations/${encodeURIComponent(e)}`)}async getMessages(e,t){let n=new URLSearchParams;t?.before&&n.set(`before`,t.before),t?.after&&n.set(`after`,t.after),t?.limit!==void 0&&n.set(`limit`,String(t.limit));let r=n.toString()?`?${n.toString()}`:``;return this.request(`GET`,`/api/chat/${e}/messages${r}`)}async deleteMessage(e,t){return this.request(`DELETE`,`/api/chat/${e}/messages/${t}`)}async editMessage(e,t,n){return this.request(`PATCH`,`/api/chat/${e}/messages/${t}`,{content:n})}async createReport(e,t,n,r){return this.request(`POST`,`/api/chat/${e}/messages/${t}/report`,{reason:n,details:r})}async getReports(e,t){let n=new URLSearchParams;t?.status&&n.set(`status`,t.status),t?.limit!==void 0&&n.set(`limit`,String(t.limit)),t?.offset!==void 0&&n.set(`offset`,String(t.offset));let r=n.toString()?`?${n.toString()}`:``;return this.request(`GET`,`/api/chat/${e}/reports${r}`)}async updateReport(e,t,n){return this.request(`PATCH`,`/api/chat/${e}/reports/${t}`,n)}async createBan(e,t,n){return this.request(`POST`,`/api/chat/${e}/bans`,{userId:t,...n})}async liftBan(e,t){return this.request(`DELETE`,`/api/chat/${e}/bans/${t}`)}async getBans(e,t=!0){let n=t?`?active=true`:``;return this.request(`GET`,`/api/chat/${e}/bans${n}`)}async getMembers(e){return this.request(`GET`,`/api/chat/${e}/members`)}async getMembersAdmin(e){return this.request(`GET`,`/api/chat/${e}/members/admin`)}async updateMemberRole(e,t,n){return this.request(`PATCH`,`/api/chat/${e}/members/${t}/roles`,{roleId:n})}async patchMemberRoles(e,t,n){return this.request(`PATCH`,`/api/chat/${e}/members/${t}/roles`,n)}async getMe(e){return this.request(`GET`,`/api/chat/${e}/me`)}async updateChatName(e,t){return this.request(`PATCH`,`/api/chat/${e}/me`,{chatName:t})}async getModerationConfig(e){return this.request(`GET`,`/api/chat/${e}/moderation/config`)}async updateModerationConfig(e,t){return this.request(`PATCH`,`/api/chat/${e}/moderation/config`,t)}async getPresenceConfig(e){return this.request(`GET`,`/api/chat/${e}/presence/config`)}async updatePresenceConfig(e,t){return this.request(`PATCH`,`/api/chat/${e}/presence/config`,t)}async getStickers(e){let t=await this.request(`GET`,`/api/chat/${e}/stickers`);return this.baseUrl&&(t.stickers=t.stickers.map(e=>e.url.startsWith(`/`)?{...e,url:`${this.baseUrl}${e.url}`}:e)),t}async uploadSticker(e,t,n){let r=await fetch(`${this.baseUrl}/api/chat/${e}/stickers/upload`,{method:`POST`,headers:{...this.authHeaders(),"Content-Type":t.type||`application/octet-stream`,"X-Sticker-Filename":encodeURIComponent(n)},body:t});return this.parseResponse(r)}async updateStickerManifest(e,t){return this.request(`PUT`,`/api/chat/${e}/stickers/manifest`,{stickers:t})}async deleteSticker(e,t){return this.request(`DELETE`,`/api/chat/${e}/stickers/${encodeURIComponent(t)}`)}async getSounds(e){return this.request(`GET`,`/api/chat/${encodeURIComponent(e)}/sounds`)}async getSpaceTheme(e){return this.request(`GET`,`/api/chat/${e}/theme`)}async saveSpaceTheme(e,t){return this.request(`PUT`,`/api/chat/${e}/theme`,t)}};function f(){let e=new URLSearchParams(window.location.search),t=e.get(`space`)??e.get(`station`)??``,n=e.get(`theme`);return{spaceSlug:t,theme:n===`dark`?`dark`:n===`light`?`light`:window.matchMedia?.(`(prefers-color-scheme: dark)`).matches?`dark`:`light`,magicLinkToken:e.get(`token`),embed:e.get(`embed`)===`true`,admin:e.get(`admin`)===`true`,managed:e.get(`managed`)===`host`}}var p=typeof window<`u`?f():{spaceSlug:``,theme:`light`,magicLinkToken:null,embed:!1,admin:!1,managed:!1};function m(){let e=new URL(window.location.href);e.searchParams.delete(`token`),window.history.replaceState({},``,e.toString())}function h(e,t){let n=window.location.protocol===`https:`?`wss:`:`ws:`,r=t?`token=${encodeURIComponent(t)}&`:``;return`${n}//${window.location.port===`5173`&&window.location.hostname!==`localhost`?`${window.location.hostname}:9000`:window.location.host}/ws?${r}station=${encodeURIComponent(e)}`}var g=`relaya_refresh_token`;function _(e){try{localStorage.setItem(g,e)}catch{}}function v(){try{return localStorage.getItem(g)}catch{return null}}function y(){try{localStorage.removeItem(g)}catch{}}function b(e){try{let[,t]=e.split(`.`),n=atob(t.replace(/-/g,`+`).replace(/_/g,`/`));return JSON.parse(n).exp??null}catch{return null}}var x=null,S=new Map;function C(e,t){let n=`${t}:${e}`,r=S.get(n);if(r)return r;let i=fetch(`/auth/verify?token=${encodeURIComponent(e)}&station=${encodeURIComponent(t)}`).then(e=>e.ok?e.json():Promise.reject());return S.set(n,i),i.finally(()=>{window.setTimeout(()=>{S.delete(n)},300*1e3)}).catch(()=>{}),i}function w(e={}){let t=e.spaceSlug??p.spaceSlug,n=e.initialToken??null,r=e.manageOwnRefreshToken??!0,i=(0,c.useRef)(e.onSessionEnded);i.current=e.onSessionEnded;let[a,o]=(0,c.useState)({status:`loading`,user:null,token:null,station:null,stationSlug:t,error:null}),s=(0,c.useRef)(null),l=(0,c.useCallback)(()=>s.current,[]),u=(0,c.useRef)(null),f=(0,c.useRef)(null),m=(0,c.useRef)(new d(``,l)).current,h=(0,c.useRef)(!1),g=(0,c.useCallback)(()=>{s.current=null,u.current=null,r&&y(),f.current!==null&&(clearTimeout(f.current),f.current=null),o(e=>({...e,status:`anonymous`,token:null,user:null,station:null,stationSlug:t}))},[t,r]),S=(0,c.useCallback)(e=>{f.current!==null&&(clearTimeout(f.current),f.current=null);let t=b(e);if(!t)return;let n=Math.max(0,t*1e3-Date.now()-120*1e3);f.current=setTimeout(()=>{let e=u.current;e&&(x||=m.refresh(e).finally(()=>{x=null}),x.then(e=>{s.current=e.accessToken,u.current=e.refreshToken,r&&_(e.refreshToken),o(t=>t.status===`authenticated`?{...t,token:e.accessToken}:t),S(e.accessToken)}).catch(e=>{typeof e==`object`&&e&&`status`in e&&(e.status===401||e.status===403)?(g(),i.current?.(`refresh-failed`)):setTimeout(()=>{let e=u.current;e&&m.refresh(e).then(e=>{s.current=e.accessToken,u.current=e.refreshToken,r&&_(e.refreshToken),o(t=>t.status===`authenticated`?{...t,token:e.accessToken}:t),S(e.accessToken)}).catch(()=>{g(),i.current?.(`refresh-failed`)})},1e4)}))},n)},[m,g,r]),w=(0,c.useCallback)(async(e,n)=>{s.current=e,u.current=n,r&&_(n),S(e);try{let n=await m.getMe(t).catch(e=>{throw process.env.NODE_ENV!==`production`&&console.warn(`[RelayaAuth] getMe failed during token apply`,{spaceSlug:t,err:e}),e}),r=await m.getStation(t).catch(e=>{throw process.env.NODE_ENV!==`production`&&console.warn(`[RelayaAuth] getStation failed during token apply`,{spaceSlug:t,err:e}),e});o({status:`authenticated`,user:{id:n.userId,displayName:n.displayName,avatarUrl:null,permissions:n.permissions,roles:n.roles,chatName:n.chatName},token:e,station:{id:r.id,name:r.name,slug:r.slug},stationSlug:r.slug,error:null})}catch(e){process.env.NODE_ENV!==`production`&&console.warn(`[RelayaAuth] Falling back to anonymous after token apply failure`,{spaceSlug:t,err:e}),g()}},[m,t,S,g,r]),T=(0,c.useCallback)(e=>{w(e.accessToken,e.refreshToken)},[w]);(0,c.useEffect)(()=>{if(h.current)return;h.current=!0;let e=new URLSearchParams(window.location.search),i=e.get(`token`),a=n??i,s=e.get(`station`)||t;if(a){if(i){let e=new URL(window.location.href);e.searchParams.delete(`token`),window.history.replaceState({},``,e.toString())}C(a,s).then(e=>{w(e.accessToken,e.refreshToken)}).catch(()=>g())}else if(r){let e=v();e?(x||=m.refresh(e).finally(()=>{x=null}),x.then(e=>{w(e.accessToken,e.refreshToken)}).catch(e=>{typeof e==`object`&&e&&`status`in e&&(e.status===401||e.status===403)?(y(),o(e=>({...e,status:`anonymous`,stationSlug:t}))):setTimeout(()=>{let e=v();if(!e){o(e=>({...e,status:`anonymous`,stationSlug:t}));return}m.refresh(e).then(e=>void w(e.accessToken,e.refreshToken)).catch(()=>{y(),o(e=>({...e,status:`anonymous`,stationSlug:t}))})},1e4)})):o(e=>({...e,status:`anonymous`,stationSlug:t}))}else o(e=>({...e,status:`anonymous`,stationSlug:t}));return()=>{f.current!==null&&clearTimeout(f.current)}},[]);let E=(0,c.useCallback)(async e=>{o(e=>({...e,error:null}));let n=`${window.location.origin}/auth/popup?station=${encodeURIComponent(t)}`;if(!window.open(n,`relaya-auth`,`width=480,height=600,left=200,top=100`)){o(e=>({...e,error:`Please allow popups for this site to sign in.`}));return}let r=e=>{if(e.origin!==window.location.origin||e.data?.type!==`relaya:auth`)return;window.removeEventListener(`message`,r);let{accessToken:t,refreshToken:n}=e.data;w(t,n)};window.addEventListener(`message`,r)},[w,t]),D=(0,c.useCallback)(()=>{let e=u.current??(r?v():null);g(),e&&fetch(`/auth/logout`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({refreshToken:e})}).catch(()=>{}),i.current?.(`logout`)},[g,r]);return{...a,login:E,logout:D,getToken:l,onOtpVerified:T}}var T=[`--relaya-color-bg`,`--relaya-color-message-bg`,`--relaya-color-message-own-bg`,`--relaya-color-text`,`--relaya-color-text-secondary`,`--relaya-color-input-bg`,`--relaya-color-input-text`,`--relaya-color-btn-bg`,`--relaya-color-btn-text`,`--relaya-color-name-mod`,`--relaya-color-link`,`--relaya-color-link-active`],E={light:{},dark:{}};function D(e,t){let n=document.documentElement;T.forEach(e=>n.style.removeProperty(e));let r=e[t]??{};Object.entries(r).forEach(([e,t])=>{n.style.setProperty(e,t)})}function O(e,t){let[n,r]=(0,c.useState)(E),[i,a]=(0,c.useState)(!1),[o,s]=(0,c.useState)(!1),[l,u]=(0,c.useState)(null),f=(0,c.useRef)(new d(``,t));return{theme:n,loading:i,saving:o,error:l,loadTheme:(0,c.useCallback)(async()=>{a(!0),u(null);try{r(await f.current.getSpaceTheme(e))}catch(e){u(e?.message??`Failed to load theme`)}finally{a(!1)}},[e]),saveTheme:(0,c.useCallback)(async(t,n)=>{s(!0),u(null);try{let i=await f.current.saveSpaceTheme(e,t);r(i),D(i,n)}catch(e){u(e?.message??`Failed to save theme`)}finally{s(!1)}},[e]),resetTheme:(0,c.useCallback)(async t=>{s(!0),u(null);try{await f.current.saveSpaceTheme(e,E),r(E),D(E,t)}catch(e){u(e?.message??`Failed to reset theme`)}finally{s(!1)}},[e])}}function k(e,t,n){let[r,i]=(0,c.useState)({bans:[],loading:!1,lifting:null,error:null}),a=t?.permissions.includes(u.BAN_USER)??!1,o=(0,c.useRef)(new d(``,n)),s=(0,c.useCallback)(async()=>{if(!(!a||!e)){i(e=>({...e,loading:!0,error:null}));try{let t=(await o.current.getBans(e,!0)).bans;i(e=>({...e,bans:t,loading:!1}))}catch(e){i(t=>({...t,loading:!1,error:e?.message??`Failed to load bans`}))}}},[a,e]),l=(0,c.useCallback)(async t=>{if(a){i(e=>({...e,lifting:t,error:null}));try{await o.current.liftBan(e,t),i(e=>({...e,lifting:null})),await s()}catch(e){throw i(t=>({...t,lifting:null,error:e?.message??`Failed to lift ban`})),e}}},[a,e,s]);return{...r,loadBans:s,liftBan:l}}function A(e,t,n){let[r,i]=(0,c.useState)({config:null,loading:!1,saving:!1,error:null,note:null}),a=new d(``,n),o=t?.permissions.includes(u.MANAGE_ROLES)??!1,s=(0,c.useCallback)(async()=>{if(!(!o||!e)){i(e=>({...e,loading:!0,error:null}));try{let t=await a.getModerationConfig(e);i(e=>({...e,config:t.config,note:t.note,loading:!1}))}catch(e){i(t=>({...t,loading:!1,error:e?.message??`Failed to load config`}))}}},[o,e]),l=(0,c.useCallback)(async t=>{if(!(!o||!e)){i(e=>({...e,saving:!0,error:null}));try{let n=await a.updateModerationConfig(e,t);i(e=>({...e,config:n.config,note:n.note,saving:!1}))}catch(e){i(t=>({...t,saving:!1,error:e?.message??`Failed to update config`}))}}},[o,e]);return{...r,loadConfig:s,updateConfig:l}}function j(e,t,n){let[r,i]=(0,c.useState)({reports:[],total:0,loading:!1,actioning:null,error:null,offset:0}),a=(0,c.useRef)(0),o=t?.permissions.includes(u.DELETE_ANY)??!1,s=(0,c.useRef)(new d(``,n)),l=(0,c.useCallback)(async t=>{if(!o||!e)return;let n=t===void 0?a.current:t;a.current=n,i(e=>({...e,loading:!0,error:null}));try{let t=await s.current.getReports(e,{status:`pending`,limit:20,offset:n});i(e=>({...e,reports:t.reports,total:t.total,loading:!1,offset:n}))}catch(e){i(t=>({...t,loading:!1,error:e?.message??`Failed to load reports`}))}},[o,e]),f=(0,c.useCallback)(async t=>{if(o){i(e=>({...e,actioning:t,error:null}));try{await s.current.updateReport(e,t,{status:`dismissed`}),i(e=>({...e,actioning:null})),await l()}catch(e){throw i(t=>({...t,actioning:null,error:e?.message??`Failed to dismiss report`})),e}}},[o,e,l]),p=(0,c.useCallback)(async(t,n)=>{if(o){i(e=>({...e,actioning:t,error:null}));try{try{await s.current.deleteMessage(e,n)}catch(e){if(e.status!==404)throw e}await s.current.updateReport(e,t,{status:`reviewed`}),i(e=>({...e,actioning:null})),await l()}catch(e){throw i(t=>({...t,actioning:null,error:e?.message??`Failed to delete message`})),e}}},[o,e,l]),m=(0,c.useCallback)(async(t,n,r)=>{if(o){i(e=>({...e,actioning:t,error:null}));try{try{await s.current.createBan(e,n,r)}catch(e){if(e.status!==409)throw e}await s.current.updateReport(e,t,{status:`reviewed`}),i(e=>({...e,actioning:null})),await l()}catch(e){throw i(t=>({...t,actioning:null,error:e?.message??`Failed to ban user`})),e}}},[o,e,l]);return{...r,loadReports:l,dismissReport:f,deleteMessageAndReview:p,banAndReview:m}}var M=`'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`,N=`#7391A7`,P={titleBg:N,spaceNameColor:`white`,spaceNameFontFamily:M,uiFontFamily:M,onlineTextColor:`white`,noNameTextColor:`white`,buttonBorderColor:`transparent`,buttonBg:`white`,buttonTextColor:`black`,avatarBg:N,avatarTextColor:`white`,ownMsgBg:N,ownMsgText:`white`,msgFontFamily:M},F={};function I(e){return F[e]??P}function L(e){let t=document.documentElement,n=(e,n)=>{n!==void 0&&t.style.setProperty(e,n)};n(`--sp-title-bg`,e.titleBg),n(`--sp-name-color`,e.spaceNameColor),n(`--sp-name-font`,e.spaceNameFontFamily),n(`--sp-ui-font`,e.uiFontFamily),n(`--sp-online-color`,e.onlineTextColor),n(`--sp-no-name-color`,e.noNameTextColor),n(`--sp-btn-border`,e.buttonBorderColor),n(`--sp-btn-bg`,e.buttonBg),n(`--sp-btn-text`,e.buttonTextColor),n(`--sp-avatar-bg`,e.avatarBg),n(`--sp-avatar-text`,e.avatarTextColor),n(`--sp-other-msg-bg`,e.otherMsgBg),n(`--sp-other-msg-text`,e.otherMsgText),n(`--sp-own-msg-bg`,e.ownMsgBg),n(`--sp-own-msg-text`,e.ownMsgText),n(`--sp-msg-font`,e.msgFontFamily??e.uiFontFamily),n(`--sp-msg-font-size`,e.msgFontSize),n(`--sp-time-color`,e.timeLabelColor),n(`--sp-send-btn-bg`,e.sendButtonBg),n(`--sp-send-btn-text`,e.sendButtonText)}function R(e,t,n){let r=e.findIndex(e=>e.filename===t),i=e.findIndex(e=>e.filename===n);if(r===-1||i===-1||r===i)return e;let a=[...e],[o]=a.splice(r,1);return a.splice(i,0,o),a.map((e,t)=>({...e,order:t}))}var z=[{value:``,label:`Permanent`},{value:`1h`,label:`1 hour`},{value:`24h`,label:`24 hours`},{value:`7d`,label:`7 days`},{value:`30d`,label:`30 days`}];function B(e){if(!e)return;let t=Date.now(),n={"1h":3600*1e3,"24h":1440*60*1e3,"7d":10080*60*1e3,"30d":720*60*60*1e3}[e];return n?new Date(t+n).toISOString():void 0}function V({userId:e,displayName:t,onBan:n,onClose:r}){let[i,a]=(0,c.useState)(``),[o,s]=(0,c.useState)(``),[u,d]=(0,c.useState)(!1),[f,p]=(0,c.useState)(null);async function m(){d(!0),p(null);try{await n(e,{reason:i.trim()||void 0,expiresAt:B(o)}),r()}catch(e){p(e?.message??`Failed to ban user.`),d(!1)}}return(0,l.jsx)(`div`,{className:`modal-overlay`,onClick:e=>e.target===e.currentTarget&&r(),children:(0,l.jsxs)(`div`,{className:`modal`,role:`dialog`,"aria-modal":`true`,"aria-label":`Ban user`,children:[(0,l.jsx)(`h2`,{className:`modal__title`,children:`Ban user`}),(0,l.jsxs)(`div`,{className:`modal__body`,children:[(0,l.jsxs)(`p`,{children:[`You are about to ban `,(0,l.jsx)(`strong`,{children:t}),` from this station's chat. They will be immediately disconnected and will not be able to rejoin.`]}),(0,l.jsx)(`label`,{htmlFor:`ban-duration`,children:`Duration`}),(0,l.jsx)(`select`,{id:`ban-duration`,value:o,onChange:e=>s(e.target.value),disabled:u,children:z.map(e=>(0,l.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,l.jsx)(`label`,{htmlFor:`ban-reason`,children:`Reason (optional)`}),(0,l.jsx)(`textarea`,{id:`ban-reason`,value:i,onChange:e=>a(e.target.value),placeholder:`Why is this user being banned?`,disabled:u,maxLength:500}),f&&(0,l.jsx)(`p`,{style:{color:`var(--color-danger)`,marginTop:8},children:f})]}),(0,l.jsxs)(`div`,{className:`modal__footer`,children:[(0,l.jsx)(`button`,{className:`btn btn--ghost`,onClick:r,disabled:u,children:`Cancel`}),(0,l.jsx)(`button`,{className:`btn btn--danger`,onClick:m,disabled:u,children:u?`Banning…`:`Confirm ban`})]})]})})}function H(e){return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function U(e){return e.replace(/_/g,` `)}function W({stationSlug:e,user:t,getToken:n}){let[r,i]=(0,c.useState)(!1),[a,o]=(0,c.useState)(null),{reports:s,total:d,loading:f,actioning:p,error:m,offset:h,loadReports:g,dismissReport:_,deleteMessageAndReview:v,banAndReview:y}=j(e,t,n);if((0,c.useEffect)(()=>{r&&g(0)},[r]),!t.permissions.includes(u.DELETE_ANY))return null;let b=h>0,x=h+20<d;return(0,l.jsxs)(`div`,{className:`report-review`,children:[(0,l.jsxs)(`button`,{className:`report-review__toggle`,onClick:()=>i(e=>!e),"aria-expanded":r,children:[(0,l.jsx)(`span`,{children:r?`▼`:`▶`}),(0,l.jsxs)(`span`,{children:[`Report queue`,d>0&&(0,l.jsx)(`span`,{className:`report-review__badge`,"aria-label":`${d} pending reports`,children:d})]})]}),r&&(0,l.jsxs)(`div`,{className:`report-review__panel`,children:[m&&(0,l.jsx)(`p`,{className:`report-review__error`,children:m}),f&&(0,l.jsx)(`p`,{className:`report-review__loading`,children:`Loading…`}),!f&&s.length===0&&(0,l.jsx)(`p`,{className:`report-review__empty`,children:`No pending reports. ✓`}),s.map(e=>{let t=p===e.reportId;return(0,l.jsxs)(`div`,{className:`report-card`,children:[(0,l.jsxs)(`div`,{className:`report-card__meta`,children:[(0,l.jsx)(`span`,{className:`report-card__reason`,children:U(e.reason)}),(0,l.jsx)(`span`,{className:`report-card__time`,children:H(e.createdAt)})]}),(0,l.jsx)(`div`,{className:`report-card__message`,children:e.messageIsDeleted?(0,l.jsx)(`em`,{className:`report-card__deleted`,children:`[message already deleted]`}):(0,l.jsx)(`span`,{children:e.messageContent??``})}),(0,l.jsxs)(`div`,{className:`report-card__details`,children:[(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Author:`}),` `,e.messageAuthor.displayName]}),(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Reported by:`}),` `,e.reporter.displayName]}),e.details&&(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Note:`}),` `,e.details]})]}),(0,l.jsxs)(`div`,{className:`report-card__actions`,children:[(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>_(e.reportId),disabled:t,title:`Dismiss this report — no action taken`,children:t?`…`:`Dismiss`}),!e.messageIsDeleted&&(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>v(e.reportId,e.messageId),disabled:t,title:`Delete the reported message and mark this report reviewed`,children:t?`…`:`Delete message`}),(0,l.jsx)(`button`,{className:`btn btn--danger`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>o({reportId:e.reportId,userId:e.messageAuthor.userId,displayName:e.messageAuthor.displayName}),disabled:t,title:`Ban this message's author and mark this report reviewed`,children:`Ban author`})]})]},e.reportId)}),(b||x)&&(0,l.jsxs)(`div`,{className:`report-review__pagination`,children:[(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>g(h-20),disabled:!b||f,children:`← Previous`}),(0,l.jsxs)(`span`,{className:`report-review__page-info`,children:[h+1,`–`,Math.min(h+20,d),` of `,d]}),(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>g(h+20),disabled:!x||f,children:`Next →`})]})]}),a&&(0,l.jsx)(V,{userId:a.userId,displayName:a.displayName,onBan:async(e,t)=>{await y(a.reportId,e,t)},onClose:()=>o(null)})]})}function G(e){return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function ee(e,t){return t||!e?`Permanent`:new Date(e)<new Date?`Expired`:`Expires ${G(e)}`}function te({stationSlug:e,user:t,getToken:n}){let[r,i]=(0,c.useState)(!1),{bans:a,loading:o,lifting:s,error:d,loadBans:f,liftBan:p}=k(e,t,n);return(0,c.useEffect)(()=>{r&&f()},[r]),t.permissions.includes(u.BAN_USER)?(0,l.jsxs)(`div`,{className:`ban-management`,children:[(0,l.jsxs)(`button`,{className:`ban-management__toggle`,onClick:()=>i(e=>!e),"aria-expanded":r,children:[(0,l.jsx)(`span`,{children:r?`▼`:`▶`}),(0,l.jsxs)(`span`,{children:[`Active bans`,a.length>0&&(0,l.jsx)(`span`,{className:`ban-management__badge`,"aria-label":`${a.length} active bans`,children:a.length})]})]}),r&&(0,l.jsxs)(`div`,{className:`ban-management__panel`,children:[d&&(0,l.jsx)(`p`,{className:`ban-management__error`,children:d}),o&&(0,l.jsx)(`p`,{className:`ban-management__loading`,children:`Loading…`}),!o&&a.length===0&&(0,l.jsx)(`p`,{className:`ban-management__empty`,children:`No active bans. ✓`}),a.map(e=>{let t=s===e.banId;return(0,l.jsxs)(`div`,{className:`ban-card`,children:[(0,l.jsxs)(`div`,{className:`ban-card__header`,children:[(0,l.jsx)(`span`,{className:`ban-card__user`,children:e.user.displayName}),(0,l.jsx)(`span`,{className:`ban-card__expiry${e.isPermanent?` ban-card__expiry--permanent`:``}`,children:ee(e.expiresAt,e.isPermanent)})]}),(0,l.jsxs)(`div`,{className:`ban-card__details`,children:[e.reason&&(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Reason:`}),` `,e.reason]}),(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Banned by:`}),` `,e.bannedBy.displayName]}),(0,l.jsxs)(`span`,{children:[(0,l.jsx)(`strong`,{children:`Banned at:`}),` `,G(e.createdAt)]})]}),(0,l.jsx)(`div`,{className:`ban-card__actions`,children:(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{fontSize:12,padding:`3px 10px`},onClick:()=>p(e.banId),disabled:t,title:`Remove this ban and allow the user to rejoin`,children:t?`…`:`Lift ban`})})]},e.banId)})]})]}):null}function ne(e,t,n){let[r,i]=(0,c.useState)({config:null,loading:!1,saving:!1,error:null}),a=new d(``,n),o=t?.permissions.includes(u.MANAGE_ROLES)??!1,s=(0,c.useCallback)(async()=>{if(!(!o||!e)){i(e=>({...e,loading:!0,error:null}));try{let t=await a.getPresenceConfig(e);i(e=>({...e,config:t.config,loading:!1}))}catch(e){i(t=>({...t,loading:!1,error:e?.message??`Failed to load presence config`}))}}},[o,e]),l=(0,c.useCallback)(async t=>{if(!(!o||!e)){i(e=>({...e,saving:!0,error:null}));try{let n=await a.updatePresenceConfig(e,t);i(e=>({...e,config:n.config,saving:!1}))}catch(e){i(t=>({...t,saving:!1,error:e?.message??`Failed to update presence config`}))}}},[o,e]);return{...r,loadConfig:s,updateConfig:l}}function re({stationSlug:e,user:t,getToken:n,onOpenStickerAdmin:r,onOpenThemeAdmin:i}){let[a,o]=(0,c.useState)(!1),{config:s,loading:u,saving:d,error:f,note:p,loadConfig:m,updateConfig:h}=A(e,t,n),[g,_]=(0,c.useState)(null),{config:v,loading:y,saving:b,error:x,loadConfig:S,updateConfig:C}=ne(e,t,n),[w,T]=(0,c.useState)(``);(0,c.useEffect)(()=>{a&&(!s&&!u&&m(),!v&&!y&&S())},[a]),(0,c.useEffect)(()=>{s&&!g&&_({rateLimitWindowMs:String(s.rateLimitWindowMs),rateLimitMaxMessages:String(s.rateLimitMaxMessages),duplicateWindowMs:String(s.duplicateWindowMs)})},[s]),(0,c.useEffect)(()=>{if(v&&w===``){let e=v.presenceGracePeriodMs/6e4;T(String(Number(e.toFixed(1))))}},[v]);async function E(){g&&await h({rateLimitWindowMs:parseInt(g.rateLimitWindowMs,10),rateLimitMaxMessages:parseInt(g.rateLimitMaxMessages,10),duplicateWindowMs:parseInt(g.duplicateWindowMs,10)})}async function D(){let e=parseFloat(w);isNaN(e)||e<0||e>15||await C({presenceGracePeriodMs:Math.round(e*6e4/1e3)*1e3})}return(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>o(e=>!e),children:[(0,l.jsx)(`span`,{children:a?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Moderation settings`})]}),a&&(0,l.jsxs)(`div`,{className:`admin-settings__panel`,children:[r&&(0,l.jsxs)(`div`,{className:`admin-settings__section`,children:[(0,l.jsxs)(`div`,{className:`admin-settings__section-copy`,children:[(0,l.jsx)(`strong`,{children:`Sticker library`}),(0,l.jsx)(`span`,{children:`Upload stickers, assign shortcodes, and control picker order.`})]}),(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{width:`auto`,padding:`6px 16px`},onClick:r,children:`Open sticker manager`})]}),i&&(0,l.jsxs)(`div`,{className:`admin-settings__section`,children:[(0,l.jsxs)(`div`,{className:`admin-settings__section-copy`,children:[(0,l.jsx)(`strong`,{children:`Colour theme`}),(0,l.jsx)(`span`,{children:`Customise the chat colours to match your brand.`})]}),(0,l.jsx)(`button`,{className:`btn btn--ghost`,style:{width:`auto`,padding:`6px 16px`},onClick:i,children:`Open theme editor`})]}),(0,l.jsxs)(`div`,{className:`admin-settings__notice`,children:[`⚠️ Changes apply immediately but revert to environment defaults on server restart.`,p&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`br`,{}),p]})]}),u&&(0,l.jsx)(`p`,{style:{fontSize:13,color:`var(--color-text-muted)`},children:`Loading…`}),f&&(0,l.jsx)(`p`,{style:{fontSize:13,color:`var(--color-danger)`},children:f}),g&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)(`div`,{className:`admin-settings__grid`,children:[(0,l.jsxs)(`div`,{className:`admin-settings__field`,children:[(0,l.jsx)(`label`,{htmlFor:`rl-window`,children:`Rate-limit window (ms)`}),(0,l.jsx)(`input`,{id:`rl-window`,type:`number`,min:1e3,value:g.rateLimitWindowMs,onChange:e=>_(t=>t&&{...t,rateLimitWindowMs:e.target.value})})]}),(0,l.jsxs)(`div`,{className:`admin-settings__field`,children:[(0,l.jsx)(`label`,{htmlFor:`rl-max`,children:`Max messages per window`}),(0,l.jsx)(`input`,{id:`rl-max`,type:`number`,min:1,value:g.rateLimitMaxMessages,onChange:e=>_(t=>t&&{...t,rateLimitMaxMessages:e.target.value})})]}),(0,l.jsxs)(`div`,{className:`admin-settings__field`,children:[(0,l.jsx)(`label`,{htmlFor:`dup-window`,children:`Duplicate burst window (ms)`}),(0,l.jsx)(`input`,{id:`dup-window`,type:`number`,min:0,value:g.duplicateWindowMs,onChange:e=>_(t=>t&&{...t,duplicateWindowMs:e.target.value})})]})]}),(0,l.jsx)(`button`,{className:`btn btn--primary`,style:{width:`auto`,padding:`6px 16px`},onClick:E,disabled:d,children:d?`Saving…`:`Apply changes`})]}),(0,l.jsxs)(`div`,{className:`admin-settings__divider`,style:{marginTop:20,borderTop:`1px solid var(--color-border)`,paddingTop:16},children:[(0,l.jsx)(`strong`,{style:{fontSize:13},children:`Online status grace period`}),(0,l.jsx)(`p`,{style:{fontSize:12,color:`var(--color-text-muted)`,marginTop:4,marginBottom:10},children:`How long a user stays visible in the online list after their browser disconnects. Use 0 for immediate removal. Saved to the database — persists across restarts.`}),y&&(0,l.jsx)(`p`,{style:{fontSize:13,color:`var(--color-text-muted)`},children:`Loading…`}),x&&(0,l.jsx)(`p`,{style:{fontSize:13,color:`var(--color-danger)`},children:x}),v!==null&&(0,l.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:8},children:[(0,l.jsx)(`input`,{id:`presence-grace`,type:`number`,min:0,max:15,step:.5,value:w,onChange:e=>T(e.target.value),style:{width:80}}),(0,l.jsx)(`label`,{htmlFor:`presence-grace`,style:{fontSize:13},children:`minutes`}),(0,l.jsx)(`button`,{className:`btn btn--primary`,style:{width:`auto`,padding:`6px 16px`},onClick:D,disabled:b,children:b?`Saving…`:`Save`})]})]})]})]})}var ie=2*1024*1024,K=310;function ae(e){return e.shortcode?`:${e.shortcode}:`:e.filename}async function oe(e){let t=URL.createObjectURL(e);try{let e=await new Promise((e,n)=>{let r=new Image;r.onload=()=>e(r),r.onerror=()=>n(Error(`Unable to read image dimensions`)),r.src=t});return{width:e.naturalWidth,height:e.naturalHeight}}finally{URL.revokeObjectURL(t)}}function q({stationSlug:e,user:t,getToken:n,onClose:r,onLibraryChanged:i}){let a=(0,c.useRef)(new d(``,n)).current,o=(0,c.useRef)(null),[s,f]=(0,c.useState)([]),[p,m]=(0,c.useState)(null),[h,g]=(0,c.useState)(!0),[_,v]=(0,c.useState)(!1),[y,b]=(0,c.useState)(!1),[x,S]=(0,c.useState)(null),[C,w]=(0,c.useState)(!1),[T,E]=(0,c.useState)(null),[D,O]=(0,c.useState)(null),[k,A]=(0,c.useState)(null),[j,M]=(0,c.useState)(null),N=t.permissions.includes(u.MANAGE_ROLES);async function P(){g(!0),E(null),O(null);try{let t=await a.getStickers(e);f(t.stickers??[]),m(t.quota??null),w(!1)}catch(e){E(e?.message??`Failed to load sticker library.`)}finally{g(!1)}}if((0,c.useEffect)(()=>{N&&P().catch(()=>void 0)},[N,e]),(0,c.useEffect)(()=>{if(D!==`Sticker order saved.`)return;let e=window.setTimeout(()=>{O(e=>e===`Sticker order saved.`?null:e)},1800);return()=>window.clearTimeout(e)},[D]),!N)return null;function F(){A(null),M(null)}function I(e,t){if(_||y||x){e.preventDefault();return}A(t),e.dataTransfer.effectAllowed=`move`,e.dataTransfer.setData(`text/plain`,t)}function L(e,t){!k||k===t||(e.preventDefault(),e.dataTransfer.dropEffect=`move`,j!==t&&M(t))}function z(e,t){e.preventDefault();let n=k||e.dataTransfer.getData(`text/plain`);if(!n||n===t){F();return}let r=R(s,n,t);if(r===s){F();return}f(r),w(!0),O(null),F(),V(r,`Sticker order saved.`)}function B(e,t){f(n=>n.map(n=>n.filename===e?{...n,shortcode:t}:n)),w(!0),O(null)}async function V(t,n){v(!0),E(null),O(null);try{let r=await a.updateStickerManifest(e,t.map(e=>({filename:e.filename,shortcode:e.shortcode?.trim()||null})));return f(r.stickers??[]),w(!1),O(n),await i?.(),r.stickers??[]}catch(e){return E(e?.message??`Failed to save sticker metadata.`),w(!0),null}finally{v(!1)}}async function H(){await V(s,`Sticker metadata saved.`)}async function U(t){let n=t.target.files?.[0];if(t.target.value=``,n){if(C){E(`Save or discard your existing sticker edits before uploading a new file.`);return}if(n.size>ie){E(`Sticker files must be 2MB or smaller.`);return}try{let e=await oe(n);if(Math.max(e.width,e.height)>K){E(`Sticker dimensions must be ${K}px or smaller on the longest side.`);return}}catch{E(`Could not read the selected image.`);return}b(!0),E(null),O(null);try{let t=await a.uploadSticker(e,n,n.name);f(e=>[...e,t.sticker].sort((e,t)=>e.order-t.order||e.filename.localeCompare(t.filename))),m(t.quota??null),O(`Sticker uploaded. Assign a shortcode and save when you are ready.`),await i?.()}catch(e){E(e?.message??`Failed to upload sticker.`)}finally{b(!1)}}}async function W(t){if(C){E(`Save or discard your existing sticker edits before deleting a file.`);return}if(window.confirm(`Delete ${t}? This removes the sticker file and its shortcode mapping.`)){S(t),E(null),O(null);try{await a.deleteSticker(e,t),await P(),O(`Sticker deleted.`),await i?.()}catch(e){E(e?.message??`Failed to delete sticker.`)}finally{S(null)}}}return(0,l.jsxs)(`div`,{className:`sticker-admin-page`,children:[(0,l.jsxs)(`div`,{className:`sticker-admin-page__topbar`,children:[(0,l.jsxs)(`div`,{className:`sticker-admin-page__title-group`,children:[(0,l.jsxs)(`div`,{className:`sticker-admin-page__title-row`,children:[r&&(0,l.jsx)(`button`,{className:`btn btn--ghost sticker-admin-page__back`,onClick:r,children:`← Back`}),(0,l.jsx)(`h2`,{className:`sticker-admin-page__title`,children:`Sticker library`}),(0,l.jsx)(`span`,{className:`sticker-admin-page__count`,children:p?`${p.used} sticker${p.used===1?``:`s`} of ${p.limit>=9999?`unlimited`:p.limit} slots available`:`${s.length} sticker${s.length===1?``:`s`}`}),D&&(0,l.jsx)(`div`,{className:`sticker-admin-page__status-inline`,children:D})]}),(0,l.jsx)(`p`,{className:`sticker-admin-page__subtitle`,children:`Upload stickers, assign shortcodes, and order the picker.`})]}),(0,l.jsxs)(`div`,{className:`sticker-admin-page__header-actions`,children:[(0,l.jsx)(`button`,{className:`btn btn--ghost`,onClick:()=>o.current?.click(),disabled:y||_||h,children:y?`Uploading…`:`Upload`}),(0,l.jsx)(`button`,{className:`btn btn--ghost`,onClick:()=>P(),disabled:h||_||y,children:`Reload`}),(0,l.jsx)(`button`,{className:`btn btn--primary`,onClick:H,disabled:!C||_||h||y,children:_?`Saving…`:`Save shortcodes`})]})]}),(0,l.jsxs)(`div`,{className:`sticker-admin-page__notice`,children:[(0,l.jsx)(`strong`,{children:`Rules:`}),` unique per station, max 12 chars, lowercase letters/numbers/hyphens/underscores only. Blank shortcode fields auto-generate from the filename. Uploads ≤2MB and ≤310px. Drag tiles to reorder.`]}),T&&(0,l.jsx)(`div`,{className:`sticker-admin-page__error`,children:T}),(0,l.jsx)(`input`,{ref:o,type:`file`,accept:`image/gif,image/png,image/jpeg,image/webp`,hidden:!0,onChange:U}),h?(0,l.jsx)(`div`,{className:`sticker-admin-page__state`,children:`Loading sticker library…`}):s.length===0?(0,l.jsx)(`div`,{className:`sticker-admin-page__state`,children:`No stickers uploaded yet.`}):(0,l.jsx)(`div`,{className:`sticker-admin-grid`,children:s.map((e,t)=>{let n=x===e.filename,r=k===e.filename,i=j===e.filename&&k!==e.filename;return(0,l.jsxs)(`div`,{className:[`sticker-admin-card`,r?`sticker-admin-card--dragging`:``,i?`sticker-admin-card--drop-target`:``].filter(Boolean).join(` `),onDragOver:t=>L(t,e.filename),onDrop:t=>z(t,e.filename),children:[(0,l.jsxs)(`div`,{className:`sticker-admin-card__preview sticker-admin-card__preview--draggable`,draggable:!_&&!y&&!x,onDragStart:t=>I(t,e.filename),onDragEnd:F,title:`Drag to reorder`,children:[(0,l.jsx)(`img`,{src:e.url,alt:ae(e),loading:`lazy`,draggable:!1}),(0,l.jsxs)(`span`,{className:`sticker-admin-card__drag-badge`,"aria-hidden":`true`,children:[(0,l.jsx)(`svg`,{viewBox:`0 0 24 24`,focusable:`false`,children:(0,l.jsx)(`path`,{fill:`currentColor`,d:`M11 23v-3.17l-1.41 1.41-1.42-1.41L12 16l3.83 3.83-1.42 1.41L13 19.83V23h-2Zm-3-7-3.83-3.83 3.83-3.83 1.42 1.41L8.01 11H11v2H8.01l1.41 1.41L8 16Zm8 0-1.41-1.41L15.99 13H13v-2h2.99l-1.4-1.42L16 8.17 19.83 12 16 15.83ZM12 8 8.17 4.17l1.42-1.41L11 4.17V1h2v3.17l1.41-1.41 1.42 1.41L12 8Z`})}),(0,l.jsx)(`span`,{children:`Drag to reorder`})]})]}),(0,l.jsxs)(`div`,{className:`sticker-admin-card__body`,children:[(0,l.jsx)(`div`,{className:`sticker-admin-card__filename`,title:e.filename,children:e.filename}),(0,l.jsx)(`label`,{className:`sticker-admin-card__field`,children:(0,l.jsxs)(`div`,{className:`sticker-admin-card__shortcode-input`,children:[(0,l.jsx)(`span`,{children:`:`}),(0,l.jsx)(`input`,{type:`text`,value:e.shortcode??``,placeholder:`viking`,maxLength:12,"aria-label":`Shortcode for ${e.filename}`,onChange:t=>B(e.filename,t.target.value.toLowerCase())}),(0,l.jsx)(`span`,{children:`:`})]})}),(0,l.jsx)(`div`,{className:`sticker-admin-card__actions`,children:(0,l.jsx)(`button`,{className:`btn btn--danger`,onClick:()=>W(e.filename),disabled:n||_||y,children:n?`Deleting…`:`Delete`})})]})]},e.filename)})})]})}var J=[{key:`--relaya-color-bg`,label:`Chat background`,hint:`Outermost container background`,lightDefault:`#f0f2f5`,darkDefault:`#0d1117`},{key:`--relaya-color-message-bg`,label:`Others' message bubbles`,hint:`Bubble background for received messages`,lightDefault:`#e9ecef`,darkDefault:`#21262d`},{key:`--relaya-color-message-own-bg`,label:`Your message bubbles`,hint:`Bubble background for sent messages`,lightDefault:`#007aff`,darkDefault:`#1f6feb`},{key:`--relaya-color-text`,label:`Body text`,hint:`Primary text colour`,lightDefault:`#1a1a2e`,darkDefault:`#e6edf3`},{key:`--relaya-color-text-secondary`,label:`Secondary / muted text`,hint:`Timestamps, labels`,lightDefault:`#6c757d`,darkDefault:`#8b949e`},{key:`--relaya-color-input-bg`,label:`Message input background`,hint:`Text-entry field background`,lightDefault:`#f8f9fa`,darkDefault:`#21262d`},{key:`--relaya-color-input-text`,label:`Message input text`,hint:`Text typed in the input`,lightDefault:`#1a1a2e`,darkDefault:`#e6edf3`},{key:`--relaya-color-btn-bg`,label:`Send button background`,hint:`Primary action button background`,lightDefault:`#007aff`,darkDefault:`#1f6feb`},{key:`--relaya-color-btn-text`,label:`Send button icon`,hint:`Icon colour on the send button`,lightDefault:`#ffffff`,darkDefault:`#ffffff`},{key:`--relaya-color-name-mod`,label:`Moderator name colour`,hint:`Display name colour for moderators`,lightDefault:`#007aff`,darkDefault:`#58a6ff`},{key:`--relaya-color-link`,label:`Link colour`,hint:`Hyperlink default state`,lightDefault:`#007aff`,darkDefault:`#58a6ff`},{key:`--relaya-color-link-active`,label:`Link hover/active colour`,hint:`Hyperlink hover/active state`,lightDefault:`#0062cc`,darkDefault:`#79b8ff`}],se={};function Y(e){return/^#[0-9a-fA-F]{6}$/.test(e.trim())}function X(e){let t=e.trim();return/^[0-9a-fA-F]{6}$/.test(t)?`#${t}`:/^#[0-9a-fA-F]{3}$/.test(t)?`#${t[1]}${t[1]}${t[2]}${t[2]}${t[3]}${t[3]}`:t}function ce({stationSlug:e,getToken:t,onClose:n}){let{theme:r,loading:i,saving:a,error:o,loadTheme:s,saveTheme:u,resetTheme:d}=O(e,t),[f,m]=(0,c.useState)(p.theme),[h,g]=(0,c.useState)({light:{},dark:{}}),[_,v]=(0,c.useState)(!1),[y,b]=(0,c.useState)(null),[x,S]=(0,c.useState)({});(0,c.useEffect)(()=>{let e=document.createElement(`div`);e.style.display=`none`,document.documentElement.appendChild(e);let t={};for(let{key:n}of J){e.style.setProperty(`background-color`,`var(${n})`);let r=getComputedStyle(e).backgroundColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);r&&(t[n]=`#`+[r[1],r[2],r[3]].map(e=>parseInt(e).toString(16).padStart(2,`0`)).join(``))}document.documentElement.removeChild(e),S(t)},[]),(0,c.useEffect)(()=>{s()},[]),(0,c.useEffect)(()=>{g({light:{...r.light},dark:{...r.dark}}),v(!1)},[r]);function C(e,t){let n=X(t);g(t=>({...t,[f]:{...t[f],[e]:n}})),v(!0),b(null)}async function w(){let e={light:{},dark:{}};for(let t of[`light`,`dark`])for(let[n,r]of Object.entries(h[t]))r&&Y(r)&&(e[t][n]=r);await u(e,f),v(!1),b(`Theme saved.`)}async function T(){confirm(`Remove all saved colour overrides and revert to the default theme?`)&&(await d(f),v(!1),b(`Theme reset to defaults.`))}let E=h[f]??se;return(0,l.jsxs)(`div`,{className:`theme-admin-page`,children:[(0,l.jsxs)(`div`,{className:`theme-admin-page__topbar`,children:[(0,l.jsxs)(`div`,{className:`theme-admin-page__title-group`,children:[(0,l.jsxs)(`div`,{className:`theme-admin-page__title-row`,children:[n&&(0,l.jsx)(`button`,{className:`btn btn--ghost theme-admin-page__back`,onClick:n,children:`← Back`}),(0,l.jsx)(`h2`,{className:`theme-admin-page__title`,children:`Colour theme`}),y&&(0,l.jsx)(`div`,{className:`theme-admin-page__status-inline`,children:y})]}),(0,l.jsx)(`p`,{className:`theme-admin-page__subtitle`,children:`Override the default colours for this space. Only saved values are stored; unset fields fall back to the default theme.`})]}),(0,l.jsxs)(`div`,{className:`theme-admin-page__header-actions`,children:[(0,l.jsx)(`button`,{className:`btn btn--ghost`,onClick:T,disabled:a||i,children:`Reset to defaults`}),(0,l.jsx)(`button`,{className:`btn btn--primary`,onClick:w,disabled:a||i||!_,children:a?`Saving…`:`Save colours`})]})]}),o&&(0,l.jsx)(`div`,{className:`theme-admin-page__error`,children:o}),(0,l.jsxs)(`div`,{className:`theme-admin-page__tabs`,children:[(0,l.jsx)(`button`,{className:`theme-admin-page__tab${f===`light`?` theme-admin-page__tab--active`:``}`,onClick:()=>m(`light`),children:`☀ Light`}),(0,l.jsx)(`button`,{className:`theme-admin-page__tab${f===`dark`?` theme-admin-page__tab--active`:``}`,onClick:()=>m(`dark`),children:`☾ Dark`})]}),i?(0,l.jsx)(`div`,{className:`theme-admin-page__state`,children:`Loading theme…`}):(0,l.jsx)(`div`,{className:`theme-admin-list`,children:J.map(({key:e,label:t,hint:n,lightDefault:r,darkDefault:i})=>{let a=f===p.theme?x[e]??(f===`light`?r:i):f===`light`?r:i,o=E[e]??``,s=o?X(o):a,c=o!==``&&!Y(o);return(0,l.jsxs)(`div`,{className:`theme-admin-row`,title:n,children:[(0,l.jsx)(`input`,{type:`color`,className:`theme-admin-row__swatch`,value:Y(s)?s:a,onChange:t=>C(e,t.target.value),title:t}),(0,l.jsx)(`label`,{className:`theme-admin-row__label`,children:t}),(0,l.jsx)(`input`,{type:`text`,className:`theme-admin-row__hex${c?` theme-admin-row__hex--invalid`:``}`,value:o,placeholder:a,maxLength:9,onChange:t=>C(e,t.target.value)})]},e)})})]})}function Z(e){return e.toISOString().slice(0,10)}function le(){let e=new Date;return{from:Z(new Date(e.getTime()-90*864e5)),to:Z(e),excludeReportedBefore:Z(new Date(e.getTime()-365*864e5))}}var ue=`A date is required — reported messages are kept indefinitely for compliance. Choose a date to limit how far back they appear in this export.`;function de({stationSlug:e,getToken:t}){let n=le(),[r,i]=(0,c.useState)(n.from),[a,o]=(0,c.useState)(n.to),[s,u]=(0,c.useState)(n.excludeReportedBefore),[d,f]=(0,c.useState)(null),[p,m]=(0,c.useState)(!1),[h,g]=(0,c.useState)(null),[_,v]=(0,c.useState)(!1);function y(){f(s?null:ue)}async function b(){if(!s){f(ue);return}f(null),g(null),m(!0);try{let n=new URLSearchParams;r&&n.set(`from`,r+`T00:00:00Z`),a&&n.set(`to`,a+`T23:59:59Z`),n.set(`excludeReportedBefore`,s+`T00:00:00Z`);let i=`/api/chat/${e}/export/messages?${n.toString()}`,o=t(),c={};o&&(c.Authorization=`Bearer ${o}`);let l=await fetch(i,{credentials:`include`,headers:c});if(l.ok){let t=await l.blob(),n=(l.headers.get(`Content-Disposition`)??``).match(/filename="([^"]+)"/),r=n?n[1]:`${e}-export.csv`,i=document.createElement(`a`);i.href=URL.createObjectURL(t),i.download=r,document.body.appendChild(i),i.click(),i.remove(),URL.revokeObjectURL(i.href);return}let u={};try{u=await l.json()}catch{}if(l.status===403){let e=u.error;if(typeof e==`object`&&e?.code===`TIER_LIMIT`){v(!0);return}g(`You do not have permission to export chat history for this space.`);return}if(l.status===429){g(`Export rate limit reached — you can export once per hour. Try again in ${Math.ceil((u.retryAfter??3600)/60)} minutes.`);return}if(l.status===413){g(`Too many messages in this date range. Please narrow the date range and try again.`);return}g((typeof u.error==`object`?u.error?.message:typeof u.error==`string`?u.error:void 0)??`Export failed. Please try again.`)}catch{g(`Export failed due to a network error. Please try again.`)}finally{m(!1)}}return _?(0,l.jsx)(`div`,{className:`export-admin-page`,children:(0,l.jsx)(`p`,{className:`export-admin-page__unavailable`,children:`Chat history export is not available on your current plan.`})}):(0,l.jsxs)(`div`,{className:`export-admin-page`,children:[(0,l.jsx)(`p`,{className:`export-admin-page__notice`,children:`Exports contain user display names and message content. Handle in accordance with your privacy policy.`}),h&&(0,l.jsx)(`div`,{className:`export-admin-page__error`,children:h}),(0,l.jsxs)(`div`,{className:`export-admin-page__form`,children:[(0,l.jsxs)(`div`,{className:`export-admin-page__date-row`,children:[(0,l.jsxs)(`label`,{className:`export-admin-page__label`,children:[`From:`,(0,l.jsx)(`input`,{type:`date`,className:`export-admin-page__date-input`,value:r,onChange:e=>i(e.target.value)})]}),(0,l.jsxs)(`label`,{className:`export-admin-page__label`,children:[`To:`,(0,l.jsx)(`input`,{type:`date`,className:`export-admin-page__date-input`,value:a,onChange:e=>o(e.target.value)})]})]}),(0,l.jsxs)(`div`,{className:`export-admin-page__exclude-row`,children:[(0,l.jsxs)(`label`,{className:`export-admin-page__label`,children:[`Exclude reported messages older than:`,(0,l.jsx)(`input`,{type:`date`,className:`export-admin-page__date-input`,value:s,onChange:e=>{u(e.target.value),f(null)},onBlur:y,required:!0})]}),d&&(0,l.jsx)(`p`,{className:`export-admin-page__field-error`,children:d})]}),(0,l.jsx)(`button`,{className:`btn btn--primary export-admin-page__btn`,onClick:b,disabled:p,children:p?`Preparing…`:`Download CSV →`}),(0,l.jsx)(`p`,{className:`export-admin-page__hint`,children:`Export is limited to the space’s retention window. Rate limited: 1 export per hour.`})]})]})}var Q={AF:`Afghanistan`,AX:`Åland Islands`,AL:`Albania`,DZ:`Algeria`,AS:`American Samoa`,AD:`Andorra`,AO:`Angola`,AI:`Anguilla`,AQ:`Antarctica`,AG:`Antigua and Barbuda`,AR:`Argentina`,AM:`Armenia`,AW:`Aruba`,AU:`Australia`,AT:`Austria`,AZ:`Azerbaijan`,BS:`Bahamas`,BH:`Bahrain`,BD:`Bangladesh`,BB:`Barbados`,BY:`Belarus`,BE:`Belgium`,BZ:`Belize`,BJ:`Benin`,BM:`Bermuda`,BT:`Bhutan`,BO:`Bolivia`,BQ:`Bonaire, Sint Eustatius and Saba`,BA:`Bosnia and Herzegovina`,BW:`Botswana`,BV:`Bouvet Island`,BR:`Brazil`,IO:`British Indian Ocean Territory`,BN:`Brunei`,BG:`Bulgaria`,BF:`Burkina Faso`,BI:`Burundi`,CV:`Cabo Verde`,KH:`Cambodia`,CM:`Cameroon`,CA:`Canada`,KY:`Cayman Islands`,CF:`Central African Republic`,TD:`Chad`,CL:`Chile`,CN:`China`,CX:`Christmas Island`,CC:`Cocos Islands`,CO:`Colombia`,KM:`Comoros`,CG:`Congo`,CD:`Congo (DRC)`,CK:`Cook Islands`,CR:`Costa Rica`,CI:`Côte d'Ivoire`,HR:`Croatia`,CU:`Cuba`,CW:`Curaçao`,CY:`Cyprus`,CZ:`Czechia`,DK:`Denmark`,DJ:`Djibouti`,DM:`Dominica`,DO:`Dominican Republic`,EC:`Ecuador`,EG:`Egypt`,SV:`El Salvador`,GQ:`Equatorial Guinea`,ER:`Eritrea`,EE:`Estonia`,SZ:`Eswatini`,ET:`Ethiopia`,FK:`Falkland Islands`,FO:`Faroe Islands`,FJ:`Fiji`,FI:`Finland`,FR:`France`,GF:`French Guiana`,PF:`French Polynesia`,TF:`French Southern Territories`,GA:`Gabon`,GM:`Gambia`,GE:`Georgia`,DE:`Germany`,GH:`Ghana`,GI:`Gibraltar`,GR:`Greece`,GL:`Greenland`,GD:`Grenada`,GP:`Guadeloupe`,GU:`Guam`,GT:`Guatemala`,GG:`Guernsey`,GN:`Guinea`,GW:`Guinea-Bissau`,GY:`Guyana`,HT:`Haiti`,HM:`Heard Island and McDonald Islands`,VA:`Holy See`,HN:`Honduras`,HK:`Hong Kong`,HU:`Hungary`,IS:`Iceland`,IN:`India`,ID:`Indonesia`,IR:`Iran`,IQ:`Iraq`,IE:`Ireland`,IM:`Isle of Man`,IL:`Israel`,IT:`Italy`,JM:`Jamaica`,JP:`Japan`,JE:`Jersey`,JO:`Jordan`,KZ:`Kazakhstan`,KE:`Kenya`,KI:`Kiribati`,KP:`North Korea`,KR:`South Korea`,KW:`Kuwait`,KG:`Kyrgyzstan`,LA:`Laos`,LV:`Latvia`,LB:`Lebanon`,LS:`Lesotho`,LR:`Liberia`,LY:`Libya`,LI:`Liechtenstein`,LT:`Lithuania`,LU:`Luxembourg`,MO:`Macao`,MG:`Madagascar`,MW:`Malawi`,MY:`Malaysia`,MV:`Maldives`,ML:`Mali`,MT:`Malta`,MH:`Marshall Islands`,MQ:`Martinique`,MR:`Mauritania`,MU:`Mauritius`,YT:`Mayotte`,MX:`Mexico`,FM:`Micronesia`,MD:`Moldova`,MC:`Monaco`,MN:`Mongolia`,ME:`Montenegro`,MS:`Montserrat`,MA:`Morocco`,MZ:`Mozambique`,MM:`Myanmar`,NA:`Namibia`,NR:`Nauru`,NP:`Nepal`,NL:`Netherlands`,NC:`New Caledonia`,NZ:`New Zealand`,NI:`Nicaragua`,NE:`Niger`,NG:`Nigeria`,NU:`Niue`,NF:`Norfolk Island`,MK:`North Macedonia`,MP:`Northern Mariana Islands`,NO:`Norway`,OM:`Oman`,PK:`Pakistan`,PW:`Palau`,PS:`Palestine`,PA:`Panama`,PG:`Papua New Guinea`,PY:`Paraguay`,PE:`Peru`,PH:`Philippines`,PN:`Pitcairn`,PL:`Poland`,PT:`Portugal`,PR:`Puerto Rico`,QA:`Qatar`,RE:`Réunion`,RO:`Romania`,RU:`Russia`,RW:`Rwanda`,BL:`Saint Barthélemy`,SH:`Saint Helena`,KN:`Saint Kitts and Nevis`,LC:`Saint Lucia`,MF:`Saint Martin`,PM:`Saint Pierre and Miquelon`,VC:`Saint Vincent and the Grenadines`,WS:`Samoa`,SM:`San Marino`,ST:`Sao Tome and Principe`,SA:`Saudi Arabia`,SN:`Senegal`,RS:`Serbia`,SC:`Seychelles`,SL:`Sierra Leone`,SG:`Singapore`,SX:`Sint Maarten`,SK:`Slovakia`,SI:`Slovenia`,SB:`Solomon Islands`,SO:`Somalia`,ZA:`South Africa`,GS:`South Georgia`,SS:`South Sudan`,ES:`Spain`,LK:`Sri Lanka`,SD:`Sudan`,SR:`Suriname`,SJ:`Svalbard and Jan Mayen`,SE:`Sweden`,CH:`Switzerland`,SY:`Syria`,TW:`Taiwan`,TJ:`Tajikistan`,TZ:`Tanzania`,TH:`Thailand`,TL:`Timor-Leste`,TG:`Togo`,TK:`Tokelau`,TO:`Tonga`,TT:`Trinidad and Tobago`,TN:`Tunisia`,TR:`Turkey`,TM:`Turkmenistan`,TC:`Turks and Caicos Islands`,TV:`Tuvalu`,UG:`Uganda`,UA:`Ukraine`,AE:`United Arab Emirates`,GB:`United Kingdom`,US:`United States`,UM:`US Minor Outlying Islands`,UY:`Uruguay`,UZ:`Uzbekistan`,VU:`Vanuatu`,VE:`Venezuela`,VN:`Vietnam`,VG:`British Virgin Islands`,VI:`US Virgin Islands`,WF:`Wallis and Futuna`,EH:`Western Sahara`,YE:`Yemen`,ZM:`Zambia`,ZW:`Zimbabwe`};function fe(e){let t=Q[e.toUpperCase()];return t?`${t} (${e.toUpperCase()})`:e.toUpperCase()}function pe(e){let t=Q[e.toUpperCase()];return t?`${t} \u00b7 ${e.toUpperCase()}`:e.toUpperCase()}var me=Object.entries(Q).map(([e,t])=>({code:e,name:t})).sort((e,t)=>e.name.localeCompare(t.name));function $(e){let t=e();return t?{Authorization:`Bearer ${t}`}:{}}function he(e){if(e.isPermanent||!e.expiresAt)return`Permanent`;let t=new Date(e.expiresAt);return t<new Date?`Expired`:`Until ${t.toLocaleDateString(void 0,{month:`short`,day:`numeric`,year:`numeric`})}`}function ge({stationSlug:e,getToken:t}){let n=`/api/chat/${e}`,[r,i]=(0,c.useState)(!1),[a,o]=(0,c.useState)(!1),[s,u]=(0,c.useState)(null),[d,f]=(0,c.useState)({mode:null,countries:[]}),[p,m]=(0,c.useState)([]),[h,g]=(0,c.useState)(``),[_,v]=(0,c.useState)(!1),y=(0,c.useRef)(null),[b,x]=(0,c.useState)(``),[S,C]=(0,c.useState)(!1),[w,T]=(0,c.useState)(``),[E,D]=(0,c.useState)(``),[O,k]=(0,c.useState)(``),[A,j]=(0,c.useState)(!1),[M,N]=(0,c.useState)(null);(0,c.useEffect)(()=>{(async()=>{i(!0),u(null);try{let e={...$(t),"Content-Type":`application/json`},[r,a]=await Promise.all([fetch(`${n}/geo/config`,{credentials:`include`,headers:e}),fetch(`${n}/ip-bans`,{credentials:`include`,headers:e})]);if(r.status===403){let e={};try{e=await r.json()}catch{}if(typeof e.error==`object`&&e.error?.code===`TIER_LIMIT`){o(!0),i(!1);return}}if(!r.ok)throw Error(`Failed to load geo config`);if(!a.ok)throw Error(`Failed to load IP bans`);let s=await r.json(),c=await a.json();f({mode:s.mode??null,countries:s.countries??[]}),m(c.bans??[])}catch(e){u(e?.message??`Failed to load geo restriction settings`)}finally{i(!1)}})()},[]),(0,c.useEffect)(()=>{function e(e){y.current&&!y.current.contains(e.target)&&v(!1)}return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[]);async function P(e,r){let i=await fetch(`${n}${e}`,{method:`POST`,credentials:`include`,headers:{...$(t),"Content-Type":`application/json`},body:JSON.stringify(r)});if(!i.ok){let e=`Request failed`;try{let t=await i.json();e=t?.error?.message??t?.error??e}catch{}throw Error(typeof e==`string`?e:`Request failed`)}return i.json()}async function F(e){let r=await fetch(`${n}${e}`,{method:`DELETE`,credentials:`include`,headers:$(t)});if(!r.ok){let e=`Request failed`;try{let t=await r.json();e=t?.error?.message??t?.error??e}catch{}throw Error(typeof e==`string`?e:`Request failed`)}return r.json()}async function I(e){N(null);let t=e===`none`?null:e;try{let e=await P(`/geo/config`,{mode:t});f({mode:e.mode??null,countries:e.countries??[]})}catch(e){N(e?.message??`Failed to update mode`)}}async function L(e){N(null),g(``),v(!1);try{let t=await P(`/geo/countries`,{countryCode:e});f({mode:t.mode??null,countries:t.countries??[]})}catch(e){N(e?.message??`Failed to add country`)}}async function R(e){N(null);try{let t=await F(`/geo/countries/${e}`);f({mode:t.mode??null,countries:t.countries??[]})}catch(e){N(e?.message??`Failed to remove country`)}}async function z(e){N(null);try{await F(`/ip-bans/${e}`),m(t=>t.filter(t=>t.id!==e))}catch(e){N(e?.message??`Failed to lift ban`)}}async function B(e){if(e.preventDefault(),w.trim()){N(null),j(!0);try{let e={ipAddress:w.trim()};if(E.trim()&&(e.reason=E.trim()),O.trim()){let t=parseInt(O,10);!isNaN(t)&&t>0&&(e.durationMinutes=t)}let t=await P(`/ip-bans`,e);m(e=>[{id:t.id,ipAddress:t.ipAddress,reason:t.reason??null,expiresAt:t.expiresAt??null,isPermanent:t.isPermanent,createdAt:t.createdAt},...e]),T(``),D(``),k(``),C(!1)}catch(e){N(e?.message??`Failed to add IP ban`)}finally{j(!1)}}}if(r)return(0,l.jsx)(`div`,{className:`geo-admin__status`,children:`Loading…`});if(a)return(0,l.jsx)(`div`,{className:`geo-admin__status geo-admin__status--unavailable`,children:`Geo restrictions and IP bans are available on the Community plan and above.`});if(s)return(0,l.jsx)(`div`,{className:`geo-admin__status geo-admin__status--error`,children:s});let V=h.trim().toLowerCase(),H=(V?me.filter(e=>e.name.toLowerCase().includes(V)||e.code.toLowerCase().includes(V)).slice(0,12):me.slice(0,12)).filter(e=>!d.countries.includes(e.code)),U=b.trim()?p.filter(e=>e.ipAddress.includes(b.trim())||(e.reason??``).toLowerCase().includes(b.trim().toLowerCase())):p;return(0,l.jsxs)(`div`,{className:`geo-admin`,children:[M&&(0,l.jsx)(`div`,{className:`geo-admin__action-error`,children:M}),(0,l.jsxs)(`div`,{className:`geo-admin__section`,children:[(0,l.jsx)(`h4`,{className:`geo-admin__section-title`,children:`Country Restrictions`}),(0,l.jsxs)(`div`,{className:`geo-admin__field`,children:[(0,l.jsx)(`label`,{className:`geo-admin__label`,children:`Restriction mode`}),(0,l.jsxs)(`select`,{className:`geo-admin__select`,value:d.mode??`none`,onChange:e=>I(e.target.value),children:[(0,l.jsx)(`option`,{value:`none`,children:`None (unrestricted)`}),(0,l.jsx)(`option`,{value:`blocklist`,children:`Blocklist — block listed countries`}),(0,l.jsx)(`option`,{value:`allowlist`,children:`Allowlist — only listed countries`})]})]}),d.mode&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`p`,{className:`geo-admin__hint`,children:d.mode===`blocklist`?`Users from these countries will be blocked from posting.`:`Only users from these countries can post.`}),d.countries.length>0?(0,l.jsx)(`div`,{className:`geo-admin__chips`,children:d.countries.map(e=>(0,l.jsxs)(`span`,{className:`geo-admin__chip`,children:[pe(e),(0,l.jsx)(`button`,{className:`geo-admin__chip-remove`,onClick:()=>R(e),title:`Remove ${e}`,"aria-label":`Remove ${e}`,children:`×`})]},e))}):(0,l.jsx)(`p`,{className:`geo-admin__hint geo-admin__hint--empty`,children:`No countries in list yet.`}),(0,l.jsxs)(`div`,{className:`geo-admin__combobox`,ref:y,children:[(0,l.jsx)(`input`,{className:`geo-admin__combobox-input`,type:`text`,placeholder:`Search country to add…`,value:h,onChange:e=>{g(e.target.value),v(!0)},onFocus:()=>v(!0),onKeyDown:e=>{e.key===`Escape`&&(v(!1),g(``)),e.key===`Enter`&&H.length===1&&L(H[0].code)}}),_&&H.length>0&&(0,l.jsx)(`ul`,{className:`geo-admin__combobox-list`,children:H.map(e=>(0,l.jsx)(`li`,{children:(0,l.jsx)(`button`,{className:`geo-admin__combobox-item`,onMouseDown:t=>{t.preventDefault(),L(e.code)},children:fe(e.code)})},e.code))}),_&&h.trim()&&H.length===0&&(0,l.jsx)(`div`,{className:`geo-admin__combobox-empty`,children:`No matching countries`})]})]})]}),(0,l.jsxs)(`div`,{className:`geo-admin__section`,children:[(0,l.jsxs)(`h4`,{className:`geo-admin__section-title`,children:[`IP Bans`,p.length>0&&(0,l.jsx)(`span`,{className:`geo-admin__badge`,children:p.length})]}),p.length>4&&(0,l.jsx)(`input`,{className:`geo-admin__filter-input`,type:`text`,placeholder:`Filter by IP or reason…`,value:b,onChange:e=>x(e.target.value)}),U.length===0&&p.length===0?(0,l.jsx)(`p`,{className:`geo-admin__hint`,children:`No active IP bans.`}):U.length===0?(0,l.jsx)(`p`,{className:`geo-admin__hint`,children:`No bans match your filter.`}):(0,l.jsx)(`div`,{className:`geo-admin__ban-list`,children:U.map(e=>(0,l.jsxs)(`div`,{className:`geo-admin__ban-row`,children:[(0,l.jsxs)(`div`,{className:`geo-admin__ban-info`,children:[(0,l.jsx)(`span`,{className:`geo-admin__ban-ip`,children:e.ipAddress}),e.reason&&(0,l.jsx)(`span`,{className:`geo-admin__ban-reason`,children:e.reason}),(0,l.jsx)(`span`,{className:`geo-admin__ban-expiry`,children:he(e)})]}),(0,l.jsx)(`button`,{className:`btn btn--ghost geo-admin__lift-btn`,onClick:()=>z(e.id),children:`Lift ban`})]},e.id))}),(0,l.jsxs)(`button`,{className:`geo-admin__add-toggle`,onClick:()=>C(e=>!e),children:[S?`▼`:`▶`,` Add IP ban`]}),S&&(0,l.jsxs)(`form`,{className:`geo-admin__add-ban-form`,onSubmit:B,children:[(0,l.jsxs)(`div`,{className:`geo-admin__field`,children:[(0,l.jsx)(`label`,{className:`geo-admin__label`,children:`IP address or CIDR range *`}),(0,l.jsx)(`input`,{className:`geo-admin__input`,type:`text`,placeholder:`e.g. 1.2.3.4 or 1.2.0.0/16`,value:w,onChange:e=>T(e.target.value),required:!0})]}),(0,l.jsxs)(`div`,{className:`geo-admin__field`,children:[(0,l.jsx)(`label`,{className:`geo-admin__label`,children:`Reason (optional)`}),(0,l.jsx)(`input`,{className:`geo-admin__input`,type:`text`,placeholder:`Reason for ban`,value:E,onChange:e=>D(e.target.value)})]}),(0,l.jsxs)(`div`,{className:`geo-admin__field`,children:[(0,l.jsx)(`label`,{className:`geo-admin__label`,children:`Duration in minutes (blank = permanent)`}),(0,l.jsx)(`input`,{className:`geo-admin__input`,type:`number`,min:`1`,placeholder:`e.g. 1440 for 24 hours`,value:O,onChange:e=>k(e.target.value)})]}),(0,l.jsx)(`button`,{className:`btn btn--primary`,type:`submit`,disabled:A||!w.trim(),children:A?`Adding…`:`Add IP ban`})]})]})]})}function _e(e){return e.email?`${e.displayName} (${e.email})`:e.displayName}function ve(e,t){return t===null?`${e} moderator${e===1?``:`s`} — unlimited slots`:`${e} of ${t} moderator slot${t===1?``:`s`} used`}function ye({stationSlug:e,user:t,getToken:n}){let r=(0,c.useRef)(new d(``,n)).current,[i,a]=(0,c.useState)([]),[o,s]=(0,c.useState)(null),[f,p]=(0,c.useState)(!0),[m,h]=(0,c.useState)(null),[g,_]=(0,c.useState)(``),[v,y]=(0,c.useState)(null),[b,x]=(0,c.useState)(null),S=t.permissions.includes(u.MANAGE_ROLES);async function C(){p(!0),h(null);try{let t=await r.getMembersAdmin(e);a(t.members),s(t.quota)}catch(e){h(e?.message??`Failed to load moderators.`)}finally{p(!1)}}if((0,c.useEffect)(()=>{S&&C().catch(()=>void 0)},[S,e]),!S)return null;let w=i.filter(e=>e.roles.includes(`moderator`)),T=i.filter(e=>!e.roles.includes(`moderator`)&&!e.roles.includes(`station_admin`)),E=g.trim().toLowerCase(),D=E===``?T:T.filter(e=>e.displayName.toLowerCase().includes(E)||(e.email??``).toLowerCase().includes(E)),O=o!==null&&o.limit!==null&&o.used>=o.limit,k=v!==null||b!==null;async function A(t){y(t),h(null);try{await r.patchMemberRoles(e,t,{add:[`moderator`]}),await C()}catch(e){h(e?.message??`Failed to promote member.`)}finally{y(null)}}async function j(t){x(t),h(null);try{await r.patchMemberRoles(e,t,{remove:[`moderator`]}),await C()}catch(e){h(e?.message??`Failed to demote moderator.`)}finally{x(null)}}return(0,l.jsxs)(`div`,{className:`moderator-admin-page`,children:[(0,l.jsx)(`div`,{className:`moderator-admin-page__topbar`,children:(0,l.jsxs)(`div`,{className:`moderator-admin-page__title-row`,children:[(0,l.jsx)(`h2`,{className:`moderator-admin-page__title`,children:`Moderators`}),o&&(0,l.jsx)(`span`,{className:`sticker-admin-page__count`,children:ve(o.used,o.limit)})]})}),m&&(0,l.jsx)(`div`,{className:`sticker-admin-page__error`,children:m}),f?(0,l.jsx)(`div`,{className:`sticker-admin-page__state`,children:`Loading moderators…`}):(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)(`div`,{className:`moderator-admin-page__section`,children:[(0,l.jsx)(`h3`,{className:`moderator-admin-page__section-title`,children:`Current moderators`}),(0,l.jsx)(`hr`,{className:`moderator-admin-page__divider`}),w.length===0?(0,l.jsx)(`div`,{className:`sticker-admin-page__state`,children:`No moderators assigned yet.`}):(0,l.jsx)(`ul`,{className:`moderator-admin-page__list`,children:w.map(e=>(0,l.jsxs)(`li`,{className:`moderator-admin-page__item`,children:[(0,l.jsx)(`button`,{className:`moderator-admin-page__demote-link`,onClick:()=>j(e.userId),disabled:k,children:b===e.userId?`Demoting…`:`Demote`}),(0,l.jsx)(`span`,{className:`moderator-admin-page__member-label`,children:_e(e)})]},e.userId))})]}),(0,l.jsxs)(`div`,{className:`moderator-admin-page__section`,children:[(0,l.jsx)(`h3`,{className:`moderator-admin-page__section-title`,children:`Add a moderator`}),(0,l.jsx)(`hr`,{className:`moderator-admin-page__divider`}),(0,l.jsx)(`input`,{className:`moderator-admin-page__filter`,type:`text`,placeholder:`Filter by name or email`,value:g,onChange:e=>_(e.target.value)}),(0,l.jsx)(`p`,{className:`moderator-admin-page__list-hint`,children:`Recent users`}),D.length===0?(0,l.jsx)(`div`,{className:`sticker-admin-page__state`,children:g?`No members match that filter.`:`No members available to promote.`}):(0,l.jsx)(`ul`,{className:`moderator-admin-page__list`,children:D.map(e=>(0,l.jsxs)(`li`,{className:`moderator-admin-page__item`,children:[(0,l.jsx)(`button`,{className:`moderator-admin-page__promote-link`,onClick:()=>A(e.userId),disabled:O||k,title:O?`Moderator limit reached for your plan`:void 0,children:v===e.userId?`Promoting…`:`Promote`}),(0,l.jsx)(`span`,{className:`moderator-admin-page__member-label`,children:_e(e)})]},e.userId))})]})]})]})}function be({className:e,spaceSlug:t,serverUrl:n=``,token:r,manageOwnRefreshToken:i,onSessionEnded:a}){let o=i??!p.managed,s=w({spaceSlug:t,initialToken:r??null,manageOwnRefreshToken:o,onSessionEnded:a}),{user:d,stationSlug:f,getToken:m}=s;(0,c.useEffect)(()=>{if(!f)return;document.documentElement.setAttribute(`data-theme`,p.theme);let e=I(f);e&&L(e);let t=`${n}/api/chat/${f}/theme`;fetch(t).then(e=>e.ok?e.json():{light:{},dark:{}}).then(e=>{(Object.keys(e?.light??{}).length>0||Object.keys(e?.dark??{}).length>0)&&D({light:e.light??{},dark:e.dark??{}},p.theme)}).catch(()=>{})},[f,n]);let[h,g]=(0,c.useState)(!1),[_,v]=(0,c.useState)(!1),[y,b]=(0,c.useState)(!1),[x,S]=(0,c.useState)(!1),[C,T]=(0,c.useState)(!1),E=e?`relaya-root ${e}`:`relaya-root`;if(s.status===`loading`)return(0,l.jsx)(`div`,{className:E,children:(0,l.jsx)(`div`,{className:`admin-panel`,children:(0,l.jsxs)(`div`,{className:`admin-panel__loading`,children:[(0,l.jsx)(`div`,{className:`connection-spinner`}),(0,l.jsx)(`span`,{children:`Loading…`})]})})});if(s.status!==`authenticated`||!d)return(0,l.jsx)(`div`,{className:E,children:(0,l.jsx)(`div`,{className:`admin-panel`,children:(0,l.jsxs)(`div`,{className:`admin-panel__unauthorized`,children:[(0,l.jsx)(`h2`,{children:`Sign in required`}),(0,l.jsx)(`p`,{children:`You must be signed in to access the admin panel.`})]})})});let O=d.permissions.includes(u.DELETE_ANY),k=d.permissions.includes(u.MANAGE_ROLES);return!O&&!k?(0,l.jsx)(`div`,{className:E,children:(0,l.jsx)(`div`,{className:`admin-panel`,children:(0,l.jsxs)(`div`,{className:`admin-panel__unauthorized`,children:[(0,l.jsx)(`h2`,{children:`Access denied`}),(0,l.jsx)(`p`,{children:`You do not have admin or moderation permissions for this space.`})]})})}):(0,l.jsx)(`div`,{className:E,children:(0,l.jsxs)(`div`,{className:`admin-panel`,children:[(0,l.jsxs)(`div`,{className:`admin-panel__header`,children:[(0,l.jsxs)(`h1`,{className:`admin-panel__title`,children:[f.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),` `,`— Admin`]}),(0,l.jsx)(`p`,{className:`admin-panel__subtitle`,children:`Moderation and administration for this space.`})]}),(0,l.jsxs)(`div`,{className:`admin-panel__sections`,children:[k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>g(e=>!e),children:[(0,l.jsx)(`span`,{children:h?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Sticker library`})]}),h&&(0,l.jsx)(`div`,{className:`admin-settings__panel`,children:(0,l.jsx)(q,{stationSlug:f,user:d,getToken:m})})]})}),k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>v(e=>!e),children:[(0,l.jsx)(`span`,{children:_?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Color theme`})]}),_&&(0,l.jsx)(`div`,{className:`admin-settings__panel`,children:(0,l.jsx)(ce,{stationSlug:f,getToken:m})})]})}),O&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsx)(W,{stationSlug:f,user:d,getToken:m})}),O&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsx)(te,{stationSlug:f,user:d,getToken:m})}),k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>b(e=>!e),children:[(0,l.jsx)(`span`,{children:y?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Moderator management`})]}),y&&(0,l.jsx)(`div`,{className:`admin-settings__panel`,children:(0,l.jsx)(ye,{stationSlug:f,user:d,getToken:m})})]})}),k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsx)(re,{stationSlug:f,user:d,getToken:m})}),k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>T(e=>!e),children:[(0,l.jsx)(`span`,{children:C?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Geo restrictions & IP bans`})]}),C&&(0,l.jsx)(`div`,{className:`admin-settings__panel`,children:(0,l.jsx)(ge,{stationSlug:f,getToken:m})})]})}),k&&(0,l.jsx)(`section`,{className:`admin-panel__section`,children:(0,l.jsxs)(`div`,{className:`admin-settings`,children:[(0,l.jsxs)(`button`,{className:`admin-settings__toggle`,onClick:()=>S(e=>!e),children:[(0,l.jsx)(`span`,{children:x?`▼`:`▶`}),(0,l.jsx)(`span`,{children:`Chat history export`})]}),x&&(0,l.jsx)(`div`,{className:`admin-settings__panel`,children:(0,l.jsx)(de,{stationSlug:f,getToken:m})})]})})]})]})})}Object.defineProperty(exports,"C",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return te}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return re}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return ce}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return V}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return be}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return m}});
|
package/dist/admin.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./AdminPanel-DqI4RFt9.cjs");exports.AdminPanel=e.t;
|
package/dist/admin.js
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./AdminPanel-DqI4RFt9.cjs");let t=require("react");t=e.C(t,1);let n=require("react/jsx-runtime");var r=`:root,[data-theme=light]{--relaya-color-bg:#f0f2f5;--relaya-color-surface:#fff;--relaya-color-surface-2:#f8f9fa;--relaya-color-border:#e0e3e8;--relaya-color-text:#1a1a2e;--relaya-color-text-muted:#6c757d;--relaya-color-text-faint:#adb5bd;--relaya-color-accent:#007aff;--relaya-color-accent-hover:#0062cc;--relaya-color-danger:#dc3545;--relaya-color-danger-hover:#c82333;--relaya-color-warning:#ffc107;--relaya-color-success:#28a745;--relaya-color-online:#28a745;--relaya-color-shadow:#00000014;--relaya-color-own-msg-bg:#007aff;--relaya-color-own-msg-text:#fff;--relaya-color-other-msg-bg:#e9ecef;--relaya-color-other-msg-text:#1a1a2e;--relaya-color-deleted-bg:#f1f3f5;--relaya-color-deleted-text:#868e96;--relaya-color-optimistic-bg:#cce5ff;--relaya-color-failed-bg:#f8d7da;--relaya-color-status-bar:#343a40;--relaya-color-status-text:#fff;--relaya-radius-sm:4px;--relaya-radius-md:8px;--relaya-radius-lg:16px;--relaya-radius-bubble:18px;--relaya-font-size-xs:11px;--relaya-font-size-sm:13px;--relaya-font-size-base:15px;--relaya-font-size-lg:17px;--spacing-xs:4px;--spacing-sm:8px;--spacing-md:12px;--spacing-lg:16px;--spacing-xl:24px;--sidebar-width:220px;--input-height:52px;--header-height:52px;--sp-title-bg:var(--relaya-color-surface);--sp-name-color:var(--relaya-color-text);--sp-name-font:inherit;--sp-ui-font:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--sp-online-color:var(--relaya-color-text-muted);--sp-no-name-color:var(--relaya-color-text-muted);--sp-btn-border:var(--relaya-color-border);--sp-btn-bg:var(--relaya-color-surface);--sp-btn-text:var(--relaya-color-text);--sp-avatar-bg:var(--relaya-color-accent);--sp-avatar-text:#fff;--sp-own-msg-bg:var(--relaya-color-own-msg-bg);--sp-own-msg-text:var(--relaya-color-own-msg-text);--sp-other-msg-bg:var(--relaya-color-other-msg-bg);--sp-other-msg-text:var(--relaya-color-other-msg-text);--sp-msg-font:inherit;--sp-msg-font-size:var(--relaya-font-size-base);--sp-time-color:var(--relaya-color-text-faint);--sp-send-btn-bg:var(--sp-own-msg-bg);--sp-send-btn-text:var(--sp-own-msg-text)}[data-theme=dark]{--relaya-color-bg:#0d1117;--relaya-color-surface:#161b22;--relaya-color-surface-2:#21262d;--relaya-color-border:#30363d;--relaya-color-text:#e6edf3;--relaya-color-text-muted:#8b949e;--relaya-color-text-faint:#484f58;--relaya-color-accent:#58a6ff;--relaya-color-accent-hover:#79b8ff;--relaya-color-danger:#f85149;--relaya-color-danger-hover:#ff7b72;--relaya-color-warning:#d29922;--relaya-color-success:#3fb950;--relaya-color-online:#3fb950;--relaya-color-shadow:#0006;--relaya-color-own-msg-bg:#1f6feb;--relaya-color-own-msg-text:#fff;--relaya-color-other-msg-bg:#21262d;--relaya-color-other-msg-text:#e6edf3;--relaya-color-deleted-bg:#2d333b;--relaya-color-deleted-text:#8b949e;--relaya-color-optimistic-bg:#1f3a5c;--relaya-color-failed-bg:#3d1f1f;--relaya-color-status-bar:#1c2128;--relaya-color-status-text:#e6edf3}:root,[data-theme=light]{--relaya-color-message-bg:var(--sp-other-msg-bg,var(--relaya-color-other-msg-bg));--relaya-color-message-own-bg:var(--sp-own-msg-bg,var(--relaya-color-own-msg-bg));--relaya-color-text-secondary:var(--relaya-color-text-muted);--relaya-color-input-bg:var(--relaya-color-surface-2);--relaya-color-input-text:var(--relaya-color-text);--relaya-color-btn-bg:var(--sp-send-btn-bg,var(--sp-own-msg-bg));--relaya-color-btn-text:var(--sp-send-btn-text,var(--sp-own-msg-text));--relaya-color-name-mod:var(--relaya-color-accent);--relaya-color-link:var(--relaya-color-accent);--relaya-color-link-active:var(--relaya-color-accent-hover)}.relaya-root .app{background:var(--relaya-color-bg);flex-direction:column;height:100%;display:flex}.relaya-root .chat-window{background:var(--relaya-color-surface);flex-direction:column;height:100%;display:flex}.relaya-root .chat-header{align-items:center;gap:var(--spacing-sm);padding:0 var(--spacing-md);height:var(--header-height);background:var(--sp-title-bg);border-bottom:1px solid color-mix(in srgb, var(--relaya-color-border) 40%, transparent);z-index:10;flex-shrink:0;display:flex;overflow:hidden}.relaya-root .chat-body{flex:1;min-height:0;display:flex;overflow:hidden}.relaya-root .message-list-container{flex-direction:column;flex:1;min-width:0;display:flex;position:relative;overflow:hidden}.relaya-root .message-list{padding:var(--spacing-md) var(--spacing-lg);gap:var(--spacing-xs);scroll-behavior:smooth;flex-direction:column;flex:1;display:flex;overflow-y:auto}.relaya-root .message-list::-webkit-scrollbar{width:6px}.relaya-root .message-list::-webkit-scrollbar-track{background:0 0}.relaya-root .message-list::-webkit-scrollbar-thumb{background:var(--relaya-color-border);border-radius:3px}.relaya-root .loading-screen{height:100%;color:var(--relaya-color-text-muted);font-size:var(--relaya-font-size-sm);justify-content:center;align-items:center;gap:var(--spacing-sm);display:flex}.relaya-root .btn{justify-content:center;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-lg);border-radius:var(--relaya-radius-md);font-size:var(--relaya-font-size-base);white-space:nowrap;font-weight:500;transition:background-color .15s,opacity .15s;display:inline-flex}.relaya-root .btn--primary{background:var(--relaya-color-accent);color:#fff;width:100%;padding:var(--spacing-md)}.relaya-root .btn--primary:hover:not(:disabled){background:var(--relaya-color-accent-hover)}.relaya-root .btn--danger{background:var(--relaya-color-danger);color:#fff}.relaya-root .btn--danger:hover:not(:disabled){background:var(--relaya-color-danger-hover)}.relaya-root .btn--ghost{color:var(--relaya-color-text-muted);border:1px solid var(--relaya-color-border);background:0 0}.relaya-root .btn--ghost:hover:not(:disabled){background:var(--relaya-color-surface-2)}.relaya-root .btn--icon{padding:var(--spacing-xs);color:var(--relaya-color-text-muted);border-radius:var(--relaya-radius-sm);flex-shrink:0;min-width:32px;min-height:32px}.relaya-root .btn--icon:hover{background:var(--relaya-color-surface-2);color:var(--relaya-color-text)}.relaya-root .btn:disabled{opacity:.55;cursor:not-allowed}.relaya-root .error-message{color:var(--relaya-color-danger);font-size:var(--relaya-font-size-sm);padding:var(--spacing-sm) var(--spacing-md);background:color-mix(in srgb, var(--relaya-color-danger) 10%, transparent);border-radius:var(--relaya-radius-sm)}.relaya-root .modal-overlay{z-index:100;padding:var(--spacing-lg);background:#00000080;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.relaya-root .modal{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-lg);padding:var(--spacing-xl);width:100%;max-width:440px;box-shadow:0 8px 32px var(--relaya-color-shadow)}.relaya-root .modal__title{font-size:var(--relaya-font-size-base);margin-bottom:var(--spacing-md);font-weight:600}.relaya-root .modal__body{margin-bottom:var(--spacing-lg)}.relaya-root .modal__body p{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin-bottom:var(--spacing-sm);line-height:1.5}.relaya-root .modal__body label{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin-bottom:var(--spacing-xs);margin-top:var(--spacing-md);font-weight:500;display:block}.relaya-root .modal__body select,.relaya-root .modal__body input,.relaya-root .modal__body textarea{width:100%;padding:var(--spacing-sm) var(--spacing-md);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);background:var(--relaya-color-surface-2);color:var(--relaya-color-text);font-size:var(--relaya-font-size-sm)}.relaya-root .modal__body select:focus,.relaya-root .modal__body input:focus,.relaya-root .modal__body textarea:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .modal__body textarea{resize:vertical;min-height:80px}.relaya-root .modal__footer{gap:var(--spacing-sm);justify-content:flex-end;display:flex}.relaya-root .login-screen{height:100%;padding:var(--spacing-lg);justify-content:center;align-items:center;display:flex}.relaya-root .login-card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-lg);padding:var(--spacing-xl) var(--spacing-xl);width:100%;max-width:400px;box-shadow:0 4px 24px var(--relaya-color-shadow)}.relaya-root .login-card__logo{text-align:center;margin-bottom:var(--spacing-xl)}.relaya-root .login-card__title{font-size:var(--relaya-font-size-lg);color:var(--relaya-color-text);margin-bottom:var(--spacing-xs);text-align:center;font-weight:600}.relaya-root .login-card__subtitle{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);text-align:center;margin-bottom:var(--spacing-xl)}.relaya-root .login-card__form{gap:var(--spacing-md);flex-direction:column;display:flex}.relaya-root .form-field label{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin-bottom:var(--spacing-xs);font-weight:500;display:block}.relaya-root .form-field input{width:100%;padding:var(--spacing-sm) var(--spacing-md);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);background:var(--relaya-color-surface-2);color:var(--relaya-color-text);font-size:var(--relaya-font-size-base);transition:border-color .15s}.relaya-root .form-field input:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .magic-link-sent{height:100%;padding:var(--spacing-lg);justify-content:center;align-items:center;display:flex}.relaya-root .magic-link-sent__card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-lg);padding:var(--spacing-xl);text-align:center;width:100%;max-width:400px;box-shadow:0 4px 24px var(--relaya-color-shadow)}.relaya-root .magic-link-sent__icon{margin-bottom:var(--spacing-lg);font-size:48px}.relaya-root .magic-link-sent__title{font-size:var(--relaya-font-size-lg);margin-bottom:var(--spacing-sm);font-weight:600}.relaya-root .magic-link-sent__body{color:var(--relaya-color-text-muted);font-size:var(--relaya-font-size-sm);margin-bottom:var(--spacing-xl);line-height:1.6}.relaya-root .modal-overlay{z-index:1000;background:#00000080;animation:.2s ease-out fadeIn;position:fixed;inset:0}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.relaya-root .auth-modal{z-index:1001;padding:var(--spacing-lg);justify-content:center;align-items:center;animation:.3s ease-out slideUp;display:flex;position:fixed;inset:0}@keyframes slideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.relaya-root .auth-modal__content{background:var(--relaya-color-surface);border-radius:var(--relaya-radius-lg);padding:var(--spacing-xl);width:100%;max-width:400px;box-shadow:0 8px 32px var(--relaya-color-shadow);gap:var(--spacing-lg);flex-direction:column;display:flex;position:relative}.relaya-root .auth-modal__close-x{top:var(--spacing-md);right:var(--spacing-md);border-radius:var(--relaya-radius-sm);width:32px;height:32px;color:var(--relaya-color-text-muted);cursor:pointer;background:0 0;justify-content:center;align-items:center;font-size:20px;line-height:1;transition:background-color .15s,color .15s;display:flex;position:absolute}.relaya-root .auth-modal__close-x:hover{background:var(--relaya-color-surface-2);color:var(--relaya-color-text)}.relaya-root .auth-modal__icon{text-align:center;font-size:48px;line-height:1}.relaya-root .auth-modal__title{font-size:var(--relaya-font-size-lg);color:var(--relaya-color-text);text-align:center;margin:0;font-weight:600;line-height:1.3}.relaya-root .auth-modal__message{font-size:var(--relaya-font-size-base);color:var(--relaya-color-text);text-align:center;margin:0;line-height:1.5}.relaya-root .auth-modal__hint{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);text-align:center;margin:0;line-height:1.4}.relaya-root .auth-modal__input{width:100%;padding:12px var(--spacing-md);font-size:var(--relaya-font-size-base);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);background:var(--relaya-color-surface);color:var(--relaya-color-text);font-family:inherit;transition:border-color .2s}.relaya-root .auth-modal__input:focus{border-color:var(--relaya-color-accent);outline:none;box-shadow:0 0 0 3px #007aff1a}.relaya-root .auth-modal__input:disabled{opacity:.6;cursor:not-allowed}.relaya-root .auth-modal__buttons{gap:var(--spacing-md);justify-content:flex-end;display:flex}.relaya-root .auth-modal__close-btn{width:100%}.relaya-root .auth-success{height:100%;padding:var(--spacing-lg);justify-content:center;align-items:center;display:flex}.relaya-root .auth-success__card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-lg);padding:var(--spacing-xl);text-align:center;width:100%;max-width:480px;box-shadow:0 4px 24px var(--relaya-color-shadow)}.relaya-root .auth-success .success-icon{margin-bottom:var(--spacing-lg);font-size:64px;line-height:1}.relaya-root .auth-success h1{font-size:var(--relaya-font-size-xl);margin-bottom:var(--spacing-sm);color:var(--relaya-color-text);font-weight:600}.relaya-root .auth-success .user-greeting{font-size:var(--relaya-font-size-base);color:var(--relaya-color-text-muted);margin-bottom:var(--spacing-xl)}.relaya-root .auth-success .instructions{margin-bottom:var(--spacing-xl)}.relaya-root .auth-success .instructions p{font-size:var(--relaya-font-size-base);color:var(--relaya-color-text);margin-bottom:var(--spacing-md);line-height:1.6}.relaya-root .auth-success .instructions p:last-child{margin-bottom:0}.relaya-root .auth-success .hint{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted)}.relaya-root .auth-success .btn{min-width:140px}.relaya-root .otp-code-input{flex-direction:column;align-items:center;gap:20px;width:100%;display:flex}.relaya-root .otp-code-input__icon{font-size:48px;line-height:1}.relaya-root .otp-code-input__title{color:var(--relaya-color-text);text-align:center;margin:0;font-size:24px;font-weight:600}.relaya-root .otp-code-input__hint{color:var(--relaya-color-text-muted);text-align:center;margin:0;font-size:14px;line-height:1.5}.relaya-root .otp-code-input__hint strong{color:var(--relaya-color-text);font-weight:500}.relaya-root .otp-code-input__field{letter-spacing:.5em;text-align:center;border:2px solid var(--relaya-color-border);background:var(--relaya-color-surface);width:100%;max-width:240px;color:var(--relaya-color-text);border-radius:8px;padding:16px 12px;font-family:Courier New,Courier,monospace;font-size:28px;font-weight:600;transition:all .2s}@media (width<=600px){.relaya-root .otp-code-input__field{letter-spacing:.4em;padding:14px 10px;font-size:24px}}.relaya-root .otp-code-input__field:focus{border-color:var(--relaya-color-accent);outline:none;box-shadow:0 0 0 3px #007aff1a}.relaya-root .otp-code-input__field:disabled{opacity:.6;cursor:not-allowed}.relaya-root .otp-code-input__field::placeholder{opacity:.3}.relaya-root .otp-code-input__error{color:#ff3b30;text-align:center;background:#ff3b301a;border:1px solid #ff3b304d;border-radius:6px;width:100%;padding:12px 16px;font-size:14px}.relaya-root .otp-code-input__actions{flex-wrap:wrap;justify-content:center;gap:12px;width:100%;display:flex}@media (width<=400px){.relaya-root .otp-code-input__actions{flex-direction:column;gap:8px}.relaya-root .otp-code-input__actions .btn{width:100%}}.relaya-root .otp-code-input__auto-submit{color:var(--relaya-color-text-muted);margin:0;font-size:13px;font-style:italic}.relaya-root .auth-modal__error{color:#ff3b30;text-align:center;background:#ff3b301a;border:1px solid #ff3b304d;border-radius:6px;width:100%;margin-top:8px;padding:12px 16px;font-size:14px}.relaya-root .mention-chip{background:var(--relaya-color-surface-2);border:1px solid var(--relaya-color-message-own-bg);border-radius:var(--relaya-radius-sm);color:var(--relaya-color-message-own-bg);white-space:nowrap;padding:0 4px;font-size:.9em;font-weight:600;display:inline}.relaya-root .mention-chip--self{background:var(--relaya-color-message-own-bg);border-color:var(--relaya-color-message-own-bg);color:var(--sp-own-msg-text)}.relaya-root .chat-header__title{font-size:var(--relaya-font-size-base);font-weight:600;font-family:var(--sp-name-font);color:var(--sp-name-color);white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.relaya-root .chat-header__online{font-size:var(--relaya-font-size-sm);color:var(--sp-online-color);white-space:nowrap;border-radius:var(--relaya-radius-sm);flex-shrink:0;align-items:center;gap:2px;padding:4px 6px;transition:opacity .15s;display:flex}.relaya-root .chat-header__online:hover{opacity:.7}.relaya-root .online-dot{background:var(--relaya-color-online);border-radius:50%;flex-shrink:0;width:8px;height:8px}.relaya-root .chat-header .btn--ghost{background:var(--sp-btn-bg);border:1px solid var(--sp-btn-border);color:var(--sp-btn-text);padding:3px 10px;font-size:12px}.relaya-root .chat-header .btn--ghost:hover:not(:disabled){opacity:.85;background:var(--sp-btn-bg)}.relaya-root .chat-header .btn--primary{background:var(--sp-btn-bg);color:var(--sp-btn-text);width:auto;padding:3px 10px;font-size:12px}.relaya-root .chat-header .btn--primary:hover:not(:disabled){opacity:.85;background:var(--sp-btn-bg)}.relaya-root .chat-name-btn{min-width:0;max-width:120px;overflow:hidden}.relaya-root .chat-name-btn__label{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.relaya-root .chat-header__popout{flex-shrink:0;line-height:0;padding:4px 6px!important}.relaya-root .chat-header .chat-name-editor__display{font-size:12px;color:var(--sp-no-name-color)!important}.relaya-root .chat-name-editor__input{border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-surface);color:var(--relaya-color-text);max-width:140px;padding:3px 8px;font-size:13px}.relaya-root .chat-name-editor__input:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .retention-boundary{padding:var(--spacing-sm) var(--spacing-md);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint);text-align:center;border-top:1px solid var(--relaya-color-border);margin-bottom:var(--spacing-sm);justify-content:center;align-items:center;display:flex}.relaya-root .load-older-btn{padding:var(--spacing-sm);flex-shrink:0;justify-content:center;display:flex}.relaya-root .load-older-btn button{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-accent);padding:var(--spacing-xs) var(--spacing-md);border-radius:var(--relaya-radius-sm)}.relaya-root .load-older-btn button:hover:not(:disabled){background:var(--relaya-color-surface-2)}.relaya-root .messages-empty{color:var(--relaya-color-text-faint);font-size:var(--relaya-font-size-sm);text-align:center;padding:var(--spacing-xl);flex:1;justify-content:center;align-items:center;display:flex}.relaya-root .message-item{--message-avatar-slot-width:32px;gap:var(--spacing-sm);align-items:flex-start;max-width:85%;display:flex;position:relative}.relaya-root .message-item--has-image{max-width:100%}.relaya-root .message-item--has-image.message-item--other .message-item__bubble-wrap{max-width:calc(100% - var(--message-avatar-slot-width) - var(--spacing-sm))}.relaya-root .message-item--has-image.message-item--own .message-item__bubble-wrap{max-width:100%}.relaya-root .message-item--own{flex-direction:row-reverse;align-self:flex-end}.relaya-root .message-item--other{align-self:flex-start}.relaya-root .message-item--deleted{opacity:.65}.relaya-root .message-item__avatar{background:var(--sp-avatar-bg);width:48px;height:48px;color:var(--sp-avatar-text);font-size:var(--relaya-font-size-xs);border-radius:4px;flex-shrink:0;justify-content:center;align-items:center;font-weight:600;display:flex}.relaya-root .message-item__avatar-column{flex-direction:column;flex-shrink:0;align-items:flex-start;gap:2px;display:flex}.relaya-root .message-item__avatar-slot{width:var(--message-avatar-slot-width);flex-shrink:0;justify-content:center;padding-top:16px;display:flex}.relaya-root .message-item--own .message-item__avatar-slot{margin-left:3px}.relaya-root .message-item--other .message-item__avatar-slot{margin-right:3px;padding-top:0}.relaya-root .message-item__avatar-column .message-item__avatar-slot{padding-top:0}.relaya-root .message-item__avatar--image{object-fit:cover}.relaya-root .message-item__bubble-wrap{flex-direction:column;min-width:0;display:flex}.relaya-root .message-item--own .message-item__bubble-wrap{align-items:flex-end}.relaya-root .message-item__name-row{align-items:baseline;gap:var(--spacing-sm);padding:0 var(--spacing-sm) 2px;width:100%;min-width:0;display:flex}.relaya-root .message-item--other .message-item__name-row{justify-content:space-between}.relaya-root .message-item--own .message-item__name-row{justify-content:flex-end}.relaya-root .message-item__author--mod{color:var(--relaya-color-name-mod)}.relaya-root .message-item__author{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.relaya-root .message-item__time{font-size:var(--relaya-font-size-xs);color:var(--sp-time-color);white-space:nowrap;flex-shrink:0}.relaya-root .message-item__status-row{align-items:center;gap:var(--spacing-xs);padding:2px var(--spacing-sm) 0;display:flex}.relaya-root .message-item__status{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint)}.relaya-root .message-item__bubble{padding:var(--spacing-sm) var(--spacing-md);border-radius:var(--relaya-radius-bubble);font-family:var(--sp-msg-font);font-size:var(--sp-msg-font-size);word-break:break-word;line-height:1.4;position:relative}.relaya-root .message-link{color:var(--relaya-color-link);word-break:break-all;text-decoration:underline}.relaya-root .message-link:hover,.relaya-root .message-link:active{color:var(--relaya-color-link-active)}.relaya-root .message-item__bubble strong{font-weight:700}.relaya-root .message-item__bare-image-wrap{max-width:100%}.relaya-root .chat-image{justify-content:center;align-items:center;max-width:100%;display:inline-flex;position:relative}.relaya-root .chat-image--inline{vertical-align:middle;margin:1px 2px}.relaya-root .chat-image--bare{display:block}.relaya-root .chat-image__img{width:auto;max-width:100%;height:auto;transition:opacity .15s;display:block}.relaya-root .chat-image__loading{background:color-mix(in srgb, var(--relaya-color-text-faint) 20%, transparent);border-radius:999px;justify-content:center;align-items:center;gap:4px;min-width:56px;min-height:32px;padding:6px 8px;display:inline-flex}.relaya-root .chat-image__loading>span{background:var(--relaya-color-text-muted);border-radius:50%;width:6px;height:6px;animation:.9s ease-in-out infinite chat-image-dot-pulse}.relaya-root .chat-image__loading>span:nth-child(2){animation-delay:.12s}.relaya-root .chat-image__loading>span:nth-child(3){animation-delay:.24s}@keyframes chat-image-dot-pulse{0%,80%,to{opacity:.45;transform:scale(.7)}40%{transform:scale(1)}}.relaya-root .chat-image__fallback{border-radius:var(--relaya-radius-sm);border:1px dashed var(--relaya-color-border);min-width:120px;min-height:32px;color:var(--relaya-color-text-muted);font-size:var(--relaya-font-size-xs);background:var(--relaya-color-surface-2);justify-content:center;align-items:center;padding:6px 10px;display:inline-flex}.relaya-root .message-item--own .message-item__bubble{background:var(--relaya-color-message-own-bg);color:var(--sp-own-msg-text);border-bottom-right-radius:var(--relaya-radius-sm)}.relaya-root .message-item--other .message-item__bubble{background:var(--relaya-color-message-bg);color:var(--sp-other-msg-text);border-bottom-left-radius:var(--relaya-radius-sm)}.relaya-root .message-item--deleted .message-item__bubble{background:var(--relaya-color-deleted-bg);color:var(--relaya-color-deleted-text);font-style:italic;font-size:var(--relaya-font-size-sm)}.relaya-root .message-item--optimistic .message-item__bubble{background:var(--relaya-color-optimistic-bg);opacity:.85}.relaya-root .message-item--failed .message-item__bubble{background:var(--relaya-color-failed-bg)}.relaya-root .scroll-to-bottom{bottom:var(--spacing-md);right:var(--spacing-lg);background:var(--relaya-color-accent);color:#fff;width:36px;height:36px;box-shadow:0 2px 8px var(--relaya-color-shadow);z-index:5;border-radius:50%;justify-content:center;align-items:center;font-size:18px;display:flex;position:absolute}.relaya-root .scroll-to-bottom:hover{background:var(--relaya-color-accent-hover)}.relaya-root .message-item__kebab-btn{width:18px;height:18px;color:var(--relaya-color-text-faint);border-radius:var(--relaya-radius-sm);cursor:pointer;background:0 0;flex-shrink:0;justify-content:center;align-items:center;padding:0;font-size:15px;line-height:1;display:none;position:relative}.relaya-root .message-item__kebab-btn:active{color:var(--relaya-color-text-muted);background:#00000014}.relaya-root .message-item__kebab-menu{z-index:200;background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);min-width:140px;box-shadow:0 4px 16px var(--relaya-color-shadow);position:fixed;overflow:hidden}.relaya-root .message-item__kebab-menu__item{align-items:center;gap:var(--spacing-sm);width:100%;padding:10px var(--spacing-md);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);text-align:left;cursor:pointer;white-space:nowrap;background:0 0;border:none;font-family:inherit;display:flex}.relaya-root .message-item__kebab-menu__item:hover,.relaya-root .message-item__kebab-menu__item:active{background:var(--relaya-color-surface-2)}.relaya-root .message-item__kebab-menu__item--danger{color:var(--relaya-color-danger)}.relaya-root .kebab-overlay{z-index:199;position:fixed;inset:0}.relaya-root .connection-status{justify-content:center;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-xs) var(--spacing-md);font-size:var(--relaya-font-size-xs);flex-shrink:0;font-weight:500;display:flex}.relaya-root .connection-status--connecting,.relaya-root .connection-status--reconnecting{background:var(--relaya-color-warning);color:#1a1a2e}.relaya-root .connection-status--disconnected{background:var(--relaya-color-danger);color:#fff}.relaya-root .connection-status--connected{display:none}.relaya-root .connection-spinner{border:2px solid;border-top-color:#0000;border-radius:50%;width:12px;height:12px;animation:.8s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.relaya-root .relaya-branding{text-align:center;color:var(--relaya-color-text);border-top:1px solid var(--relaya-color-border,#ffffff14);flex-shrink:0;padding:4px 8px;font-size:11px}.relaya-root .relaya-branding a{color:inherit;text-decoration:none;transition:opacity .15s}.relaya-root .relaya-branding a:hover{opacity:.75;text-decoration:underline}.relaya-root .message-input-bar{align-items:flex-end;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-lg);border-top:1px solid var(--relaya-color-border);background:var(--relaya-color-surface);flex-shrink:0;display:flex;position:relative}.relaya-root .sticker-btn{border:1px solid var(--relaya-color-border);background:var(--relaya-color-surface-2);width:36px;height:36px;color:var(--relaya-color-text-muted);border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;transition:background-color .15s,color .15s;display:flex}.relaya-root .sticker-btn:hover:not(:disabled){background:var(--relaya-color-surface);color:var(--relaya-color-text)}.relaya-root .sticker-btn:disabled{opacity:.45;cursor:not-allowed}.relaya-root .message-input{min-height:36px;max-height:120px;padding:var(--spacing-sm) var(--spacing-md);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-bubble);background:var(--relaya-color-input-bg);color:var(--relaya-color-input-text);font-size:var(--relaya-font-size-base);font-family:var(--sp-msg-font);resize:none;flex:1;line-height:1.4;transition:border-color .15s;overflow-y:auto}.relaya-root .message-input:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .message-input::placeholder{color:var(--relaya-color-text-faint)}.relaya-root .message-input:disabled{opacity:.55}.relaya-root .send-btn{background:var(--relaya-color-btn-bg);width:36px;height:36px;color:var(--relaya-color-btn-text);border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;transition:opacity .15s;display:flex}.relaya-root .send-btn:hover:not(:disabled){opacity:.85}.relaya-root .send-btn:disabled{opacity:.4;cursor:not-allowed}.relaya-root .sticker-picker__overlay{z-index:170;background:#00000059;position:fixed;inset:0}.relaya-root .sticker-picker{left:50%;bottom:calc(var(--input-height) + var(--spacing-md));border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-lg);background:var(--relaya-color-surface);width:min(92vw,920px);max-height:min(70vh,620px);box-shadow:0 10px 32px var(--relaya-color-shadow);z-index:171;flex-direction:column;display:flex;position:fixed;transform:translate(-50%)}.relaya-root .sticker-picker__header{padding:var(--spacing-sm) var(--spacing-md);border-bottom:1px solid var(--relaya-color-border);font-size:var(--relaya-font-size-sm);justify-content:space-between;align-items:center;font-weight:600;display:flex}.relaya-root .sticker-picker__close{min-width:28px;min-height:28px}.relaya-root .sticker-picker__body{padding:var(--spacing-md);overflow-y:auto}.relaya-root .sticker-picker__state{color:var(--relaya-color-text-muted);font-size:var(--relaya-font-size-sm);padding:var(--spacing-lg) var(--spacing-sm)}.relaya-root .sticker-picker__grid{gap:var(--spacing-sm);grid-template-columns:repeat(auto-fill,minmax(128px,1fr));display:grid}.relaya-root .sticker-picker__item{aspect-ratio:1;border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);background:var(--relaya-color-surface-2);justify-content:center;align-items:center;gap:var(--spacing-xs);width:100%;padding:var(--spacing-xs);flex-direction:column;display:flex;overflow:hidden}.relaya-root .sticker-picker__item:hover{border-color:var(--relaya-color-accent);background:var(--relaya-color-surface)}.relaya-root .sticker-picker__item img{object-fit:contain;width:auto;max-width:100%;height:auto;max-height:calc(100% - 20px)}.relaya-root .sticker-picker__item-label{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);line-height:1.2}.relaya-root .sticker-suggestions{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);box-shadow:0 8px 24px var(--relaya-color-shadow);z-index:175;flex-direction:column;max-height:220px;display:flex;position:absolute;bottom:calc(100% + 8px);left:56px;right:52px;overflow-y:auto}.relaya-root .sticker-suggestions__item{align-items:center;gap:var(--spacing-sm);width:100%;padding:var(--spacing-sm) var(--spacing-md);text-align:left;display:flex}.relaya-root .sticker-suggestions__item:hover{background:var(--relaya-color-surface-2)}.relaya-root .sticker-suggestions__item img{object-fit:contain;flex-shrink:0;width:32px;height:32px}.relaya-root .sticker-suggestions__code{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text)}.relaya-root .mention-suggestions{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);box-shadow:0 8px 24px var(--relaya-color-shadow);z-index:175;flex-direction:column;min-width:120px;max-height:200px;display:flex;position:absolute;bottom:calc(100% + 8px);left:56px;overflow-y:auto}.relaya-root .mention-suggestions__item{align-items:center;gap:var(--spacing-xs);width:100%;padding:var(--spacing-sm) var(--spacing-md);text-align:left;font-size:var(--relaya-font-size-sm);display:flex}.relaya-root .mention-suggestions__item:hover,.relaya-root .mention-suggestions__item--highlighted{background:var(--relaya-color-surface-2)}.relaya-root .mention-suggestions__at{color:var(--relaya-color-accent);flex-shrink:0;font-weight:700}.relaya-root .mention-suggestions__name{color:var(--relaya-color-text);text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.relaya-root .user-list{width:var(--sidebar-width);border-left:1px solid var(--relaya-color-border);background:var(--relaya-color-surface-2);padding:var(--spacing-md);gap:var(--spacing-sm);flex-direction:column;flex-shrink:0;display:none;overflow-y:auto}.relaya-root .user-list__title{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);text-transform:uppercase;letter-spacing:.05em;padding-bottom:var(--spacing-xs);border-bottom:1px solid var(--relaya-color-border);font-weight:600}.relaya-root .user-list__item{align-items:center;gap:var(--spacing-sm);padding:var(--spacing-xs);border-radius:var(--relaya-radius-sm);font-size:var(--relaya-font-size-sm);display:flex}.relaya-root .user-list__avatar{background:var(--sp-avatar-bg);width:24px;height:24px;color:var(--sp-avatar-text);font-size:var(--relaya-font-size-xs);border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-weight:600;display:flex}.relaya-root .user-list__name{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--relaya-color-text);flex:1;overflow:hidden}.relaya-root .user-list__self-badge{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint)}.relaya-root .pane-divider{cursor:col-resize;background:var(--relaya-color-border);flex-shrink:0;width:5px;transition:background .15s;display:none}.relaya-root .pane-divider:hover{background:var(--relaya-color-text-faint)}.relaya-root .user-list-modal__header{justify-content:space-between;align-items:center;display:flex}.relaya-root .user-list-modal__body{max-height:50vh;padding-right:var(--spacing-xs);margin-bottom:0;overflow-y:auto}.relaya-root .user-list-modal__item{padding:var(--spacing-xs) 0}.relaya-root .user-list-modal__close{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);padding:var(--spacing-xs)}.relaya-root .user-list-modal__close:hover{color:var(--relaya-color-text);background:var(--relaya-color-surface-2);border-radius:var(--relaya-radius-sm)}.relaya-root .admin-panel{background:var(--relaya-color-bg);height:100%;overflow-y:auto}.relaya-root .admin-panel__header{padding:var(--spacing-xl) var(--spacing-xl) var(--spacing-lg);border-bottom:1px solid var(--relaya-color-border);background:var(--relaya-color-surface)}.relaya-root .admin-panel__title{color:var(--relaya-color-text);margin:0;font-size:22px;font-weight:600}.relaya-root .admin-panel__subtitle{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin:var(--spacing-xs) 0 0}.relaya-root .admin-panel__loading,.relaya-root .admin-panel__unauthorized{justify-content:center;align-items:center;gap:var(--spacing-md);height:100%;color:var(--relaya-color-text-muted);font-size:var(--relaya-font-size-sm);text-align:center;padding:var(--spacing-xl);flex-direction:column;display:flex}.relaya-root .admin-settings{border-top:1px solid var(--relaya-color-border);background:var(--relaya-color-surface-2);padding:var(--spacing-md) var(--spacing-lg)}.relaya-root .admin-settings__toggle{align-items:center;gap:var(--spacing-sm);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);width:100%;padding:0;font-weight:500;display:flex}.relaya-root .admin-settings__toggle:hover{color:var(--relaya-color-text)}.relaya-root .admin-settings__panel{margin-top:var(--spacing-md)}.relaya-root .admin-settings__section{justify-content:space-between;align-items:center;gap:var(--spacing-md);margin-bottom:var(--spacing-md);display:flex}.relaya-root .admin-settings__section-copy{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);flex-direction:column;gap:2px;display:flex}.relaya-root .admin-settings__section-copy strong{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text)}.relaya-root .admin-settings__notice{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text);background:color-mix(in srgb, var(--relaya-color-warning) 15%, transparent);border-left:3px solid var(--relaya-color-warning);padding:var(--spacing-sm) var(--spacing-md);border-radius:var(--relaya-radius-sm);margin-bottom:var(--spacing-md);line-height:1.4}.relaya-root .admin-settings__grid{gap:var(--spacing-md);margin-bottom:var(--spacing-md);grid-template-columns:repeat(auto-fit,minmax(160px,1fr));display:grid}.relaya-root .admin-settings__field label{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);margin-bottom:var(--spacing-xs);font-weight:500;display:block}.relaya-root .admin-settings__field input{width:100%;padding:var(--spacing-xs) var(--spacing-sm);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-surface);color:var(--relaya-color-text);font-size:var(--relaya-font-size-sm)}.relaya-root .sticker-admin-page{background:var(--relaya-color-bg);flex-direction:column;gap:6px;min-height:100%;padding:8px;display:flex;overflow-y:auto}.relaya-root .sticker-admin-page__topbar{justify-content:space-between;align-items:flex-start;gap:8px;display:flex}.relaya-root .sticker-admin-page__title-group{flex-direction:column;gap:2px;min-width:0;display:flex}.relaya-root .sticker-admin-page__title-row{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.relaya-root .sticker-admin-page__header{justify-content:space-between;align-items:flex-start;gap:var(--spacing-md);display:flex}.relaya-root .sticker-admin-page__back{margin-bottom:0;font-size:12px;padding:3px 8px!important}.relaya-root .sticker-admin-page__title{font-size:18px;line-height:1.1}.relaya-root .sticker-admin-page__subtitle{color:var(--relaya-color-text-muted);margin-top:0;font-size:12px}.relaya-root .sticker-admin-page__status-inline{background:color-mix(in srgb, var(--relaya-color-success) 10%, transparent);min-height:18px;color:var(--relaya-color-success);border-radius:999px;align-items:center;gap:4px;width:fit-content;max-width:100%;padding:1px 8px;font-size:11px;line-height:1.2;display:inline-flex}.relaya-root .sticker-admin-page__header-actions{flex-shrink:0;gap:6px;display:flex}.relaya-root .sticker-admin-page__header-actions .btn{min-height:32px;padding:3px 10px;font-size:12px}.relaya-root .sticker-admin-page__notice,.relaya-root .sticker-admin-page__error,.relaya-root .sticker-admin-page__success,.relaya-root .sticker-admin-page__state{border-radius:var(--relaya-radius-md);padding:6px 10px;font-size:12px}.relaya-root .sticker-admin-page__notice{background:color-mix(in srgb, var(--relaya-color-accent) 10%, transparent);color:var(--relaya-color-text)}.relaya-root .sticker-admin-page__error{background:color-mix(in srgb, var(--relaya-color-danger) 10%, transparent);color:var(--relaya-color-danger)}.relaya-root .sticker-admin-page__success{background:color-mix(in srgb, var(--relaya-color-success) 10%, transparent);color:var(--relaya-color-success)}.relaya-root .sticker-admin-page__toolbar{justify-content:space-between;align-items:center;gap:var(--spacing-sm);display:flex}.relaya-root .sticker-admin-page__count{color:var(--relaya-color-text-muted);font-size:12px;line-height:1}.relaya-root .sticker-admin-grid{grid-template-columns:repeat(auto-fill,minmax(116px,1fr));gap:6px;display:grid}.relaya-root .sticker-admin-card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:10px;flex-direction:column;transition:border-color .15s,box-shadow .15s,opacity .15s,transform .15s;display:flex;overflow:hidden}.relaya-root .sticker-admin-card--dragging{opacity:.45;transform:scale(.98)}.relaya-root .sticker-admin-card--drop-target{border-color:var(--relaya-color-accent);box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--relaya-color-accent) 65%, transparent)}.relaya-root .sticker-admin-card__preview{background:var(--relaya-color-surface-2);flex-direction:column;justify-content:center;align-items:center;gap:4px;min-height:122px;padding:4px;display:flex}.relaya-root .sticker-admin-card__preview--draggable{cursor:grab;-webkit-user-select:none;user-select:none;position:relative}.relaya-root .sticker-admin-card__preview--draggable:active{cursor:grabbing}.relaya-root .sticker-admin-card__preview img{object-fit:contain;width:96px;max-width:96px;height:auto;max-height:96px}.relaya-root .sticker-admin-card__drag-badge{background:color-mix(in srgb, var(--relaya-color-surface) 92%, transparent);border:1px solid color-mix(in srgb, var(--relaya-color-border) 90%, transparent);min-height:20px;color:var(--relaya-color-text-muted);pointer-events:none;border-radius:999px;justify-content:center;align-items:center;gap:4px;padding:4px 8px;font-size:9px;line-height:1;display:inline-flex;position:static}.relaya-root .sticker-admin-card__drag-badge svg{width:10px;height:10px;display:block}.relaya-root .sticker-admin-card__body{flex-direction:column;gap:4px;padding:4px;display:flex}.relaya-root .sticker-admin-card__filename{color:var(--relaya-color-text);text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:600;overflow:hidden}.relaya-root .sticker-admin-card__field{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);flex-direction:column;gap:0;display:flex}.relaya-root .sticker-admin-card__shortcode-input{border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-surface-2);align-items:center;gap:4px;padding:0 4px;display:flex}.relaya-root .sticker-admin-card__shortcode-input input{background:0 0;border:none;flex:1;min-width:0;padding:4px 0;font-size:11px}.relaya-root .sticker-admin-card__shortcode-input input:focus{outline:none}.relaya-root .sticker-admin-card__meta{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint);flex-direction:column;gap:2px;display:flex}.relaya-root .sticker-admin-card__actions{flex-wrap:wrap;gap:3px;display:flex}.relaya-root .sticker-admin-card__actions .btn{min-height:20px;padding:2px 6px;font-size:10px;line-height:1}.relaya-root .report-review{border-top:1px solid var(--relaya-color-border);background:var(--relaya-color-surface-2);padding:var(--spacing-md) var(--spacing-lg)}.relaya-root .report-review__toggle{align-items:center;gap:var(--spacing-sm);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);width:100%;padding:0;font-weight:500;display:flex}.relaya-root .report-review__toggle:hover{color:var(--relaya-color-text)}.relaya-root .report-review__badge{min-width:18px;height:18px;margin-left:var(--spacing-sm);background:var(--relaya-color-danger);color:#fff;font-size:var(--relaya-font-size-xs);border-radius:9px;justify-content:center;align-items:center;padding:0 5px;font-weight:600;line-height:1;display:inline-flex}.relaya-root .report-review__panel{margin-top:var(--spacing-md);gap:var(--spacing-sm);flex-direction:column;max-height:360px;display:flex;overflow-y:auto}.relaya-root .report-review__loading,.relaya-root .report-review__empty{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);padding:var(--spacing-sm) 0}.relaya-root .report-review__error{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-danger);padding:var(--spacing-sm) 0}.relaya-root .report-card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);padding:var(--spacing-sm) var(--spacing-md);gap:var(--spacing-xs);flex-direction:column;display:flex}.relaya-root .report-card__meta{justify-content:space-between;align-items:center;gap:var(--spacing-sm);display:flex}.relaya-root .report-card__reason{font-size:var(--relaya-font-size-xs);text-transform:capitalize;color:var(--relaya-color-text-muted);background:color-mix(in srgb, var(--relaya-color-warning) 15%, transparent);border-radius:var(--relaya-radius-sm);padding:1px 6px;font-weight:600}.relaya-root .report-card__time{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint);flex-shrink:0}.relaya-root .report-card__message{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);word-break:break-word;padding:var(--spacing-xs) 0;border-top:1px solid var(--relaya-color-border);border-bottom:1px solid var(--relaya-color-border);line-height:1.4}.relaya-root .report-card__deleted{color:var(--relaya-color-text-muted)}.relaya-root .report-card__details{gap:var(--spacing-sm) var(--spacing-lg);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);flex-wrap:wrap;display:flex}.relaya-root .report-card__details strong{color:var(--relaya-color-text)}.relaya-root .report-card__actions{gap:var(--spacing-xs);padding-top:var(--spacing-xs);flex-wrap:wrap;display:flex}.relaya-root .report-review__pagination{justify-content:center;align-items:center;gap:var(--spacing-md);padding-top:var(--spacing-xs);display:flex}.relaya-root .report-review__page-info{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted)}.relaya-root .ban-management{border-top:1px solid var(--relaya-color-border);background:var(--relaya-color-surface-2);padding:var(--spacing-md) var(--spacing-lg)}.relaya-root .ban-management__toggle{align-items:center;gap:var(--spacing-sm);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);width:100%;padding:0;font-weight:500;display:flex}.relaya-root .ban-management__toggle:hover{color:var(--relaya-color-text)}.relaya-root .ban-management__badge{min-width:18px;height:18px;margin-left:var(--spacing-sm);background:var(--relaya-color-warning);color:#1a1a2e;font-size:var(--relaya-font-size-xs);border-radius:9px;justify-content:center;align-items:center;padding:0 5px;font-weight:600;line-height:1;display:inline-flex}.relaya-root .ban-management__panel{margin-top:var(--spacing-md);gap:var(--spacing-sm);flex-direction:column;max-height:320px;display:flex;overflow-y:auto}.relaya-root .ban-management__loading,.relaya-root .ban-management__empty{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);padding:var(--spacing-sm) 0}.relaya-root .ban-management__error{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-danger);padding:var(--spacing-sm) 0}.relaya-root .ban-card{background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);padding:var(--spacing-sm) var(--spacing-md);gap:var(--spacing-xs);flex-direction:column;display:flex}.relaya-root .ban-card__header{justify-content:space-between;align-items:center;gap:var(--spacing-sm);display:flex}.relaya-root .ban-card__user{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);font-weight:600}.relaya-root .ban-card__expiry{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);flex-shrink:0}.relaya-root .ban-card__expiry--permanent{color:var(--relaya-color-danger);font-weight:600}.relaya-root .ban-card__details{gap:var(--spacing-xs) var(--spacing-lg);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);flex-wrap:wrap;display:flex}.relaya-root .ban-card__details strong{color:var(--relaya-color-text)}.relaya-root .ban-card__actions{padding-top:var(--spacing-xs)}.relaya-root .theme-admin-page{min-height:100%;padding:var(--spacing-lg);gap:var(--spacing-md);flex-direction:column;display:flex;overflow-y:auto}.relaya-root .theme-admin-page__topbar{justify-content:space-between;align-items:flex-start;gap:var(--spacing-md);flex-wrap:wrap;display:flex}.relaya-root .theme-admin-page__title-group{flex:1;min-width:0}.relaya-root .theme-admin-page__title-row{align-items:center;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.relaya-root .theme-admin-page__back{flex-shrink:0;margin-bottom:0}.relaya-root .theme-admin-page__title{color:var(--relaya-color-text);margin:0;font-size:18px;font-weight:600}.relaya-root .theme-admin-page__subtitle{margin-top:var(--spacing-xs);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin-bottom:0}.relaya-root .theme-admin-page__status-inline{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-success);background:color-mix(in srgb, var(--relaya-color-success) 12%, transparent);border-radius:var(--relaya-radius-sm);align-items:center;padding:2px 8px;display:inline-flex}.relaya-root .theme-admin-page__header-actions{gap:var(--spacing-xs);flex-shrink:0;align-items:center;display:flex}.relaya-root .theme-admin-page__header-actions .btn{font-size:var(--relaya-font-size-sm);padding:3px 10px}.relaya-root .theme-admin-page__error,.relaya-root .theme-admin-page__state{border-radius:var(--relaya-radius-md);padding:var(--spacing-sm) var(--spacing-md);font-size:var(--relaya-font-size-sm)}.relaya-root .theme-admin-page__error{background:color-mix(in srgb, var(--relaya-color-danger) 10%, transparent);color:var(--relaya-color-danger)}.relaya-root .theme-admin-page__state{color:var(--relaya-color-text-muted);background:var(--relaya-color-surface)}.relaya-root .theme-admin-list{border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);flex-direction:column;gap:0;display:flex;overflow:hidden}.relaya-root .theme-admin-row{align-items:center;gap:var(--spacing-sm);padding:8px var(--spacing-sm);background:var(--relaya-color-surface);border-bottom:1px solid var(--relaya-color-border);grid-template-columns:36px 1fr 90px;transition:background .1s;display:grid}.relaya-root .theme-admin-row:last-child{border-bottom:none}.relaya-root .theme-admin-row:hover{background:color-mix(in srgb, var(--relaya-color-accent) 4%, var(--relaya-color-surface))}.relaya-root .theme-admin-row__swatch{border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);cursor:pointer;background:0 0;flex-shrink:0;width:32px;height:28px;padding:0}.relaya-root .theme-admin-row__label{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);white-space:nowrap;text-overflow:ellipsis;cursor:default;overflow:hidden}.relaya-root .theme-admin-row__hex{font-size:11px;font-family:var(--relaya-font-mono,monospace);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-bg);color:var(--relaya-color-text);width:100%;padding:3px 6px}.relaya-root .theme-admin-row__hex--invalid{border-color:var(--relaya-color-danger);color:var(--relaya-color-danger)}.relaya-root .theme-admin-row__hex:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .theme-admin-page__tabs{border-bottom:1px solid var(--relaya-color-border);margin-bottom:var(--spacing-xs);gap:2px;display:flex}.relaya-root .theme-admin-page__tab{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;margin-bottom:-1px;padding:6px 16px;transition:color .1s,border-color .1s}.relaya-root .theme-admin-page__tab:hover{color:var(--relaya-color-text)}.relaya-root .theme-admin-page__tab--active{color:var(--relaya-color-accent);border-bottom-color:var(--relaya-color-accent);font-weight:500}.relaya-root .geo-admin{gap:var(--spacing-lg);padding:var(--spacing-sm) 0;flex-direction:column;display:flex}.relaya-root .geo-admin__status{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);padding:var(--spacing-sm) 0}.relaya-root .geo-admin__status--unavailable{background:color-mix(in srgb, var(--relaya-color-warning) 10%, transparent);border-left:3px solid var(--relaya-color-warning);padding:var(--spacing-sm) var(--spacing-md);border-radius:var(--relaya-radius-sm);color:var(--relaya-color-text)}.relaya-root .geo-admin__status--error{color:var(--relaya-color-danger)}.relaya-root .geo-admin__action-error{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-danger);background:color-mix(in srgb, var(--relaya-color-danger) 8%, transparent);border-radius:var(--relaya-radius-sm);padding:var(--spacing-xs) var(--spacing-sm)}.relaya-root .geo-admin__section{gap:var(--spacing-sm);flex-direction:column;display:flex}.relaya-root .geo-admin__section-title{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);align-items:center;gap:var(--spacing-sm);border-bottom:1px solid var(--relaya-color-border);padding-bottom:var(--spacing-xs);margin:0;font-weight:600;display:flex}.relaya-root .geo-admin__badge{background:var(--relaya-color-warning);color:#1a1a2e;min-width:18px;height:18px;font-size:var(--relaya-font-size-xs);border-radius:9px;justify-content:center;align-items:center;padding:0 5px;font-weight:600;line-height:1;display:inline-flex}.relaya-root .geo-admin__field{gap:var(--spacing-xs);flex-direction:column;display:flex}.relaya-root .geo-admin__label{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);font-weight:500}.relaya-root .geo-admin__select,.relaya-root .geo-admin__input,.relaya-root .geo-admin__filter-input,.relaya-root .geo-admin__combobox-input{padding:var(--spacing-xs) var(--spacing-sm);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-surface);color:var(--relaya-color-text);font-size:var(--relaya-font-size-sm);width:100%}.relaya-root .geo-admin__select:focus,.relaya-root .geo-admin__input:focus,.relaya-root .geo-admin__filter-input:focus,.relaya-root .geo-admin__combobox-input:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .geo-admin__hint{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);margin:0}.relaya-root .geo-admin__hint--empty{font-style:italic}.relaya-root .geo-admin__chips{flex-wrap:wrap;gap:6px;display:flex}.relaya-root .geo-admin__chip{background:color-mix(in srgb, var(--relaya-color-accent) 12%, var(--relaya-color-surface));border:1px solid color-mix(in srgb, var(--relaya-color-accent) 30%, var(--relaya-color-border));font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text);border-radius:999px;align-items:center;gap:5px;padding:3px 8px 3px 10px;line-height:1;display:inline-flex}.relaya-root .geo-admin__chip-remove{width:16px;height:16px;color:var(--relaya-color-text-muted);cursor:pointer;background:0 0;border:none;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;padding:0;font-size:14px;line-height:1;transition:color .1s,background .1s;display:inline-flex}.relaya-root .geo-admin__chip-remove:hover{color:var(--relaya-color-danger);background:color-mix(in srgb, var(--relaya-color-danger) 12%, transparent)}.relaya-root .geo-admin__combobox{position:relative}.relaya-root .geo-admin__combobox-list{z-index:100;background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);max-height:220px;margin:0;padding:2px 0;list-style:none;position:absolute;top:calc(100% + 2px);left:0;right:0;overflow-y:auto;box-shadow:0 4px 12px #00000026}.relaya-root .geo-admin__combobox-item{width:100%;padding:6px var(--spacing-sm);text-align:left;font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:none;display:block;overflow:hidden}.relaya-root .geo-admin__combobox-item:hover{background:color-mix(in srgb, var(--relaya-color-accent) 10%, transparent);color:var(--relaya-color-accent)}.relaya-root .geo-admin__combobox-empty{padding:8px var(--spacing-sm);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);font-style:italic}.relaya-root .geo-admin__ban-list{flex-direction:column;gap:4px;max-height:300px;display:flex;overflow-y:auto}.relaya-root .geo-admin__ban-row{justify-content:space-between;align-items:center;gap:var(--spacing-sm);background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);padding:6px var(--spacing-sm);display:flex}.relaya-root .geo-admin__ban-info{align-items:baseline;gap:4px var(--spacing-sm);flex-wrap:wrap;min-width:0;display:flex}.relaya-root .geo-admin__ban-ip{font-family:var(--relaya-font-mono,monospace);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text);font-weight:600}.relaya-root .geo-admin__ban-reason{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted)}.relaya-root .geo-admin__ban-expiry{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-faint);flex-shrink:0}.relaya-root .geo-admin__lift-btn{flex-shrink:0;min-height:22px;padding:2px 8px;font-size:11px}.relaya-root .geo-admin__add-toggle{align-items:center;gap:var(--spacing-xs);font-size:var(--relaya-font-size-xs);color:var(--relaya-color-accent);cursor:pointer;margin-top:var(--spacing-xs);background:0 0;border:none;padding:0;font-weight:500;display:inline-flex}.relaya-root .geo-admin__add-toggle:hover{text-decoration:underline}.relaya-root .geo-admin__add-ban-form{gap:var(--spacing-sm);padding:var(--spacing-sm);background:var(--relaya-color-surface);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);margin-top:var(--spacing-xs);flex-direction:column;display:flex}.relaya-root .export-admin-page{padding:var(--spacing-sm) 0}.relaya-root .export-admin-page__notice{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);margin:0 0 var(--spacing-md)}.relaya-root .export-admin-page__unavailable{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-muted);background:color-mix(in srgb, var(--relaya-color-warning) 10%, transparent);border-left:3px solid var(--relaya-color-warning);padding:var(--spacing-sm) var(--spacing-md);border-radius:var(--relaya-radius-sm);margin:0}.relaya-root .export-admin-page__error{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-danger);background:color-mix(in srgb, var(--relaya-color-danger) 8%, transparent);border-radius:var(--relaya-radius-sm);padding:var(--spacing-xs) var(--spacing-sm);margin-bottom:var(--spacing-md)}.relaya-root .export-admin-page__form{gap:var(--spacing-md);flex-direction:column;display:flex}.relaya-root .export-admin-page__date-row{gap:var(--spacing-md);flex-wrap:wrap;display:flex}.relaya-root .export-admin-page__exclude-row{gap:var(--spacing-xs);flex-direction:column;display:flex}.relaya-root .export-admin-page__label{align-items:center;gap:var(--spacing-sm);font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);font-weight:500;display:flex}.relaya-root .export-admin-page__date-input{padding:var(--spacing-xs) var(--spacing-sm);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);background:var(--relaya-color-surface);color:var(--relaya-color-text);font-size:var(--relaya-font-size-sm)}.relaya-root .export-admin-page__date-input:focus{border-color:var(--relaya-color-accent);outline:none}.relaya-root .export-admin-page__field-error{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-danger);margin:0}.relaya-root .export-admin-page__btn{align-self:stretch}.relaya-root .export-admin-page__hint{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-muted);margin:0}.relaya-root .moderator-admin-page{flex-direction:column;gap:0;display:flex}.relaya-root .moderator-admin-page__topbar{padding:var(--spacing-sm) var(--spacing-md);border-bottom:1px solid var(--relaya-color-border);margin-bottom:var(--spacing-sm)}.relaya-root .moderator-admin-page__title-row{align-items:baseline;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.relaya-root .moderator-admin-page__title{color:var(--relaya-color-text);margin:0;font-size:16px;font-weight:600}.relaya-root .moderator-admin-page__section{padding:var(--spacing-sm) var(--spacing-md)}.relaya-root .moderator-admin-page__section+.moderator-admin-page__section{margin-top:var(--spacing-xs)}.relaya-root .moderator-admin-page__section-title{color:var(--relaya-color-text-muted);text-transform:uppercase;letter-spacing:.07em;margin:0 0 var(--spacing-xs) 0;font-size:11px;font-weight:600}.relaya-root .moderator-admin-page__divider{border:none;border-top:1px solid var(--relaya-color-border);margin:0 0 var(--spacing-sm) 0}.relaya-root .moderator-admin-page__filter{box-sizing:border-box;width:100%;padding:5px var(--spacing-sm);color:var(--relaya-color-text);background:var(--relaya-color-bg);border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-sm);margin-bottom:var(--spacing-sm);outline:none;font-size:11px;transition:border-color .15s;display:block}.relaya-root .moderator-admin-page__filter::placeholder{color:var(--relaya-color-text-faint)}.relaya-root .moderator-admin-page__filter:focus{border-color:var(--relaya-color-accent)}.relaya-root .moderator-admin-page__list{border:1px solid var(--relaya-color-border);border-radius:var(--relaya-radius-md);margin:0;padding:0;list-style:none;overflow:hidden}.relaya-root .moderator-admin-page__item{justify-content:space-between;align-items:center;gap:var(--spacing-sm);padding:2px var(--spacing-sm);background:var(--relaya-color-surface);border-bottom:1px solid var(--relaya-color-border);transition:background .1s;display:flex}.relaya-root .moderator-admin-page__item:last-child{border-bottom:none}.relaya-root .moderator-admin-page__item:hover{background:color-mix(in srgb, var(--relaya-color-accent) 4%, var(--relaya-color-surface))}.relaya-root .moderator-admin-page__member-label{color:var(--relaya-color-text);text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:11px;font-weight:500;overflow:hidden}.relaya-root .moderator-admin-page__list-hint{color:var(--relaya-color-text-muted);margin:0 0 var(--spacing-xs) 0;font-size:10px}.relaya-root .moderator-admin-page__item .btn{flex-shrink:0;min-height:22px;padding:2px 8px;font-size:11px}.relaya-root .moderator-admin-page__demote-link{color:var(--relaya-color-text-muted);cursor:pointer;background:0 0;border:none;flex-shrink:0;padding:0;font-size:11px;font-weight:500;text-decoration:none}.relaya-root .moderator-admin-page__demote-link:hover:not(:disabled){color:var(--relaya-color-danger);text-decoration:underline}.relaya-root .moderator-admin-page__demote-link:disabled{opacity:.4;cursor:default}.relaya-root .moderator-admin-page__promote-link{color:var(--relaya-color-accent);cursor:pointer;background:0 0;border:none;flex-shrink:0;padding:0;font-size:11px;font-weight:500;text-decoration:none}.relaya-root .moderator-admin-page__promote-link:hover:not(:disabled){text-decoration:underline}.relaya-root .moderator-admin-page__promote-link:disabled{opacity:.4;cursor:default}.relaya-root .message-item__edit-form{background:var(--relaya-color-surface-2);border-radius:8px;flex-direction:column;gap:8px;padding:8px;display:flex}.relaya-root .message-item__edit-textarea{border:1px solid var(--relaya-color-border);background:var(--relaya-color-surface);width:100%;min-height:60px;color:var(--relaya-color-text);resize:vertical;border-radius:4px;padding:8px;font-family:inherit;font-size:14px;line-height:1.4}.relaya-root .message-item__edit-textarea:focus{outline:2px solid var(--relaya-color-accent);outline-offset:1px}.relaya-root .message-item__edit-error{color:var(--relaya-color-error,#e74c3c);padding:4px 0;font-size:12px}.relaya-root .message-item__edit-actions{justify-content:flex-end;gap:8px;display:flex}.relaya-root .message-item__edit-actions .btn{min-width:60px}.relaya-root .message-input-container{flex-direction:column;display:flex}.relaya-root .reply-preview{padding:var(--spacing-sm) var(--spacing-md);background:var(--relaya-color-surface-2,#f5f5f5);border-top:1px solid var(--relaya-color-border);justify-content:space-between;align-items:center;gap:var(--spacing-sm);display:flex}.relaya-root .reply-preview__content{align-items:center;gap:var(--spacing-sm);flex:1;min-width:0;display:flex}.relaya-root .reply-preview__line{background:var(--relaya-color-accent,#3b82f6);border-radius:2px;flex-shrink:0;width:3px;height:36px}.relaya-root .reply-preview__text{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.relaya-root .reply-preview__author{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text);font-weight:600}.relaya-root .reply-preview__excerpt{font-size:var(--relaya-font-size-sm);color:var(--relaya-color-text-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.relaya-root .reply-preview__cancel{padding:var(--spacing-xs);cursor:pointer;color:var(--relaya-color-text-secondary,#6b7280);border-radius:var(--relaya-radius-sm);background:0 0;border:none;flex-shrink:0;font-size:18px;line-height:1;transition:background .15s}.relaya-root .reply-preview__cancel:hover{color:var(--relaya-color-text);background:#0000000d}.relaya-root .message-reply-bubble{align-items:stretch;gap:var(--spacing-sm);margin-bottom:var(--spacing-sm);background:var(--reply-bubble-bg,#0000000f);border-radius:var(--relaya-radius-sm);border-left:3px solid var(--relaya-color-accent,#3b82f6);padding:6px 8px;display:flex}.relaya-root .message-reply-bubble__text{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.relaya-root .message-reply-bubble__author{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-accent,#3b82f6);text-overflow:ellipsis;white-space:nowrap;font-weight:600;overflow:hidden}.relaya-root .message-reply-bubble__excerpt{font-size:var(--relaya-font-size-xs);color:var(--relaya-color-text-secondary,#6b7280);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}@media (prefers-color-scheme:dark){.relaya-root .message-reply-bubble{--reply-bubble-bg:#ffffff14}}.relaya-root .message-item--own .message-reply-bubble{--reply-bubble-bg:#fff3;border-left-color:#ffffffb3}.relaya-root .message-item--own .message-reply-bubble__author{color:#fff}.relaya-root .message-item--own .message-reply-bubble__excerpt{color:#ffffffbf}.relaya-root .mute-toggle{cursor:pointer;color:#fff;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;min-width:24px;min-height:24px;margin-left:auto;margin-right:-10px;padding:4px 6px;transition:opacity .2s;display:flex}.relaya-root .mute-toggle:hover{opacity:.8}.relaya-root .mute-toggle:focus{outline:2px solid var(--primary-color,#007bff);outline-offset:2px;border-radius:4px}.relaya-root .mute-toggle:focus:not(:focus-visible){outline:none}.relaya-root .mute-toggle:active{opacity:.6}.relaya-root .mute-toggle__icon{width:18px;height:18px;display:block}.relaya-root .sr-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (width>=768px){.relaya-root .user-list{display:flex}.relaya-root .pane-divider{display:block}}@media (width<=479px){.relaya-root .chat-header__signout{display:none}.relaya-root .chat-name-btn{max-width:80px}}@media (width<=599px){.relaya-root .message-item{max-width:95%}.relaya-root .chat-header{padding:0 var(--spacing-sm);gap:var(--spacing-xs)}.relaya-root .message-list,.relaya-root .message-input-bar{padding:var(--spacing-sm) var(--spacing-md)}.relaya-root .send-btn,.relaya-root .sticker-btn{width:44px;height:44px}.relaya-root .sticker-picker{width:min(96vw,560px);bottom:calc(var(--input-height) + var(--spacing-sm));max-height:62vh}.relaya-root .sticker-suggestions{left:var(--spacing-md);right:var(--spacing-md);bottom:calc(100% + 6px)}.relaya-root .sticker-picker__grid{grid-template-columns:repeat(auto-fill,minmax(96px,1fr))}.relaya-root .btn--icon{min-width:40px;min-height:40px}.relaya-root .message-item__kebab-btn{display:inline-flex}.relaya-root .sticker-admin-page{padding:var(--spacing-md)}.relaya-root .sticker-admin-page__topbar,.relaya-root .admin-settings__section{flex-direction:column;align-items:stretch}.relaya-root .sticker-admin-page__header-actions{width:100%}.relaya-root .sticker-admin-page__header-actions .btn{flex:1}.relaya-root .auth-modal{padding:0}.relaya-root .auth-modal__content{width:100%;max-width:none;height:100%;padding:var(--spacing-xl) var(--spacing-lg);border-radius:0;justify-content:center}.relaya-root .auth-modal__buttons{flex-direction:column-reverse}.relaya-root .auth-modal__buttons .btn{width:100%}}.relaya-root *,.relaya-root :before,.relaya-root :after{box-sizing:border-box;margin:0;padding:0}.relaya-root *{font-family:var(--sp-ui-font);-webkit-font-smoothing:antialiased}.relaya-root button{cursor:pointer;font-family:inherit;font-size:inherit;background:0 0;border:none}.relaya-root input,.relaya-root textarea{font-family:inherit;font-size:inherit}`,i=`relaya-default-styles`;function a(){if(typeof document>`u`||document.getElementById(i))return;let e=document.createElement(`style`);e.id=i,e.textContent=r,document.head.appendChild(e)}function o(){typeof document>`u`||document.getElementById(i)?.remove()}function s(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,9)}`}function c(e,t=1e3,n=3e4){let r=t*2**e;return Math.min(r,n)}function l(e,t){return t?e.filter(e=>e.clientId!==t):e}function u(e,t){return e.map(e=>e.clientId===t?{...e,status:`failed`}:e)}function d(e){let t=new Set;return e.filter(e=>t.has(e.id)?!1:(t.add(e.id),!0))}var f=new Set([`.gif`,`.png`,`.jpg`,`.jpeg`,`.webp`]),p={pathPrefixes:[`/files/stations/`],hosts:[`tenor.com`,`media.tenor.com`,`giphy.com`,`media.giphy.com`,`i.giphy.com`,`editablegifs.com`,`imgur.com`,`i.imgur.com`]},m=/(https?:\/\/[^\s]+|\/files\/stations\/[^\s]+)/gi,h=/:([a-z0-9_-]{1,64}):/gi;function g(e){return e.trim().toLowerCase()}function _(e){return e.reduce((e,t)=>(t.shortcode&&(e[g(t.shortcode)]=t.url),e),{})}function v(e,t){let n=_(t);return e.replace(h,(e,t)=>n[g(t)]??e)}function y(e){let t=e.toLowerCase();for(let e of f)if(t.endsWith(e))return!0;return!1}function b(e){let t=e.toLowerCase();return p.hosts.some(e=>t===e||t.endsWith(`.${e}`))}function x(e){let t=e.match(/[\],.!?:;]+$/);if(!t)return{core:e,trailing:``};let n=t[0];return{core:e.slice(0,-n.length),trailing:n}}function S(e,t){if(!t)return;let n=e[e.length-1];if(n&&!n.isImage){n.text+=t;return}e.push({text:t,isImage:!1})}function C(e){try{if(e.startsWith(`/`))return p.pathPrefixes.some(t=>e.startsWith(t))&&y(e.split(`?`)[0]??e);let t=new URL(e);if(t.protocol!==`http:`&&t.protocol!==`https:`)return!1;let n=t.pathname,r=p.pathPrefixes.some(e=>n.startsWith(e)),i=b(t.hostname);return!r&&!i?!1:y(n)}catch{return!1}}function w(e){let t=[],n=0;for(let r of e.matchAll(m)){let i=r[0],a=r.index??0,o=a+i.length;a>n&&S(t,e.slice(n,a));let{core:s,trailing:c}=x(i);C(s)?(t.push({text:s,isImage:!0,url:s}),S(t,c)):S(t,i),n=o}return n<e.length&&S(t,e.slice(n)),t}function T(e){let t=w(e);return t.filter(e=>e.isImage).length===1?t.every(e=>e.isImage||e.text.trim()===``):!1}var E=class{buildWsUrl;onMessage;onStatusChange;ws=null;status=`disconnected`;reconnectAttempt=0;reconnectTimer=null;closed=!1;backoffBaseMs;backoffMaxMs;onAuthRevoked;constructor(e,t,n,r={}){this.buildWsUrl=e,this.onMessage=t,this.onStatusChange=n,this.backoffBaseMs=r.backoffBaseMs??1e3,this.backoffMaxMs=r.backoffMaxMs??3e4,this.onAuthRevoked=r.onAuthRevoked}getStatus(){return this.status}connect(){this.closed||(this.setStatus(`connecting`),this.openSocket())}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}close(){this.closed=!0,this.clearReconnectTimer(),this.ws&&=(this.ws.onclose=null,this.ws.close(),null),this.setStatus(`disconnected`)}openSocket(){if(this.closed)return;let e=this.buildWsUrl(),t=new WebSocket(e);this.ws=t,t.onopen=()=>{if(this.closed){t.close();return}this.reconnectAttempt=0,this.setStatus(`connected`)},t.onmessage=e=>{let t;try{t=JSON.parse(e.data)}catch{return}if(t.type===`ping`){this.send({type:`pong`});return}if(t.type===`force_logout`){this.handleAuthRevoked();return}this.onMessage(t)},t.onclose=e=>{if(!this.closed){if(e.code===4001){this.handleAuthRevoked();return}this.scheduleReconnect()}},t.onerror=()=>{}}scheduleReconnect(){if(this.closed)return;this.setStatus(`reconnecting`);let e=c(this.reconnectAttempt,this.backoffBaseMs,this.backoffMaxMs);this.reconnectAttempt++,this.reconnectTimer=setTimeout(()=>{this.closed||this.openSocket()},e)}clearReconnectTimer(){this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null)}setStatus(e){this.status!==e&&(this.status=e,this.onStatusChange(e))}handleAuthRevoked(){this.closed=!0,this.clearReconnectTimer(),this.ws&&=(this.ws.onclose=null,this.ws.close(),null),this.setStatus(`disconnected`),this.onAuthRevoked?.()}};function D(e,t,n){return r=>{switch(r.type){case`auth:success`:e.userDirectory.current.clear(),e.avatarHistory.current.clear(),r.users.forEach(t=>{e.userDirectory.current.set(t.id,{id:t.id,displayName:t.displayName,avatarUrl:t.avatarUrl}),t.avatarUrl!==null&&e.avatarHistory.current.set(t.id,[{url:t.avatarUrl,changedAt:new Date(0)}])}),e.newestMessageIdRef.current?console.log(`[auth:success] reconnect — skipping full reload (catch-up already in flight)`):(console.log(`[auth:success] fresh connect — loading initial messages`),t(e=>({...e,loadingInitial:!0})),n());break;case`message:broadcast`:{let{message:n,clientId:i}=r;t(t=>{let r=d([...t.messages,n]),a=r.length>150?r.slice(r.length-150):r,o=l(t.optimistic,i);return e.newestMessageIdRef.current=n.id,a.length>0&&(e.oldestMessageIdRef.current=a[0].id),{...t,messages:a,optimistic:o}});break}case`message:deleted`:{let{messageId:e}=r;t(t=>({...t,messages:t.messages.map(t=>t.id===e?{...t,is_deleted:!0,content:null}:t)}));break}case`message:edited`:{let{message:e}=r;t(t=>({...t,messages:t.messages.map(t=>t.id===e.id?e:t)}));break}case`mention:notification`:{let{mentionedBy:t,excerpt:n}=r;e.mentionSoundPlayRef.current&&e.mentionSoundPlayRef.current(),console.log(`[Mention] @${t.displayName}: ${n}`);break}case`channel:notification`:{let{mentionedBy:t,excerpt:n}=r;e.channelSoundPlayRef.current&&e.channelSoundPlayRef.current(),console.log(`[Channel] @channel by ${t.displayName}: ${n}`);break}case`presence:update`:r.users.forEach(t=>{e.userDirectory.current.set(t.id,{id:t.id,displayName:t.displayName,avatarUrl:t.avatarUrl})}),t(e=>({...e,users:r.users.map(e=>({id:e.id,displayName:e.displayName,avatarUrl:e.avatarUrl})),userCount:r.userCount,totalCount:r.totalCount}));break;case`user:update`:{let{userId:n,updates:i,timestamp:a}=r,o=e.userDirectory.current.get(n);if(e.userDirectory.current.set(n,{id:n,displayName:i.displayName??o?.displayName??`Unknown User`,avatarUrl:i.avatarUrl===void 0?o?.avatarUrl??null:i.avatarUrl}),i.avatarUrl!==void 0){let t=e.avatarHistory.current.get(n)||[];t.push({url:i.avatarUrl,changedAt:new Date(a)});let r=t.length>20?t.slice(t.length-20):t;e.avatarHistory.current.set(n,r)}t(e=>({...e,users:e.users.map(e=>e.id===n?{...e,...i}:e)}));break}case`error`:t(e=>{let t=e.optimistic.filter(e=>e.status===`sending`);return t.length===1?{...e,optimistic:u(e.optimistic,t[0].clientId),error:r.message}:{...e,error:r.message}});break;case`stickers:updated`:e.onStickersUpdatedRef.current?.();break;default:break}}}var O=(0,t.createContext)(void 0);function k({children:e}){let[r,i]=(0,t.useState)(!1);return(0,n.jsx)(O.Provider,{value:{isMuted:r,setIsMuted:i},children:e})}function A(){let e=(0,t.useContext)(O);if(!e)throw Error(`useNotificationMute must be used within NotificationMuteProvider`);return e}function j(t,n,r){if(!t)return e.v(n,r);let i=new URL(t,window.location.href),a=i.protocol===`https:`?`wss:`:`ws:`,o=r?`token=${encodeURIComponent(r)}&`:``;return`${a}//${i.host}/ws?${o}station=${encodeURIComponent(n)}`}var M=50;function N(n,r,i){let[a,o]=(0,t.useState)({messages:[],optimistic:[],users:[],userCount:0,totalCount:0,connectionStatus:`disconnected`,loadingInitial:!1,loadingOlder:!1,hasOlderMessages:!1,retentionCutoff:null,error:null}),c=(0,t.useRef)(null),l=(0,t.useRef)(void 0),u=(0,t.useRef)(void 0),f=(0,t.useRef)(new Map),p=(0,t.useRef)(new Map),m=(0,t.useRef)(new Map),h=(0,t.useRef)(new e.x(``,r)).current,g=(0,t.useRef)(null),_=(0,t.useRef)(null),v=(0,t.useRef)(null),y=(0,t.useRef)(null),b=(0,t.useRef)(void 0),{isMuted:x}=A(),S=(0,t.useRef)(x),C=n.stationSlug,w=n.user?.id??``,T=(0,t.useCallback)((e,t)=>{let n=(m.current.get(e)||[]).filter(e=>e.changedAt<=t).pop();return n?n.url:p.current.get(e)?.avatarUrl??null},[]),O=(0,t.useCallback)(async(e={})=>{if(C)try{let t=await h.getMessages(C,{after:e.after,limit:M}),n=t.messages??[];console.log(`[loadMessages] ${e.after?`catch-up (after=`+e.after.slice(0,8)+`…)`:`initial`} → ${n.length} messages, oldest=${n[0]?.id?.slice(0,8)??`none`}… newest=${n[n.length-1]?.id?.slice(0,8)??`none`}…, hasMore=${t.hasMore}`),o(r=>{let i;return i=e.after?d([...r.messages,...n]):n,n.length>0&&(u.current=i[i.length-1].id,e.after||(l.current=i[0].id)),{...r,messages:i,hasOlderMessages:t.hasMore??!1,loadingInitial:!1,...e.after?{}:{retentionCutoff:t.retentionCutoff??null}}})}catch(e){console.error(`[loadMessages] fetch failed:`,e),o(e=>({...e,loadingInitial:!1}))}},[h,C]),k=(0,t.useCallback)(D({userDirectory:p,avatarHistory:m,newestMessageIdRef:u,oldestMessageIdRef:l,mentionSoundPlayRef:v,channelSoundPlayRef:y,onStickersUpdatedRef:b},o,O),[O]),N=(0,t.useCallback)(e=>{o(t=>({...t,connectionStatus:e})),e===`connected`&&u.current&&O({after:u.current})},[O]);(0,t.useEffect)(()=>{g.current=k,_.current=N,S.current=x,b.current=i?.onStickersUpdated}),(0,t.useEffect)(()=>{if(!C||n.status===`loading`)return;let e=()=>{let e=new E(()=>{let e=n.status===`authenticated`?r()??void 0:void 0;return j(i?.wsBaseUrl,C,e)},e=>g.current?.(e),e=>_.current?.(e),{onAuthRevoked:i?.onForcedLogout});return c.current=e,e.connect(),e};e();let t=()=>{document.hidden?(c.current?.close(),c.current=null):e()};return document.addEventListener(`visibilitychange`,t),()=>{document.removeEventListener(`visibilitychange`,t),c.current?.close(),c.current=null}},[C,n.status,r,i?.wsBaseUrl]);let P=(0,t.useCallback)(async()=>{if(!(!C||!l.current||a.loadingOlder)){o(e=>({...e,loadingOlder:!0}));try{let e=await h.getMessages(C,{before:l.current,limit:M}),t=e.messages??[];o(n=>{let r=d([...t,...n.messages]);return t.length>0&&(l.current=t[0].id),{...n,messages:r,hasOlderMessages:e.hasMore??!1,loadingOlder:!1}})}catch{o(e=>({...e,loadingOlder:!1}))}}},[h,C,a.loadingOlder]),F=(0,t.useCallback)((e,t)=>{if(!c.current||!n.user)return;let r=s(),i={clientId:r,content:e.trim(),authorId:w,authorDisplayName:n.user.displayName,authorAvatarUrl:n.user.avatarUrl,createdAt:new Date,status:`sending`};o(e=>({...e,optimistic:[...e.optimistic,i]})),f.current.set(r,e.trim()),c.current.send({type:`message:send`,content:e.trim(),clientId:r,replyToMessageId:t?.messageId,replyAuthorName:t?.authorName,replyExcerpt:t?.excerpt})},[n.user,w]),ee=(0,t.useCallback)(e=>{if(!c.current||!n.user)return;let t=f.current.get(e);t&&(o(t=>({...t,optimistic:t.optimistic.filter(t=>t.clientId!==e)})),f.current.delete(e),F(t))},[n.user,F]),I=(0,t.useCallback)(async e=>{C&&(await h.deleteMessage(C,e),o(t=>({...t,messages:t.messages.map(t=>t.id===e?{...t,is_deleted:!0,content:null}:t)})))},[h,C]),L=(0,t.useCallback)(async(e,t)=>{C&&await h.createBan(C,e,t)},[h,C]),R=(0,t.useCallback)(async(e,t,n)=>{C&&await h.createReport(C,e,t,n)},[h,C]),z=(0,t.useCallback)(async(e,t)=>{if(C)try{let n=await h.editMessage(C,e,t);o(t=>({...t,messages:t.messages.map(t=>t.id===e?{...t,...n}:t)}))}catch(e){throw o(e=>({...e,error:`Failed to edit message`})),e}},[h,C]),B=(0,t.useCallback)(e=>{v.current=e},[]),V=(0,t.useCallback)(e=>{y.current=e},[]),H=(0,t.useCallback)(e=>p.current.get(e),[]);return{...a,sendMessage:F,loadOlderMessages:P,editMessage:z,deleteMessage:I,banUser:L,reportMessage:R,retryFailed:ee,registerMentionSound:B,registerChannelSound:V,getUserInfo:H,getAvatarForMessage:T}}function P(e,t){if(t<=0||t>e.length)return null;let n=t-1;for(;n>=0&&/[a-zA-Z0-9_-]/.test(e[n]??``);)--n;if(e[n]!==`@`)return null;let r=n>0?e[n-1]:``;return r&&!/\s/.test(r)?null:{query:e.slice(n+1,t).toLowerCase(),start:n,end:t}}function F(e,t,n,r=8){let i=t.trim().toLowerCase();return e.filter(e=>e.id!==n).filter(e=>!i||e.displayName.toLowerCase().startsWith(i)||e.displayName.toLowerCase().includes(i)).sort((e,t)=>i&&!e.displayName.toLowerCase().startsWith(i)-+!t.displayName.toLowerCase().startsWith(i)||e.displayName.localeCompare(t.displayName)).slice(0,r)}function ee(e,t,n,r){if(t<=0)return null;let i=e.slice(0,t).match(/(?:^|(?<=\s))@([a-zA-Z0-9_-]+)$/);if(!i)return null;let a=i[1].toLowerCase(),o=t,s=o-i[0].length,c=n.filter(e=>e.id!==r).filter(e=>!e.displayName.includes(` `)).filter(e=>e.displayName.toLowerCase()===a);return c.length===1?{user:c[0],start:s,end:o}:null}function I(e,t,n,r){let i=`@[${r.displayName}|${r.id}] `;return{nextText:`${e.slice(0,t)}${i}${e.slice(n)}`,caretPosition:t+i.length}}function L(e,t){if(t<=0||t>e.length)return null;let n=t-1;for(;n>=0&&/[A-Za-z0-9_-]/.test(e[n]??``);)--n;if(e[n]!==`:`)return null;let r=n>0?e[n-1]:``;if(r&&!/\s/.test(r))return null;let i=e.slice(n+1,t);return/^[A-Za-z0-9_-]*$/.test(i)?{query:i.toLowerCase(),start:n,end:t}:null}function R(e,t,n,r){let i=`:${r}: `;return{nextText:`${e.slice(0,t)}${i}${e.slice(n)}`,caretPosition:t+i.length}}function z(e,t,n=6){let r=t.trim().toLowerCase();return e.filter(e=>!!e.shortcode).filter(e=>!r||e.shortcode.startsWith(r)||e.shortcode.includes(r)).sort((e,t)=>!e.shortcode.startsWith(r)-+!t.shortcode.startsWith(r)||e.order-t.order||e.filename.localeCompare(t.filename)).slice(0,n)}function B({onLogin:e,error:r,stationSlug:i}){let[a,o]=(0,t.useState)(``),[s,c]=(0,t.useState)(!1);async function l(t){if(t.preventDefault(),!(!a.trim()||s)){c(!0);try{await e(a.trim())}catch{}finally{c(!1)}}}let u=i.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `);return(0,n.jsx)(`div`,{className:`login-screen`,children:(0,n.jsxs)(`div`,{className:`login-card`,children:[(0,n.jsx)(`div`,{className:`login-card__logo`,children:(0,n.jsx)(`span`,{style:{fontSize:40},children:`📻`})}),(0,n.jsxs)(`h1`,{className:`login-card__title`,children:[u,` Chat`]}),(0,n.jsx)(`p`,{className:`login-card__subtitle`,children:`Enter your email to receive a magic link and join the chat.`}),(0,n.jsxs)(`form`,{className:`login-card__form`,onSubmit:l,children:[(0,n.jsxs)(`div`,{className:`form-field`,children:[(0,n.jsx)(`label`,{htmlFor:`email`,children:`Email address`}),(0,n.jsx)(`input`,{id:`email`,type:`email`,value:a,onChange:e=>o(e.target.value),placeholder:`you@example.com`,autoComplete:`email`,autoFocus:!0,required:!0,disabled:s})]}),r&&(0,n.jsx)(`div`,{className:`error-message`,children:r}),(0,n.jsx)(`button`,{type:`submit`,className:`btn btn--primary`,disabled:s||!a.trim(),children:s?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`span`,{className:`connection-spinner`}),`Sending…`]}):`Send magic link`})]})]})})}function V({onBack:e}){return(0,n.jsx)(`div`,{className:`magic-link-sent`,children:(0,n.jsxs)(`div`,{className:`magic-link-sent__card`,children:[(0,n.jsx)(`div`,{className:`magic-link-sent__icon`,children:`✉️`}),(0,n.jsx)(`h1`,{className:`magic-link-sent__title`,children:`Check your email`}),(0,n.jsxs)(`p`,{className:`magic-link-sent__body`,children:[`We've sent a magic link to your email address. Click the link to join the chat.`,(0,n.jsx)(`br`,{}),(0,n.jsx)(`br`,{}),`The link expires in 15 minutes and can only be used once.`]}),(0,n.jsx)(`button`,{className:`btn btn--ghost`,onClick:e,style:{width:`100%`},children:`Use a different email`})]})})}var H={color:void 0,size:void 0,className:void 0,style:void 0,attr:void 0},U=t.default.createContext&&t.default.createContext(H),te=[`attr`,`size`,`title`];function W(e,t){if(e==null)return{};var n,r,i=G(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function G(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.indexOf(r)!==-1)continue;n[r]=e[r]}return n}function K(){return K=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},K.apply(null,arguments)}function q(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function J(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?q(Object(n),!0).forEach(function(t){Y(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):q(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function Y(e,t,n){return(t=ne(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ne(e){var t=re(e,`string`);return typeof t==`symbol`?t:t+``}function re(e,t){if(typeof e!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(typeof r!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function X(e){return e&&e.map((e,n)=>t.default.createElement(e.tag,J({key:n},e.attr),X(e.child)))}function Z(e){return n=>t.default.createElement(ie,K({attr:J({},e.attr)},n),X(e.child))}function ie(e){var n=n=>{var{attr:r,size:i,title:a}=e,o=W(e,te),s=i||n.size||`1em`,c;return n.className&&(c=n.className),e.className&&(c=(c?c+` `:``)+e.className),t.default.createElement(`svg`,K({stroke:`currentColor`,fill:`currentColor`,strokeWidth:`0`},n.attr,r,o,{className:c,style:J(J({color:e.color||n.color},n.style),e.style),height:s,width:s,xmlns:`http://www.w3.org/2000/svg`}),a&&t.default.createElement(`title`,null,a),e.children)};return U===void 0?n(H):t.default.createElement(U.Consumer,null,e=>n(e))}function ae(e){return Z({tag:`svg`,attr:{viewBox:`0 0 24 24`,fill:`currentColor`,"aria-hidden":`true`},child:[{tag:`path`,attr:{fillRule:`evenodd`,d:`M5.25 9a6.75 6.75 0 0 1 13.5 0v.75c0 2.123.8 4.057 2.118 5.52a.75.75 0 0 1-.297 1.206c-1.544.57-3.16.99-4.831 1.243a3.75 3.75 0 1 1-7.48 0 24.585 24.585 0 0 1-4.831-1.244.75.75 0 0 1-.298-1.205A8.217 8.217 0 0 0 5.25 9.75V9Zm4.502 8.9a2.25 2.25 0 1 0 4.496 0 25.057 25.057 0 0 1-4.496 0Z`,clipRule:`evenodd`},child:[]}]})(e)}function oe(e){return Z({tag:`svg`,attr:{viewBox:`0 0 24 24`,fill:`currentColor`,"aria-hidden":`true`},child:[{tag:`path`,attr:{d:`M3.53 2.47a.75.75 0 0 0-1.06 1.06l18 18a.75.75 0 1 0 1.06-1.06l-18-18ZM20.57 16.476c-.223.082-.448.161-.674.238L7.319 4.137A6.75 6.75 0 0 1 18.75 9v.75c0 2.123.8 4.057 2.118 5.52a.75.75 0 0 1-.297 1.206Z`},child:[]},{tag:`path`,attr:{fillRule:`evenodd`,d:`M5.25 9c0-.184.007-.366.022-.546l10.384 10.384a3.751 3.751 0 0 1-7.396-1.119 24.585 24.585 0 0 1-4.831-1.244.75.75 0 0 1-.298-1.205A8.217 8.217 0 0 0 5.25 9.75V9Zm4.502 8.9a2.25 2.25 0 1 0 4.496 0 25.057 25.057 0 0 1-4.496 0Z`,clipRule:`evenodd`},child:[]}]})(e)}function se(e){return Z({tag:`svg`,attr:{fill:`none`,viewBox:`0 0 24 24`,strokeWidth:`1.5`,stroke:`currentColor`,"aria-hidden":`true`},child:[{tag:`path`,attr:{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z`},child:[]},{tag:`path`,attr:{strokeLinecap:`round`,strokeLinejoin:`round`,d:`M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z`},child:[]}]})(e)}var ce=[{value:`spam`,label:`Spam`},{value:`harassment`,label:`Harassment or bullying`},{value:`offensive_content`,label:`Offensive or hateful content`},{value:`misinformation`,label:`Misinformation`},{value:`other`,label:`Other`}];function le({messageId:e,authorName:r,onReport:i,onClose:a}){let[o,s]=(0,t.useState)(ce[0].value),[c,l]=(0,t.useState)(``),[u,d]=(0,t.useState)(!1),[f,p]=(0,t.useState)(null),[m,h]=(0,t.useState)(!1);async function g(){d(!0),p(null);try{await i(e,o,c.trim()||void 0),h(!0)}catch(e){p(e?.message??`Failed to submit report.`)}finally{d(!1)}}return(0,n.jsx)(`div`,{className:`modal-overlay`,onClick:e=>e.target===e.currentTarget&&a(),children:(0,n.jsxs)(`div`,{className:`modal`,role:`dialog`,"aria-modal":`true`,"aria-label":`Report message`,children:[(0,n.jsx)(`h2`,{className:`modal__title`,children:`Report message`}),m?(0,n.jsx)(`div`,{className:`modal__body`,children:(0,n.jsx)(`p`,{children:`✅ Your report has been submitted. Our moderators will review it shortly.`})}):(0,n.jsxs)(`div`,{className:`modal__body`,children:[(0,n.jsxs)(`p`,{children:[`Report a message from `,(0,n.jsx)(`strong`,{children:r}),`.`]}),(0,n.jsx)(`label`,{htmlFor:`report-reason`,children:`Reason`}),(0,n.jsx)(`select`,{id:`report-reason`,value:o,onChange:e=>s(e.target.value),disabled:u,children:ce.map(e=>(0,n.jsx)(`option`,{value:e.value,children:e.label},e.value))}),(0,n.jsx)(`label`,{htmlFor:`report-details`,children:`Additional details (optional)`}),(0,n.jsx)(`textarea`,{id:`report-details`,value:c,onChange:e=>l(e.target.value),placeholder:`Describe the issue…`,disabled:u,maxLength:500}),f&&(0,n.jsx)(`p`,{style:{color:`var(--color-danger)`,marginTop:8},children:f})]}),(0,n.jsx)(`div`,{className:`modal__footer`,children:m?(0,n.jsx)(`button`,{className:`btn btn--primary`,onClick:a,children:`Close`}):(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`button`,{className:`btn btn--ghost`,onClick:a,disabled:u,children:`Cancel`}),(0,n.jsx)(`button`,{className:`btn btn--danger`,onClick:g,disabled:u,children:u?`Submitting…`:`Submit report`})]})})]})})}function ue(e){return e.split(` `).map(e=>e[0]).join(``).toUpperCase().slice(0,2)}function Q({displayName:e,avatarUrl:r}){let[i,a]=(0,t.useState)(!1);return(0,n.jsx)(`div`,{className:`message-item__avatar-slot`,"aria-hidden":`true`,children:r&&!i?(0,n.jsx)(`img`,{className:`message-item__avatar message-item__avatar--image`,src:r,alt:``,onError:()=>a(!0),loading:`lazy`}):(0,n.jsx)(`div`,{className:`message-item__avatar`,children:ue(e)})})}function de({position:e,onClose:t,showAvatarOptions:r,hasGalleryImages:i,onSelectGravatarPhoto:a,onUseDefaultGravatar:o,onUseInitials:s,showReply:c,showEdit:l,showDelete:u,showReport:d,showBan:f,onReply:p,onEdit:m,onDelete:h,onReport:g,onBan:_}){let v=C(),y=window.innerWidth,b=window.innerHeight,x=e.x+220>y?e.x-220:e.x,S=e.y+v>b?e.y-v:e.y;function C(){let e=0;r&&(e+=3),c&&e++,l&&e++,u&&e++,d&&e++,f&&e++;let t=e*40,n=r&&(c||l||u||d||f)?1:0,i=c&&(d||f||u)?1:0;return t+n+i+4}let w=({onClick:e,children:r,icon:i,danger:a=!1})=>(0,n.jsxs)(`button`,{onClick:()=>{e(),t()},style:{display:`flex`,alignItems:`center`,gap:`8px`,width:`100%`,padding:`10px 12px`,textAlign:`left`,background:`none`,border:`none`,color:a?`var(--relaya-color-danger, #e74c3c)`:`var(--relaya-color-text)`,fontSize:`var(--relaya-font-size-sm)`,cursor:`pointer`,fontFamily:`inherit`},onMouseEnter:e=>{e.currentTarget.style.background=`var(--relaya-color-surface-2)`},onMouseLeave:e=>{e.currentTarget.style.background=`none`},children:[(0,n.jsx)(`span`,{children:i}),(0,n.jsx)(`span`,{children:r})]});return r||c||l||u||d||f?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`div`,{onClick:t,style:{position:`fixed`,top:0,left:0,right:0,bottom:0,zIndex:999}}),(0,n.jsxs)(`div`,{style:{position:`fixed`,top:S,left:x,zIndex:1e3,minWidth:`220px`,background:`var(--relaya-color-surface)`,border:`1px solid var(--relaya-color-border)`,borderRadius:`var(--relaya-radius-md)`,boxShadow:`0 4px 16px var(--relaya-color-shadow)`,overflow:`hidden`},children:[r&&(0,n.jsxs)(n.Fragment,{children:[a&&(0,n.jsx)(w,{onClick:a,icon:`🌐`,children:`Select gravatar image...`}),o&&(0,n.jsx)(w,{onClick:o,icon:`🌐`,children:`Use default Gravatar`}),s&&(0,n.jsx)(w,{onClick:s,icon:`⭕`,children:`Use initials (no avatar)`})]}),r&&(c||l||u||d||f)&&(0,n.jsx)(`div`,{style:{height:`1px`,background:`var(--relaya-color-border)`,margin:`4px 0`}}),c&&p&&(0,n.jsx)(w,{onClick:p,icon:`↩️`,children:`Reply`}),c&&(d||f||u)&&(0,n.jsx)(`div`,{style:{height:`1px`,background:`var(--relaya-color-border)`,margin:`4px 0`}}),l&&m&&(0,n.jsx)(w,{onClick:m,icon:`✏️`,children:`Edit message`}),d&&g&&(0,n.jsx)(w,{onClick:g,icon:`🚩`,children:`Report`}),f&&_&&(0,n.jsx)(w,{onClick:_,icon:`🔨`,children:`Ban user`}),u&&h&&(0,n.jsx)(w,{onClick:h,icon:`🗑`,danger:!0,children:`Delete`})]})]}):null}var fe=[{id:`identicon`,label:`Identicon`,icon:`🔷`},{id:`monsterid`,label:`Monster`,icon:`👾`},{id:`retro`,label:`Retro`,icon:`🎮`},{id:`wavatar`,label:`Wavatar`,icon:`🌊`},{id:`robohash`,label:`Robohash`,icon:`🤖`},{id:`mp`,label:`Mystery Person`,icon:`👤`}];function pe({stationSlug:e,getToken:r,onClose:i,onSelect:a,currentAvatarUrl:o}){let[s,c]=(0,t.useState)([]),[l,u]=(0,t.useState)(!0),[d,f]=(0,t.useState)(null),[p,m]=(0,t.useState)(o),[h,g]=(0,t.useState)(!1);(0,t.useEffect)(()=>{(async()=>{try{let t=r(),n={};t&&(n.Authorization=`Bearer ${t}`);let i=await fetch(`/api/chat/${e}/me/gravatar/gallery`,{headers:n});if(!i.ok)throw Error(`Failed to fetch gallery`);c((await i.json()).gallery||[])}catch(e){console.error(`Error fetching Gravatar gallery:`,e),f(`Failed to load Gravatar gallery`),c([])}finally{u(!1)}})()},[e,r]);let _=async()=>{if(p){g(!0);try{await a(p,`gravatar`),i()}catch{f(`Failed to update avatar`),g(!1)}}},v=e=>{m(e)},y=e=>{m(`https://www.gravatar.com/avatar/HASH?d=${e}&s=96`)};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`div`,{onClick:i,style:{position:`fixed`,top:0,left:0,right:0,bottom:0,background:`rgba(0, 0, 0, 0.5)`,zIndex:1e3,display:`flex`,alignItems:`center`,justifyContent:`center`}}),(0,n.jsxs)(`div`,{onClick:e=>e.stopPropagation(),style:{position:`fixed`,top:`50%`,left:`50%`,transform:`translate(-50%, -50%)`,zIndex:1001,width:`90%`,maxWidth:`600px`,maxHeight:`80vh`,background:`var(--relaya-color-input-bg)`,border:`1px solid var(--relaya-color-border)`,borderRadius:`var(--relaya-radius-lg)`,boxShadow:`0 8px 32px rgba(0, 0, 0, 0.2)`,display:`flex`,flexDirection:`column`,overflow:`hidden`},children:[(0,n.jsxs)(`div`,{style:{padding:`16px 20px`,borderBottom:`1px solid var(--relaya-color-border)`,display:`flex`,alignItems:`center`,justifyContent:`space-between`},children:[(0,n.jsx)(`h3`,{style:{margin:0,fontSize:`var(--relaya-font-size-lg)`,fontWeight:600},children:`Select Gravatar Image`}),(0,n.jsx)(`button`,{onClick:i,style:{background:`none`,border:`none`,fontSize:`20px`,cursor:`pointer`,color:`var(--relaya-color-text-muted)`,padding:`4px 8px`,lineHeight:1},children:`×`})]}),(0,n.jsxs)(`div`,{style:{padding:`20px`,overflowY:`auto`,flex:1},children:[l&&(0,n.jsx)(`div`,{children:`Loading...`}),d&&(0,n.jsx)(`div`,{style:{color:`var(--relaya-color-danger)`,marginBottom:`16px`},children:d}),!l&&(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(`div`,{style:{marginBottom:`24px`},children:[(0,n.jsx)(`h4`,{style:{fontSize:`var(--relaya-font-size-sm)`,fontWeight:600,marginBottom:`12px`,color:`var(--relaya-color-text-muted)`},children:`Your Uploaded Images (from gravatar.com)`}),s.length>0?(0,n.jsx)(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fill, minmax(80px, 1fr))`,gap:`12px`},children:s.map((e,t)=>(0,n.jsxs)(`div`,{onClick:()=>v(e.url),style:{cursor:`pointer`,border:p===e.url?`2px solid var(--relaya-color-accent)`:`2px solid transparent`,borderRadius:`var(--relaya-radius-sm)`,padding:`4px`},children:[(0,n.jsx)(`img`,{src:e.url,alt:e.alt||`Gallery image`,style:{width:`100%`,height:`auto`,borderRadius:`var(--relaya-radius-sm)`,display:`block`}}),e.alt&&(0,n.jsx)(`div`,{style:{fontSize:`10px`,color:`var(--relaya-color-text-muted)`,marginTop:`4px`,textAlign:`center`},children:e.alt})]},t))}):(0,n.jsxs)(`div`,{style:{fontSize:`var(--relaya-font-size-sm)`,color:`var(--relaya-color-text-muted)`,padding:`12px 0`},children:[`Upload some images to your Gravatar `,(0,n.jsx)(`strong`,{children:(0,n.jsx)(`em`,{children:`photos`})}),` section to show them here`]})]}),(0,n.jsxs)(`div`,{children:[(0,n.jsx)(`h4`,{style:{fontSize:`var(--relaya-font-size-sm)`,fontWeight:600,marginBottom:`12px`,color:`var(--relaya-color-text-muted)`},children:s.length>0?`Generated Alternatives`:`Gravatar Generated Styles`}),(0,n.jsx)(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fill, minmax(80px, 1fr))`,gap:`12px`},children:fe.map(e=>(0,n.jsxs)(`div`,{onClick:()=>y(e.id),style:{cursor:`pointer`,border:`2px solid transparent`,borderRadius:`var(--relaya-radius-sm)`,padding:`8px`,textAlign:`center`},children:[(0,n.jsx)(`div`,{style:{fontSize:`32px`,marginBottom:`4px`},children:e.icon}),(0,n.jsx)(`div`,{style:{fontSize:`11px`,color:`var(--relaya-color-text-muted)`},children:e.label})]},e.id))})]})]})]}),(0,n.jsxs)(`div`,{style:{padding:`12px 20px`,borderTop:`1px solid var(--relaya-color-border)`,display:`flex`,gap:`8px`,justifyContent:`flex-end`},children:[(0,n.jsx)(`button`,{onClick:i,disabled:h,style:{padding:`8px 16px`,borderRadius:`var(--relaya-radius-sm)`,border:`1px solid var(--relaya-color-border)`,background:`var(--relaya-color-input-bg)`,color:`var(--relaya-color-text)`,cursor:`pointer`,fontSize:`var(--relaya-font-size-sm)`},children:`Cancel`}),(0,n.jsx)(`button`,{onClick:_,disabled:!p||h,style:{padding:`8px 16px`,borderRadius:`var(--relaya-radius-sm)`,border:`none`,background:p&&!h?`var(--relaya-color-accent)`:`var(--relaya-color-surface-2)`,color:p&&!h?`#ffffff`:`var(--relaya-color-text-muted)`,cursor:p&&!h?`pointer`:`not-allowed`,fontSize:`var(--relaya-font-size-sm)`},children:h?`Saving...`:`Select Image`})]})]})]})}function me(e){let t=typeof e==`string`?new Date(e):e,n=new Date,r=t.getFullYear()===n.getFullYear()&&t.getMonth()===n.getMonth()&&t.getDate()===n.getDate(),i=t.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`});return r?i:`${t.toLocaleDateString([],{month:`short`,day:`numeric`})}, ${i}`}function he(e){return(typeof e==`string`?new Date(e):e)>new Date(Date.now()-900*1e3)}function ge(e){return T(e)?w(e).find(e=>e.isImage&&e.url)?.url??null:null}function _e(e){let t=e.split(`/`).pop()??`image`,n=t.split(`?`)[0]??t;return decodeURIComponent(n).replace(/\.[^.]+$/,``).replace(/[-_]+/g,` `)||`Sticker image`}function ve({url:e,bare:r=!1,title:i}){let[a,o]=(0,t.useState)(!1),[s,c]=(0,t.useState)(!1);return(0,n.jsxs)(`span`,{className:[`chat-image`,r?`chat-image--bare`:`chat-image--inline`].join(` `),title:i,children:[!a&&!s&&(0,n.jsxs)(`span`,{className:`chat-image__loading`,"aria-label":`Loading image`,children:[(0,n.jsx)(`span`,{}),(0,n.jsx)(`span`,{}),(0,n.jsx)(`span`,{})]}),s?(0,n.jsx)(`span`,{className:`chat-image__fallback`,children:`Image unavailable`}):(0,n.jsx)(`img`,{src:e,alt:_e(e),loading:`lazy`,className:`chat-image__img`,title:i,style:{opacity:+!!a},onLoad:()=>o(!0),onError:()=>{o(!1),c(!0)}})]})}var ye=/@\[([^\]|]+)\|([^\]]+)\]/g,be=/(https?:\/\/\S+)/g;function xe(e){return e.replace(/[.,;:!?)]+$/,``)}function Se(e,r){if(!e.includes(`@`))return e;let i=e.split(/(@[a-zA-Z0-9_-]+)/g);return i.length===1?e:(0,n.jsx)(t.default.Fragment,{children:i.map((e,r)=>/^@[a-zA-Z0-9_-]+$/.test(e)?(0,n.jsx)(`strong`,{children:e},r):(0,n.jsx)(t.default.Fragment,{children:e},r))},`legacy-${r}`)}function Ce(e,r){let i=e.split(be);return i.length===1?$(e,r):(0,n.jsx)(n.Fragment,{children:i.map((e,i)=>{if(i%2==1){let r=xe(e),a=e.slice(r.length);return(0,n.jsxs)(t.default.Fragment,{children:[(0,n.jsx)(`a`,{href:r,className:`message-link`,target:`_blank`,rel:`noopener noreferrer`,children:r}),a]},`link-${i}`)}return e?(0,n.jsx)(t.default.Fragment,{children:$(e,r)},`text-${i}`):null})})}function $(e,t){if(!e.includes(`@`))return e;let r=[],i=0;ye.lastIndex=0;let a=ye.exec(e);for(;a!==null;){let[o,s,c]=a,l=a.index;l>i&&r.push(Se(e.slice(i,l),`${i}`));let u=!!t&&c.trim()===t;r.push((0,n.jsxs)(`span`,{className:`mention-chip${u?` mention-chip--self`:``}`,children:[`@`,s]},`mention-${l}`)),i=l+o.length,a=ye.exec(e)}return i<e.length&&r.push(Se(e.slice(i),`${i}-end`)),r.length===0?e:r.length===1?r[0]:(0,n.jsx)(n.Fragment,{children:r})}function we({content:e,stickers:r,currentUserId:i}){return(0,n.jsx)(n.Fragment,{children:w(e).map((e,a)=>{if(e.isImage&&e.url){let t=r.find(t=>t.url===e.url&&t.shortcode);return(0,n.jsx)(ve,{url:e.url,title:t?.shortcode?`:${t.shortcode}:`:void 0},`img-${a}-${e.url}`)}return(0,n.jsx)(t.default.Fragment,{children:Ce(e.text,i)},`txt-${a}`)})})}function Te({msg:e,stickers:t,currentUserId:r,onRetry:i}){let a=v(e.content,t),o=e.authorId===r,s=w(a).some(e=>e.isImage),c=ge(a),l=!!c,u=e.status===`sending`?`Sending…`:e.status===`failed`?`⚠ Failed`:``;return(0,n.jsxs)(`div`,{className:[`message-item`,o?`message-item--own`:`message-item--other`,s?`message-item--has-image`:``,l?`message-item--image`:``,`message-item--${e.status===`failed`?`failed`:`optimistic`}`].join(` `),children:[o&&(0,n.jsx)(Q,{displayName:e.authorDisplayName,avatarUrl:e.authorAvatarUrl}),!o&&(0,n.jsxs)(`div`,{className:`message-item__avatar-column`,children:[(0,n.jsx)(`span`,{className:`message-item__author`,children:e.authorDisplayName}),(0,n.jsx)(Q,{displayName:e.authorDisplayName,avatarUrl:e.authorAvatarUrl})]}),(0,n.jsxs)(`div`,{className:`message-item__bubble-wrap`,children:[(0,n.jsx)(`div`,{className:`message-item__name-row`,children:(0,n.jsx)(`span`,{className:`message-item__time`,children:me(e.createdAt)})}),l&&c?(0,n.jsx)(`div`,{className:`message-item__bare-image-wrap`,children:(0,n.jsx)(ve,{url:c,bare:!0})}):(0,n.jsx)(`div`,{className:`message-item__bubble`,children:(0,n.jsx)(we,{content:a,stickers:t,currentUserId:r})}),u&&(0,n.jsxs)(`div`,{className:`message-item__status-row`,children:[(0,n.jsx)(`span`,{className:`message-item__status`,children:u}),e.status===`failed`&&i&&(0,n.jsx)(`button`,{style:{fontSize:11,color:`var(--color-accent)`},onClick:()=>i(e.clientId),children:`Retry`})]})]})]})}function Ee({editContent:e,editError:t,onChange:r,onSave:i,onCancel:a}){return(0,n.jsxs)(`div`,{className:`message-item__edit-form`,children:[(0,n.jsx)(`textarea`,{value:e,onChange:e=>r(e.target.value),maxLength:2e3,autoFocus:!0,className:`message-item__edit-textarea`,rows:3}),t&&(0,n.jsx)(`div`,{className:`message-item__edit-error`,children:t}),(0,n.jsxs)(`div`,{className:`message-item__edit-actions`,children:[(0,n.jsx)(`button`,{className:`btn btn--primary btn--sm`,onClick:i,children:`Save`}),(0,n.jsx)(`button`,{className:`btn btn--secondary btn--sm`,onClick:a,children:`Cancel`})]})]})}function De({item:r,stickers:i,currentUserId:a,currentUserPermissions:o,stationSlug:s,getToken:c,onDelete:l,onBan:u,onReport:d,onReply:f,onEdit:p,onRetry:m,getUserInfo:h,getAvatarForMessage:g}){let[_,y]=(0,t.useState)(!1),[b,x]=(0,t.useState)(!1),[S,C]=(0,t.useState)(!1),[T,E]=(0,t.useState)(null),[D,O]=(0,t.useState)(!1),[k,A]=(0,t.useState)(``),[j,M]=(0,t.useState)(null),[N,P]=(0,t.useState)(!1),[F,ee]=(0,t.useState)(!1),[I,L]=(0,t.useState)(!1),R=(0,t.useRef)(null),z=(0,t.useRef)(null),B=(0,t.useRef)(null),V=o.includes(e.S.DELETE_ANY),H=o.includes(e.S.BAN_USER),U=o.includes(e.S.REPORT),te=o.includes(e.S.EDIT_OWN);if(r.kind===`optimistic`)return(0,n.jsx)(Te,{msg:r.msg,stickers:i,currentUserId:a,onRetry:m});let W=r.msg,G=W.user_id===a,K=W.is_deleted,q=W.user_id,J=h(q),Y=J?.displayName??`Unknown User`,ne=J?.isModerator??!1,re=g(q,new Date(W.created_at)),X=W.content??``,Z=K?X:v(X,i),ie=!K&&w(Z).some(e=>e.isImage),ae=K?null:ge(Z),oe=!!ae,se=q!==a,ce=!K&&G&&te&&(W.edit_count??0)<2&&he(W.created_at)&&!!p,ue=!K&&(V||o.includes(e.S.DELETE_OWN)&&G),fe=!K&&H&&se,_e=!K&&U&&se,ye=!K&&se,be=ce||ue||fe||_e||G||ye,xe=async()=>{if(!I){try{let e=c(),t={};e&&(t.Authorization=`Bearer ${e}`);let n=await fetch(`/api/chat/${s}/me/gravatar/gallery`,{headers:t});n.ok&&ee(((await n.json()).gallery||[]).length>0)}catch(e){console.error(`Failed to fetch Gravatar gallery:`,e)}L(!0)}},Se=async e=>{e.preventDefault(),e.stopPropagation(),G&&await xe(),E({x:e.clientX,y:e.clientY}),C(!0)},Ce=async e=>{e.stopPropagation(),G&&await xe();let t=R.current?.getBoundingClientRect();t&&E({x:t.right,y:t.bottom+2}),C(!0)},$=()=>{C(!1),E(null)},De=e=>{if(G||K)return;let t=e.touches[0];B.current={x:t.clientX,y:t.clientY},z.current=setTimeout(()=>{E({x:t.clientX,y:t.clientY}),C(!0)},500)},Oe=()=>{z.current&&=(clearTimeout(z.current),null)},ke=e=>{if(!B.current)return;let t=e.touches[0],n=t.clientX-B.current.x,r=t.clientY-B.current.y;(Math.abs(n)>10||Math.abs(r)>10)&&(z.current&&=(clearTimeout(z.current),null))},Ae=()=>{A(X),M(null),O(!0),$()},je=()=>{O(!1),A(``),M(null)},Me=async()=>{if(!p)return;let e=k.trim();if(!e){M(`Message cannot be empty`);return}if(e.length>2e3){M(`Message exceeds 2000 characters`);return}try{await p(W.id,e),O(!1),A(``),M(null)}catch{M(`Failed to edit message`)}},Ne=W.edited_at||W.created_at,Pe=W.edited_at?`Edited: `:``,Fe=me(Ne);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(`div`,{className:[`message-item`,G?`message-item--own`:`message-item--other`,ie?`message-item--has-image`:``,oe?`message-item--image`:``,K?`message-item--deleted`:``].filter(Boolean).join(` `),onContextMenu:!K&&be?Se:void 0,onTouchStart:De,onTouchEnd:Oe,onTouchMove:ke,children:[G&&!K&&(0,n.jsx)(Q,{displayName:Y,avatarUrl:re}),!G&&(0,n.jsx)(`div`,{className:`message-item__avatar-column`,children:(0,n.jsx)(Q,{displayName:Y,avatarUrl:re})}),(0,n.jsxs)(`div`,{className:`message-item__bubble-wrap`,children:[(0,n.jsxs)(`div`,{className:`message-item__name-row`,children:[!G&&!K&&(0,n.jsx)(`span`,{className:`message-item__author${ne?` message-item__author--mod`:``}`,children:Y}),(0,n.jsxs)(`span`,{className:`message-item__time`,children:[Pe,Fe]}),be&&(0,n.jsx)(`button`,{ref:R,className:`message-item__kebab-btn`,onClick:Ce,"aria-label":`Message actions`,children:`⋮`})]}),K?(0,n.jsx)(`div`,{className:`message-item__bubble`,children:`Message removed`}):D?(0,n.jsx)(Ee,{editContent:k,editError:j,onChange:A,onSave:Me,onCancel:je}):oe&&ae?(0,n.jsx)(`div`,{className:`message-item__bare-image-wrap`,children:(0,n.jsx)(ve,{url:ae,bare:!0})}):(0,n.jsxs)(`div`,{className:`message-item__bubble`,children:[W.reply_excerpt&&(0,n.jsx)(`div`,{className:`message-reply-bubble`,children:(0,n.jsxs)(`div`,{className:`message-reply-bubble__text`,children:[(0,n.jsx)(`div`,{className:`message-reply-bubble__author`,children:W.reply_author_name}),(0,n.jsx)(`div`,{className:`message-reply-bubble__excerpt`,children:W.reply_excerpt})]})}),(0,n.jsx)(we,{content:Z,stickers:i,currentUserId:a})]})]})]}),S&&T&&!K&&be&&(0,n.jsx)(de,{position:T,onClose:$,showAvatarOptions:G,hasGalleryImages:F,onSelectGravatarPhoto:()=>{$(),P(!0)},onUseDefaultGravatar:async()=>{try{let e=c();if(!(await fetch(`/api/chat/${s}/me/avatar/preference`,{method:`PATCH`,headers:{"Content-Type":`application/json`,...e?{Authorization:`Bearer ${e}`}:{}},body:JSON.stringify({preference:`default`})})).ok)throw Error(`Failed to update avatar preference`);$()}catch(e){console.error(`Failed to set default Gravatar:`,e),alert(`Failed to update avatar. Please try again.`)}},onUseInitials:async()=>{try{let e=c();if(!(await fetch(`/api/chat/${s}/me/avatar/preference`,{method:`PATCH`,headers:{"Content-Type":`application/json`,...e?{Authorization:`Bearer ${e}`}:{}},body:JSON.stringify({preference:null})})).ok)throw Error(`Failed to update avatar preference`);$()}catch(e){console.error(`Failed to clear avatar:`,e),alert(`Failed to update avatar. Please try again.`)}},showReply:ye,showEdit:ce,showDelete:ue,showReport:_e,showBan:fe,onReply:()=>{$(),f(W.id,Y,X)},onEdit:Ae,onDelete:()=>{$(),l(W.id)},onReport:()=>{$(),y(!0)},onBan:()=>{$(),x(!0)}}),N&&(0,n.jsx)(pe,{stationSlug:s,getToken:c,onClose:()=>P(!1),onSelect:async(e,t)=>{try{let t=c(),n=e.startsWith(`https://`)?{preference:`gravatar`,avatarUrl:e}:{preference:`gravatar`,style:e.split(`d=`)[1]?.split(`&`)[0]};if(!(await fetch(`/api/chat/${s}/me/avatar/preference`,{method:`PATCH`,headers:{"Content-Type":`application/json`,...t?{Authorization:`Bearer ${t}`}:{}},body:JSON.stringify(n)})).ok)throw Error(`Failed to update avatar preference`);P(!1)}catch(e){throw console.error(`Failed to select avatar:`,e),e}},currentAvatarUrl:re}),_&&(0,n.jsx)(le,{messageId:W.id,authorName:Y,onReport:d,onClose:()=>y(!1)}),b&&(0,n.jsx)(e.s,{userId:q,displayName:Y,onBan:u,onClose:()=>x(!1)})]})}function Oe({messages:e,optimistic:r,stickers:i,currentUserId:a,currentUserPermissions:o,stationSlug:s,getToken:c,loadingInitial:l,loadingOlder:u,hasOlderMessages:d,retentionCutoff:f,onLoadOlder:p,onEdit:m,onDelete:h,onBan:g,onReport:_,onReply:v,onRetry:y,getUserInfo:b,getAvatarForMessage:x}){let S=(0,t.useRef)(null),[C,w]=(0,t.useState)(!0),[T,E]=(0,t.useState)(!1),D=(0,t.useRef)(!0);(0,t.useEffect)(()=>{C&&!D.current&&S.current&&S.current.scrollTo({top:S.current.scrollHeight,behavior:`smooth`})},[e.length,r.length,C]),(0,t.useEffect)(()=>{!l&&e.length>0&&D.current&&requestAnimationFrame(()=>{requestAnimationFrame(()=>{S.current&&(S.current.scrollTop=S.current.scrollHeight,D.current=!1)})})},[l,e.length]);function O(){let e=S.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight<80;w(t),E(!t)}function k(){S.current?.scrollTo({top:S.current.scrollHeight,behavior:`smooth`}),w(!0),E(!1)}let A=[...e.map(e=>({kind:`server`,msg:e})),...r.map(e=>({kind:`optimistic`,msg:e}))],j=!d&&f!==null,M=f?new Date(f).toLocaleDateString(void 0,{year:`numeric`,month:`long`,day:`numeric`}):null;return l?(0,n.jsx)(`div`,{className:`message-list-container`,children:(0,n.jsxs)(`div`,{className:`messages-empty`,children:[(0,n.jsx)(`span`,{className:`connection-spinner`}),` Loading messages…`]})}):(0,n.jsxs)(`div`,{className:`message-list-container`,children:[d&&(0,n.jsx)(`div`,{className:`load-older-btn`,children:(0,n.jsx)(`button`,{onClick:p,disabled:u,children:u?`Loading…`:`↑ Load older messages`})}),(0,n.jsxs)(`div`,{className:`message-list`,ref:S,onScroll:O,children:[j&&M&&(0,n.jsxs)(`div`,{className:`retention-boundary`,children:[`Chat history before `,M,` is not available on this plan.`]}),A.length===0&&!j&&(0,n.jsx)(`div`,{className:`messages-empty`,children:`No messages yet. Be the first to say something! 👋`}),A.map(e=>(0,n.jsx)(De,{item:e,stickers:i,currentUserId:a,currentUserPermissions:o,stationSlug:s,getToken:c,onEdit:m,onDelete:h,onBan:g,onReport:_,onReply:v,onRetry:y,getUserInfo:b,getAvatarForMessage:x},e.kind===`server`?e.msg.id:`opt-${e.msg.clientId}`))]}),T&&(0,n.jsx)(`button`,{className:`scroll-to-bottom`,onClick:k,title:`Scroll to latest`,children:`↓`})]})}function ke({isConnected:e,stationSlug:n,onRefreshStickers:r}){let[i,a]=(0,t.useState)(!1),[o,s]=(0,t.useState)(!1),[c,l]=(0,t.useState)(null),u=(0,t.useRef)(null),d=(0,t.useRef)(null),f=(0,t.useCallback)(()=>a(!1),[]),p=(0,t.useCallback)(()=>{e&&a(e=>!e)},[e]);return(0,t.useEffect)(()=>{if(!i)return;async function e(){if(r){s(!0),l(null);try{await r()}catch{l(`Could not load stickers right now.`)}finally{s(!1)}}}e().catch(()=>void 0)},[i,r,n]),(0,t.useEffect)(()=>{if(!i)return;let e=e=>{e.key===`Escape`&&f()},t=e=>{let t=e.target;if(!t)return;let n=u.current?.contains(t)??!1,r=d.current?.contains(t)??!1;!n&&!r&&f()};return document.addEventListener(`keydown`,e),document.addEventListener(`mousedown`,t),()=>{document.removeEventListener(`keydown`,e),document.removeEventListener(`mousedown`,t)}},[i,f]),(0,t.useEffect)(()=>{!e&&i&&f()},[e,i,f]),{pickerOpen:i,pickerLoading:o,pickerError:c,pickerRef:u,stickerBtnRef:d,closePicker:f,togglePicker:p}}function Ae(e,n,r,i,a,o,s){let[c,l]=(0,t.useState)(-1),[u,d]=(0,t.useState)(!1),f=a?F(r,a.query,i):[];(0,t.useEffect)(()=>{l(-1),d(!1)},[a?.query]);let p=!o&&!!a&&f.length>0&&!u,m=(0,t.useMemo)(()=>{if(r.length===0)return;let e=r.reduce((e,t)=>Math.max(e,t.displayName.length),0);return Math.min(320,Math.max(120,e*8+52))},[r]);function h(t){let r=I(e,a?.start??n,a?.end??n,t);s(r.nextText,r.caretPosition)}return{mentionSuggestions:f,mentionHighlight:c,setMentionHighlight:l,mentionStripDismissed:u,setMentionStripDismissed:d,mentionStripVisible:p,mentionStripWidth:m,insertMention:h}}function je(e){return e.replace(/\.[^.]+$/,``).replace(/[-_]+/g,` `)||`Sticker`}function Me({pickerRef:e,pickerLoading:t,pickerError:r,pickerStickers:i,onClose:a,onInsert:o}){return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`div`,{className:`sticker-picker__overlay`,onClick:a}),(0,n.jsxs)(`div`,{className:`sticker-picker`,ref:e,role:`dialog`,"aria-label":`Sticker picker`,children:[(0,n.jsxs)(`div`,{className:`sticker-picker__header`,children:[(0,n.jsx)(`span`,{children:`Stickers`}),(0,n.jsx)(`button`,{type:`button`,className:`btn btn--icon sticker-picker__close`,onClick:a,"aria-label":`Close sticker picker`,title:`Close`,children:`✕`})]}),(0,n.jsxs)(`div`,{className:`sticker-picker__body`,children:[t&&(0,n.jsx)(`div`,{className:`sticker-picker__state`,children:`Loading stickers…`}),!t&&r&&(0,n.jsx)(`div`,{className:`sticker-picker__state`,children:r}),!t&&!r&&i.length===0&&(0,n.jsx)(`div`,{className:`sticker-picker__state`,children:`No stickers are available yet. Ask a station admin to upload them in the sticker manager.`}),!t&&!r&&i.length>0&&(0,n.jsx)(`div`,{className:`sticker-picker__grid`,children:i.map(e=>(0,n.jsxs)(`button`,{type:`button`,className:`sticker-picker__item`,onClick:()=>o(e),title:`:${e.shortcode}:`,"aria-label":`Insert sticker ${je(e.filename)}`,children:[(0,n.jsx)(`img`,{src:e.url,alt:je(e.filename),loading:`lazy`}),(0,n.jsxs)(`span`,{className:`sticker-picker__item-label`,children:[`:`,e.shortcode,`:`]})]},e.filename))})]})]})]})}function Ne({onSend:e,connectionStatus:r,canPost:i,onRequestAuth:a,stationSlug:o,getToken:s,stickers:c,onRefreshStickers:l,replyingTo:u,onCancelReply:d,onlineUsers:f=[],currentUserId:p}){let[m,h]=(0,t.useState)(``),[g,_]=(0,t.useState)(0),v=(0,t.useRef)(null),y=r===`connected`,{pickerOpen:b,pickerLoading:x,pickerError:S,pickerRef:C,stickerBtnRef:w,closePicker:T,togglePicker:E}=ke({isConnected:y,stationSlug:o,onRefreshStickers:l}),D=L(m,g),O=D?z(c,D.query):[],k=c.filter(e=>!!e.shortcode);function A(e,t){h(e),T(),requestAnimationFrame(()=>{let e=v.current;e&&(e.focus(),e.setSelectionRange(t,t),_(t),e.style.height=`auto`,e.style.height=`${Math.min(e.scrollHeight,120)}px`)})}let{mentionSuggestions:j,mentionHighlight:M,setMentionHighlight:N,setMentionStripDismissed:F,mentionStripVisible:B,mentionStripWidth:V,insertMention:H}=Ae(m,g,f,p,P(m,g),b,A);function U(){let t=m.trim();if(!(!t||!y)){if(!i){a(),h(``),v.current&&(v.current.style.height=`auto`);return}e(t),h(``),v.current&&(v.current.style.height=`auto`)}}function te(e){if(B){if(e.key===`ArrowDown`){e.preventDefault(),N(e=>(e+1)%j.length);return}if(e.key===`ArrowUp`){e.preventDefault(),N(e=>e<=0?j.length-1:e-1);return}if(e.key===`Escape`){e.preventDefault(),N(-1),F(!0);return}if(e.key===`Enter`&&M>=0){e.preventDefault(),H(j[M]);return}}if(e.key===`Tab`&&j.length===1){e.preventDefault(),H(j[0]);return}if(e.key===` `){let t=ee(m,g,f,p);if(t){e.preventDefault();let n=I(m,t.start,t.end,t.user);A(n.nextText,n.caretPosition);return}}e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),U())}function W(){let e=v.current;e&&(e.style.height=`auto`,e.style.height=`${Math.min(e.scrollHeight,120)}px`)}function G(e){let t=v.current,n=e.shortcode?`:${e.shortcode}: `:`${e.url} `;if(!t){let e=`${m}${n}`;A(e,e.length);return}let r=t.selectionStart??m.length,i=t.selectionEnd??m.length;A(`${m.slice(0,r)}${n}${m.slice(i)}`,r+n.length)}function K(e){let t=v.current,n=R(m,D?.start??t?.selectionStart??m.length,D?.end??t?.selectionEnd??m.length,e);A(n.nextText,n.caretPosition)}(0,t.useEffect)(()=>{let e=e=>{e.key===`Escape`&&u&&!b&&d()};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[u,b,d]),(0,t.useEffect)(()=>{u&&v.current&&v.current.focus()},[u]);let q=y?`Message…`:`Connecting…`;return(0,n.jsxs)(`div`,{className:`message-input-container`,children:[u&&(0,n.jsxs)(`div`,{className:`reply-preview`,children:[(0,n.jsxs)(`div`,{className:`reply-preview__content`,children:[(0,n.jsx)(`div`,{className:`reply-preview__line`}),(0,n.jsxs)(`div`,{className:`reply-preview__text`,children:[(0,n.jsx)(`div`,{className:`reply-preview__author`,children:u.authorName}),(0,n.jsx)(`div`,{className:`reply-preview__excerpt`,children:u.excerpt})]})]}),(0,n.jsx)(`button`,{type:`button`,className:`reply-preview__cancel`,onClick:d,"aria-label":`Cancel reply`,title:`Cancel reply (Esc)`,children:`✕`})]}),(0,n.jsxs)(`div`,{className:`message-input-bar`,children:[(0,n.jsx)(`button`,{type:`button`,ref:w,className:`sticker-btn`,onMouseDown:e=>e.preventDefault(),onClick:E,disabled:!y,title:`Open sticker picker`,"aria-label":`Open sticker picker`,children:`☺`}),(0,n.jsx)(`textarea`,{ref:v,className:`message-input`,value:m,onChange:e=>{h(e.target.value),_(e.target.selectionStart??e.target.value.length)},onKeyDown:te,onInput:W,onClick:e=>_(e.currentTarget.selectionStart??m.length),onKeyUp:e=>_(e.currentTarget.selectionStart??m.length),onSelect:e=>_(e.currentTarget.selectionStart??m.length),placeholder:q,disabled:!y,rows:1,maxLength:2e3}),(0,n.jsx)(`button`,{type:`button`,className:`send-btn`,onClick:U,disabled:!y||!m.trim(),title:`Send (Enter)`,"aria-label":`Send message`,children:`↑`}),B&&(0,n.jsx)(`div`,{className:`mention-suggestions`,role:`listbox`,"aria-label":`Mention suggestions`,style:V?{width:V}:void 0,children:j.map((e,t)=>(0,n.jsxs)(`button`,{type:`button`,className:`mention-suggestions__item${t===M?` mention-suggestions__item--highlighted`:``}`,onMouseDown:e=>e.preventDefault(),onClick:()=>H(e),children:[(0,n.jsx)(`span`,{className:`mention-suggestions__at`,children:`@`}),(0,n.jsx)(`span`,{className:`mention-suggestions__name`,children:e.displayName})]},e.id))}),!b&&D&&O.length>0&&(0,n.jsx)(`div`,{className:`sticker-suggestions`,role:`listbox`,"aria-label":`Sticker shortcode suggestions`,children:O.map(e=>(0,n.jsxs)(`button`,{type:`button`,className:`sticker-suggestions__item`,onMouseDown:e=>e.preventDefault(),onClick:()=>K(e.shortcode),children:[(0,n.jsx)(`img`,{src:e.url,alt:e.shortcode??``,loading:`lazy`}),(0,n.jsxs)(`span`,{className:`sticker-suggestions__code`,children:[`:`,e.shortcode,`:`]})]},e.filename))}),b&&(0,n.jsx)(Me,{pickerRef:C,pickerLoading:x,pickerError:S,pickerStickers:k,onClose:T,onInsert:G})]})]})}function Pe(e){return e.split(` `).map(e=>e[0]).join(``).toUpperCase().slice(0,2)}function Fe({users:e,currentUserId:t,style:r}){return(0,n.jsxs)(`div`,{className:`user-list`,style:r,children:[(0,n.jsxs)(`div`,{className:`user-list__title`,children:[`Online — `,e.length]}),e.map(e=>(0,n.jsxs)(`div`,{className:`user-list__item`,children:[(0,n.jsx)(`div`,{className:`user-list__avatar`,children:Pe(e.displayName)}),(0,n.jsx)(`span`,{className:`user-list__name`,children:e.displayName}),e.id===t&&(0,n.jsx)(`span`,{className:`user-list__self-badge`,children:`you`})]},e.id))]})}var Ie={disconnected:`Disconnected — check your connection`,connecting:`Connecting…`,reconnecting:`Reconnecting…`,connected:``};function Le({status:e}){return e===`connected`?null:(0,n.jsxs)(`div`,{className:`connection-status connection-status--${e}`,children:[(e===`connecting`||e===`reconnecting`)&&(0,n.jsx)(`span`,{className:`connection-spinner`}),Ie[e]]})}function Re({stationSlug:r,initialChatName:i,getToken:a,onUpdated:o}){let[s,c]=(0,t.useState)(i),[l,u]=(0,t.useState)(!1),[d,f]=(0,t.useState)(``),[p,m]=(0,t.useState)(!1),[h,g]=(0,t.useState)(null),_=(0,t.useRef)(null),v=(0,t.useRef)(new e.x(``,a)).current;(0,t.useEffect)(()=>{l||c(i)},[i]);let y=(0,t.useCallback)(()=>{f(s??``),g(null),u(!0),setTimeout(()=>_.current?.focus(),0)},[s]),b=(0,t.useCallback)(()=>{u(!1),g(null)},[]),x=(0,t.useCallback)(async()=>{let e=d.trim();if(e.length>40){g(`Name must be 40 characters or fewer`);return}m(!0),g(null);try{let t=await v.updateChatName(r,e.length===0?null:e);c(t.chatName),u(!1),o?.(t.chatName,t.displayName)}catch(e){g(e?.message??`Failed to save chat name`)}finally{m(!1)}},[v,d,r,o]),S=(0,t.useCallback)(e=>{e.key===`Enter`&&x(),e.key===`Escape`&&b()},[x,b]);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`button`,{className:`btn btn--ghost chat-name-btn`,onClick:y,title:s?`Change your display name`:`Set your display name`,"aria-label":s?`Display name: ${s}. Click to change.`:`Set your display name`,children:(0,n.jsx)(`span`,{className:`chat-name-btn__label`,children:s??`Set name`})}),l&&(0,n.jsx)(`div`,{className:`modal-overlay`,onClick:b,children:(0,n.jsxs)(`div`,{className:`modal`,onClick:e=>e.stopPropagation(),children:[(0,n.jsx)(`div`,{className:`modal__title`,children:s?`Change display name`:`Set display name`}),(0,n.jsxs)(`div`,{className:`modal__body`,children:[(0,n.jsx)(`p`,{children:`This is how other listeners will see you in chat.`}),(0,n.jsx)(`input`,{ref:_,type:`text`,value:d,maxLength:40,placeholder:`Your chat name (max 40 characters)`,onChange:e=>f(e.target.value),onKeyDown:S,disabled:p,"aria-label":`Chat display name`}),h&&(0,n.jsx)(`p`,{style:{color:`var(--color-danger)`,fontSize:`var(--font-size-xs)`,marginTop:`var(--spacing-xs)`},children:h})]}),(0,n.jsxs)(`div`,{className:`modal__footer`,children:[(0,n.jsx)(`button`,{className:`btn btn--ghost`,onClick:b,disabled:p,children:`Cancel`}),(0,n.jsx)(`button`,{className:`btn btn--primary`,onClick:x,disabled:p,style:{width:`auto`},children:p?`…`:`Save`})]})]})})]})}function ze(e){return e.split(` `).map(e=>e[0]).join(``).toUpperCase().slice(0,2)}function Be({users:e,currentUserId:r,onClose:i}){let a=(0,t.useCallback)(e=>{e.key===`Escape`&&i()},[i]);return(0,t.useEffect)(()=>(document.addEventListener(`keydown`,a),()=>document.removeEventListener(`keydown`,a)),[a]),(0,n.jsx)(`div`,{className:`modal-overlay`,onClick:i,children:(0,n.jsxs)(`div`,{className:`modal user-list-modal`,onClick:e=>e.stopPropagation(),children:[(0,n.jsxs)(`div`,{className:`modal__title user-list-modal__header`,children:[(0,n.jsxs)(`span`,{children:[`Online — `,e.length]}),(0,n.jsx)(`button`,{className:`btn btn--icon user-list-modal__close`,onClick:i,"aria-label":`Close`,title:`Close`,children:`✕`})]}),(0,n.jsx)(`div`,{className:`modal__body user-list-modal__body`,children:e.length===0?(0,n.jsx)(`p`,{style:{color:`var(--color-text-muted)`},children:`No listeners online.`}):e.map(e=>(0,n.jsxs)(`div`,{className:`user-list__item user-list-modal__item`,children:[(0,n.jsx)(`div`,{className:`user-list__avatar`,children:ze(e.displayName)}),(0,n.jsx)(`span`,{className:`user-list__name`,children:e.displayName}),e.id===r&&(0,n.jsx)(`span`,{className:`user-list__self-badge`,children:`you`})]},e.id))})]})})}function Ve({email:e,pendingId:r,onVerify:i,onResend:a,onChangeEmail:o,isSubmitting:s,error:c}){let[l,u]=(0,t.useState)(``),[d,f]=(0,t.useState)(30),[p,m]=(0,t.useState)(!1),h=(0,t.useRef)(null);(0,t.useEffect)(()=>{h.current?.focus()},[]),(0,t.useEffect)(()=>{if(d>0){let e=setTimeout(()=>f(d-1),1e3);return()=>clearTimeout(e)}},[d]),(0,t.useEffect)(()=>{l.length===6&&!s&&_()},[l]);function g(e){u(e.replace(/\D/g,``).slice(0,6))}async function _(){l.length!==6||s||await i(l)}async function v(){if(!(d>0||p)){m(!0);try{await a(),f(30),u(``)}finally{m(!1)}}}return(0,n.jsxs)(`div`,{className:`otp-code-input`,children:[(0,n.jsx)(`div`,{className:`otp-code-input__icon`,children:`🔑`}),(0,n.jsx)(`h2`,{className:`otp-code-input__title`,children:`Enter verification code`}),(0,n.jsxs)(`p`,{className:`otp-code-input__hint`,children:[`We sent a 6-digit code to `,(0,n.jsx)(`strong`,{children:e})]}),(0,n.jsx)(`input`,{ref:h,type:`text`,inputMode:`numeric`,pattern:`[0-9]*`,className:`otp-code-input__field`,placeholder:`000000`,value:l,onChange:e=>g(e.target.value),disabled:s,autoComplete:`one-time-code`,maxLength:6}),c&&(0,n.jsx)(`div`,{className:`otp-code-input__error`,children:c}),(0,n.jsxs)(`div`,{className:`otp-code-input__actions`,children:[(0,n.jsx)(`button`,{type:`button`,className:`btn btn--ghost btn--small`,onClick:o,disabled:s||p,children:`Use different email`}),(0,n.jsx)(`button`,{type:`button`,className:`btn btn--ghost btn--small`,onClick:v,disabled:d>0||p,children:p?`Sending…`:d>0?`Resend (${d}s)`:`Resend code`})]}),l.length===6&&(0,n.jsx)(`p`,{className:`otp-code-input__auto-submit`,children:`Verifying...`})]})}function He({isOpen:e,onClose:r,onRequestCode:i,onVerifyCode:a,stationSlug:o,error:s}){let[c,l]=(0,t.useState)(``),[u,d]=(0,t.useState)(!1),[f,p]=(0,t.useState)(null),[m,h]=(0,t.useState)(null),g=(0,t.useRef)(null);(0,t.useEffect)(()=>{e||(l(``),d(!1),p(null),h(null))},[e]),(0,t.useEffect)(()=>{e&&!f&&g.current?.focus()},[e,f]),(0,t.useEffect)(()=>{if(!e)return;function t(e){e.key===`Escape`&&x()}return document.addEventListener(`keydown`,t),()=>document.removeEventListener(`keydown`,t)},[e]);async function _(){if(!(!c.trim()||u)){d(!0),h(null);try{p((await i(c)).pendingId)}catch{}finally{d(!1)}}}async function v(e){if(f){d(!0),h(null);try{await a(f,e)}catch(e){h(e?.message??`Invalid or expired code`)}finally{d(!1)}}}async function y(){c.trim()&&(h(null),p((await i(c)).pendingId))}function b(){p(null),h(null),l(``)}function x(){u||(console.log(`[AuthModal] handleClose called`),r())}function S(e){e.key===`Enter`&&c.trim()&&!u&&(e.preventDefault(),_())}return e?f?(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`div`,{className:`modal-overlay`,onClick:x}),(0,n.jsx)(`div`,{className:`auth-modal`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`auth-modal-title`,children:(0,n.jsxs)(`div`,{className:`auth-modal__content`,children:[(0,n.jsx)(`button`,{type:`button`,className:`auth-modal__close-x`,onClick:x,"aria-label":`Close`,title:`Close`,children:`✕`}),(0,n.jsx)(Ve,{email:c,pendingId:f,onVerify:v,onResend:y,onChangeEmail:b,isSubmitting:u,error:m})]})})]}):(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(`div`,{className:`modal-overlay`,onClick:x}),(0,n.jsx)(`div`,{className:`auth-modal`,role:`dialog`,"aria-modal":`true`,"aria-labelledby":`auth-modal-title`,children:(0,n.jsxs)(`div`,{className:`auth-modal__content`,children:[(0,n.jsx)(`div`,{className:`auth-modal__icon`,children:`🔒`}),(0,n.jsx)(`h2`,{id:`auth-modal-title`,className:`auth-modal__title`,children:`Sign in to post messages`}),(0,n.jsx)(`input`,{ref:g,type:`email`,className:`auth-modal__input`,placeholder:`your@email.com`,value:c,onChange:e=>l(e.target.value),onKeyDown:S,disabled:u,autoComplete:`email`}),s&&(0,n.jsx)(`div`,{className:`auth-modal__error`,children:s}),(0,n.jsxs)(`div`,{className:`auth-modal__buttons`,children:[(0,n.jsx)(`button`,{type:`button`,className:`btn btn--ghost`,onClick:x,disabled:u,children:`Cancel`}),(0,n.jsx)(`button`,{type:`button`,className:`btn btn--primary`,onClick:_,disabled:!c.trim()||u,children:u?`Sending…`:`Continue`})]})]})})]}):null}function Ue({onMention:e,onChannel:n,mentionSoundUrl:r,channelSoundUrl:i}){let a=(0,t.useRef)(null),o=(0,t.useRef)(null),s=(0,t.useRef)(null),c=(0,t.useRef)(r),l=(0,t.useRef)(i);(0,t.useEffect)(()=>{c.current=r},[r]),(0,t.useEffect)(()=>{l.current=i},[i]),(0,t.useEffect)(()=>{function e(){t();let e=new AudioContext;a.current=e,e.resume().then(()=>{if(e.state!==`running`)return;let t=e.createBuffer(1,1,e.sampleRate),n=e.createBufferSource();n.buffer=t,n.connect(e.destination),n.start(0);let r=[];c.current&&r.push(fetch(c.current).then(e=>e.arrayBuffer()).then(t=>e.decodeAudioData(t)).then(e=>{o.current=e}).catch(()=>{})),l.current&&r.push(fetch(l.current).then(e=>e.arrayBuffer()).then(t=>e.decodeAudioData(t)).then(e=>{s.current=e}).catch(()=>{})),Promise.all(r)}).catch(()=>{})}function t(){document.removeEventListener(`mousedown`,e,!0),document.removeEventListener(`touchstart`,e,!0),document.removeEventListener(`touchend`,e,!0),document.removeEventListener(`keydown`,e,!0)}return document.addEventListener(`mousedown`,e,!0),document.addEventListener(`touchstart`,e,!0),document.addEventListener(`touchend`,e,!0),document.addEventListener(`keydown`,e,!0),t},[]);async function u(){let e=a.current;if(!e)return null;if(e.state!==`running`)try{await e.resume()}catch{return null}return e.state===`running`?e:null}async function d(){let e=await u();if(!e||!o.current)return;let t=e.createBufferSource();t.buffer=o.current,t.connect(e.destination),t.start(0)}async function f(){let e=await u();if(!e||!s.current)return;let t=e.createBufferSource();t.buffer=s.current,t.connect(e.destination),t.start(0)}return(0,t.useEffect)(()=>{e(d)},[e]),(0,t.useEffect)(()=>{n(f)},[n]),null}function We(){let{isMuted:e,setIsMuted:t}=A();return(0,n.jsx)(`button`,{className:`mute-toggle`,onClick:()=>{let n=!e;t(n);let r=n?`Notifications muted`:`Notifications unmuted`,i=document.createElement(`div`);i.setAttribute(`role`,`status`),i.setAttribute(`aria-live`,`polite`),i.className=`sr-only`,i.textContent=r,document.body.appendChild(i),setTimeout(()=>document.body.removeChild(i),1e3)},"aria-label":e?`Unmute notifications`:`Mute notifications`,title:e?`Unmute notifications`:`Mute notifications`,type:`button`,children:e?(0,n.jsx)(oe,{className:`mute-toggle__icon`,"aria-hidden":`true`}):(0,n.jsx)(ae,{className:`mute-toggle__icon`,"aria-hidden":`true`})})}function Ge({onResize:e,containerRef:r,minWidth:i=120,maxFraction:a=.5}){let o=(0,t.useRef)(!1),s=(0,t.useCallback)(t=>{o.current=!0,document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let n=t=>{if(!o.current||!r.current)return;let n=r.current.getBoundingClientRect(),s=n.width*a,c=n.right-t;e(Math.min(s,Math.max(i,c)))},s=e=>n(e.clientX),c=e=>{e.touches.length>0&&n(e.touches[0].clientX)},l=()=>{o.current=!1,document.body.style.userSelect=``,document.body.style.cursor=``,document.removeEventListener(`mousemove`,s),document.removeEventListener(`mouseup`,l),document.removeEventListener(`touchmove`,c),document.removeEventListener(`touchend`,l)};document.addEventListener(`mousemove`,s),document.addEventListener(`mouseup`,l),document.addEventListener(`touchmove`,c,{passive:!0}),document.addEventListener(`touchend`,l)},[r,i,a,e]);return(0,n.jsx)(`div`,{className:`pane-divider`,onMouseDown:(0,t.useCallback)(e=>{e.preventDefault(),s(e.clientX)},[s]),onTouchStart:(0,t.useCallback)(e=>{e.touches.length>0&&s(e.touches[0].clientX)},[s]),"aria-hidden":`true`})}var Ke=`relaya_sidebar_width`,qe=768,Je=220;function Ye({auth:r,showBranding:i=!0,serverUrl:a,hideSignOut:o=!1,hideAdmin:s=!1}){let{user:c,station:l,stationSlug:u,getToken:d}=r,[f,p]=(0,t.useState)(c?.chatName??null),[m,h]=(0,t.useState)(!1),[g,_]=(0,t.useState)(!1),[v,y]=(0,t.useState)(null),[b,x]=(0,t.useState)([]),[S,C]=(0,t.useState)({mentionSoundUrl:null,channelSoundUrl:null}),w=(0,t.useRef)(new e.x(``,d)),T=(0,t.useRef)(null),[E,D]=(0,t.useState)(()=>typeof window<`u`&&window.innerWidth>=qe),[O,k]=(0,t.useState)(()=>{try{let e=localStorage.getItem(Ke);return e?parseInt(e,10):Je}catch{return Je}});(0,t.useEffect)(()=>{let e=window.matchMedia(`(min-width: ${qe}px)`),t=e=>D(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let A=(0,t.useCallback)(e=>{k(e);try{localStorage.setItem(Ke,String(Math.round(e)))}catch{}},[]),j=(0,t.useMemo)(()=>({width:O}),[O]),M=(0,t.useCallback)(async()=>{try{x((await w.current.getStickers(u)).stickers??[])}catch{}},[u]),P=N(r,d,{onStickersUpdated:M,wsBaseUrl:a,onForcedLogout:r.logout});(0,t.useEffect)(()=>{r.status===`authenticated`&&c&&w.current.getMe(u).then(e=>p(e.chatName)).catch(()=>{}),M().catch(()=>void 0),w.current.getSounds(u).then(e=>C(e)).catch(()=>{})},[u,r.status,c]),(0,t.useEffect)(()=>{let e=window.setInterval(()=>{M().catch(()=>void 0)},6e4),t=()=>{M().catch(()=>void 0)};return window.addEventListener(`focus`,t),document.addEventListener(`visibilitychange`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t),document.removeEventListener(`visibilitychange`,t)}},[M]);let F=r.status===`authenticated`&&(c?.permissions.includes(e.S.POST)??!1),ee=c?.permissions.includes(e.S.DELETE_ANY)??!1,I=c?.permissions.includes(e.S.MANAGE_ROLES)??!1,L=e._.embed,R=l?.name||u.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),z=(()=>{let e=new URL(window.location.href);return e.searchParams.delete(`embed`),e.toString()})(),B=(()=>{let e=new URL(window.location.href);return e.searchParams.set(`admin`,`true`),e.searchParams.delete(`embed`),e.toString()})();return(0,n.jsxs)(`div`,{className:`chat-window`,children:[(0,n.jsxs)(`div`,{className:`chat-header`,children:[(0,n.jsx)(`div`,{className:`chat-header__title`,children:R}),r.status===`authenticated`&&(0,n.jsx)(We,{}),(0,n.jsxs)(`button`,{className:`chat-header__online`,onClick:()=>h(!0),title:`${P.totalCount} listener${P.totalCount===1?``:`s`} online — tap to see who's here`,"aria-label":`${P.totalCount} listeners online. Tap to see list.`,children:[(0,n.jsx)(`svg`,{width:`18`,height:`14`,viewBox:`0 0 24 24`,fill:`currentColor`,"aria-hidden":`true`,children:(0,n.jsx)(`path`,{d:`M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z`})}),P.totalCount]}),r.status===`authenticated`&&(0,n.jsx)(Re,{stationSlug:u,initialChatName:f,getToken:d,onUpdated:e=>p(e)}),L&&(0,n.jsx)(`a`,{href:z,target:`_blank`,rel:`noopener noreferrer`,className:`btn btn--ghost chat-header__popout`,title:`Open in new window`,"aria-label":`Open chat in new window`,children:(0,n.jsx)(`svg`,{width:`14`,height:`14`,viewBox:`0 0 14 14`,fill:`currentColor`,"aria-hidden":`true`,children:(0,n.jsx)(`path`,{d:`M9 1h4v4l-1.5-1.5L8 7 7 6l3.5-3.5L9 1zM2 3h5v1H3v7h7V8h1v3a1 1 0 01-1 1H3a1 1 0 01-1-1V4a1 1 0 011-1z`})})}),r.status===`anonymous`?(0,n.jsx)(`button`,{className:`btn btn--primary chat-header__signin`,onClick:()=>_(!0),title:`Sign in`,children:`Sign in`}):o?null:(0,n.jsx)(`button`,{className:`btn btn--ghost chat-header__signout`,onClick:r.logout,title:`Sign out`,children:`Sign out`}),!s&&(I||ee)&&(0,n.jsx)(`a`,{href:B,target:`_blank`,rel:`noopener noreferrer`,className:`btn btn--ghost chat-header__admin`,title:`Open admin panel`,"aria-label":`Open admin panel in new window`,children:(0,n.jsx)(se,{className:`chat-header__admin-icon`,"aria-hidden":`true`})})]}),(0,n.jsx)(Le,{status:P.connectionStatus}),(0,n.jsxs)(`div`,{className:`chat-body`,ref:T,children:[(0,n.jsx)(Oe,{messages:P.messages,optimistic:P.optimistic,stickers:b,currentUserId:c?.id??``,currentUserPermissions:c?.permissions??[],stationSlug:u,getToken:d,loadingInitial:P.loadingInitial,loadingOlder:P.loadingOlder,hasOlderMessages:P.hasOlderMessages,retentionCutoff:P.retentionCutoff,onLoadOlder:P.loadOlderMessages,onEdit:P.editMessage,onDelete:P.deleteMessage,onBan:P.banUser,onReport:P.reportMessage,onRetry:P.retryFailed,onReply:(e,t,n)=>{y({messageId:e,authorName:t,excerpt:n.length>60?n.substring(0,60)+`…`:n})},getUserInfo:P.getUserInfo,getAvatarForMessage:P.getAvatarForMessage}),E&&(0,n.jsx)(Ge,{onResize:A,containerRef:T}),(0,n.jsx)(Fe,{users:P.users,currentUserId:c?.id??``,style:j})]}),(0,n.jsx)(Ne,{onSend:e=>{P.sendMessage(e,v||void 0),y(null)},connectionStatus:P.connectionStatus,canPost:F,onRequestAuth:()=>_(!0),stationSlug:u,getToken:d,stickers:b,onRefreshStickers:M,replyingTo:v,onCancelReply:()=>y(null),onlineUsers:P.users,currentUserId:c?.id}),i&&(0,n.jsx)(`div`,{className:`relaya-branding`,children:(0,n.jsx)(`a`,{href:`https://relaya.chat?ref=powered-by`,target:`_blank`,rel:`noopener noreferrer`,children:`Powered by Relaya`})}),m&&(0,n.jsx)(Be,{users:P.users,currentUserId:c?.id??``,onClose:()=>h(!1)}),(0,n.jsx)(He,{isOpen:g,onClose:()=>{console.log(`[ChatWindow] Closing AuthModal`),_(!1)},onRequestCode:async e=>({pendingId:(await w.current.requestCode(e,u)).pendingId}),onVerifyCode:async(e,t)=>{let n=await w.current.verifyCode(e,t,u);r.onOtpVerified(n),_(!1)},stationSlug:u,error:r.error}),r.status===`authenticated`&&(0,n.jsx)(Ue,{onMention:P.registerMentionSound,onChannel:P.registerChannelSound,mentionSoundUrl:S.mentionSoundUrl,channelSoundUrl:S.channelSoundUrl})]})}function Xe({stationSlug:e,userDisplayName:t}){return e.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),(0,n.jsx)(`div`,{className:`auth-success`,children:(0,n.jsxs)(`div`,{className:`auth-success__card`,children:[(0,n.jsx)(`div`,{className:`success-icon`,children:`✅`}),(0,n.jsx)(`h1`,{children:`You're signed in!`}),(0,n.jsxs)(`p`,{className:`user-greeting`,children:[`Welcome, `,t]}),(0,n.jsx)(`div`,{className:`instructions`,children:(0,n.jsxs)(`p`,{children:[`Close this tab and`,(0,n.jsx)(`br`,{}),(0,n.jsx)(`strong`,{children:`refresh the chat page`}),(0,n.jsx)(`br`,{}),`to start posting messages.`]})})]})})}function Ze(t){return e._.admin?(0,n.jsx)(e.t,{className:t.className,spaceSlug:t.spaceSlug,serverUrl:t.serverUrl,token:t.token,manageOwnRefreshToken:t.manageOwnRefreshToken,onSessionEnded:t.onSessionEnded}):(0,n.jsx)(Qe,{...t})}function Qe({serverUrl:r,spaceSlug:i,token:o,className:s,manageOwnRefreshToken:c,onSessionEnded:l,hideSignOut:u,hideAdmin:d}){let f=c??!e._.managed,p=u??!f,m=e.g({spaceSlug:i,initialToken:o??null,manageOwnRefreshToken:f,onSessionEnded:l}),[h,g]=(0,t.useState)(!1),[_,v]=(0,t.useState)(!0);(0,t.useEffect)(()=>{a()},[]),(0,t.useEffect)(()=>{document.documentElement.setAttribute(`data-theme`,e._.theme);let t=e.u(i);t&&e.l(t);let n=`${r}/api/chat/${i}/theme`;fetch(n).then(e=>e.ok?e.json():{light:{},dark:{}}).then(t=>{(Object.keys(t?.light??{}).length>0||Object.keys(t?.dark??{}).length>0)&&e.m({light:t.light??{},dark:t.dark??{}},e._.theme)}).catch(()=>{})},[r,i]),(0,t.useEffect)(()=>{let e=`${r}/api/public/config?slug=${encodeURIComponent(i)}`;fetch(e).then(e=>e.ok?e.json():null).then(e=>{e&&typeof e.showBranding==`boolean`&&v(e.showBranding)}).catch(()=>{})},[r,i]),(0,t.useEffect)(()=>{e._.magicLinkToken&&m.status===`authenticated`&&g(!0)},[m.status]);let y=s?`relaya-root ${s}`:`relaya-root`;if(m.status===`loading`)return(0,n.jsx)(`div`,{className:y,children:(0,n.jsx)(`div`,{className:`app`,children:(0,n.jsxs)(`div`,{className:`loading-screen`,children:[(0,n.jsx)(`div`,{className:`connection-spinner`}),(0,n.jsx)(`span`,{children:`Loading…`})]})})});if(m.status===`magic-link-sent`)return(0,n.jsx)(`div`,{className:y,children:(0,n.jsx)(`div`,{className:`app`,children:(0,n.jsx)(V,{onBack:m.logout})})});if(m.status===`unauthenticated`)return(0,n.jsx)(`div`,{className:y,children:(0,n.jsx)(`div`,{className:`app`,children:(0,n.jsx)(B,{onLogin:m.login,error:m.error,stationSlug:i})})});let b=window.self!==window.top;return m.status===`authenticated`&&h&&!b?(0,n.jsx)(`div`,{className:y,children:(0,n.jsx)(`div`,{className:`app`,children:(0,n.jsx)(Xe,{stationSlug:m.stationSlug,userDisplayName:m.user?.displayName??`there`})})}):(0,n.jsx)(`div`,{className:y,children:(0,n.jsx)(`div`,{className:`app`,children:(0,n.jsx)(k,{children:(0,n.jsx)(Ye,{auth:m,showBranding:_,serverUrl:r,hideSignOut:p,hideAdmin:d})})})})}exports.AdminPanel=e.t,exports.AdminSettings=e.i,exports.AudioNotification=Ue,exports.AuthModal=He,exports.AuthSuccess=Xe,exports.BanManagement=e.a,exports.BanModal=e.s,exports.ChatNameEditor=Re,exports.ChatWindow=Ye,exports.ConnectionStatus=Le,exports.GravatarStyleModal=pe,exports.LoginScreen=B,exports.MagicLinkSent=V,exports.MessageAvatar=Q,exports.MessageContextMenu=de,exports.MessageInput=Ne,exports.MessageItem=De,exports.MessageList=Oe,exports.MuteToggle=We,exports.NotificationMuteProvider=k,exports.OTPCodeInput=Ve,exports.RelayaChat=Ze,exports.ReportModal=le,exports.ReportReview=e.o,exports.StickerAdminPage=e.r,exports.ThemeAdminPage=e.n,exports.UserList=Fe,exports.UserListModal=Be,exports.appConfig=e._,exports.applyDbTheme=e.m,exports.applySpaceTheme=e.l,exports.buildWsUrl=e.v,exports.clearTokenFromUrl=e.y,exports.findActiveMentionQuery=P,exports.findActiveShortcodeQuery=L,exports.getMentionSuggestions=F,exports.getSpaceTheme=e.u,exports.getStickerSuggestions=z,exports.injectRelayaStyles=a,exports.insertMentionToken=I,exports.insertStickerShortcode=R,exports.parseConfig=e.b,exports.removeRelayaStyles=o,exports.reorderStickersByFilename=e.c,exports.resolveSpaceCompletion=ee,exports.useBans=e.p,exports.useModerationConfig=e.f,exports.useNotificationMute=A,exports.useRelayaAuth=e.g,exports.useRelayaChat=N,exports.useReports=e.d,exports.useSpaceTheme=e.h;
|