From f9b8cd10b21a427ce2ea592ee7c27a86c23c191e Mon Sep 17 00:00:00 2001 From: Kunthawat Greethong Date: Thu, 27 Aug 2026 13:26:58 +0700 Subject: [PATCH] feat(deploy): single-container Docker packaging (nginx + Flask + prebuilt SPA) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add self-contained Docker deployment for EasyPanel / docker-compose: - Dockerfile: python:3.11-slim + nginx. Serves the PREBUILT Vue SPA (frontend/dist, committed) via nginx and reverse-proxies /api to the Flask backend on 127.0.0.1:5000. No node/npm in the image (avoids Vite/npm flakiness in Docker builds). VOLUME /app/backend/data for persistence (factor vintages, dividend ledger, forward runs, prices). HEALTHCHECK hits /api/v1/dashboard/summary. Exposes :80. - deploy/nginx.conf: SPA fallback + /api proxy to 127.0.0.1:5000 + gzip. - deploy/entrypoint.sh: starts Flask (HOST=0.0.0.0:5000) + nginx foreground, forwards signals. - docker-compose.yml: single service 'set50', port 8080:80, mounts ./backend/data for persistence, healthcheck. - .dockerignore excludes .git/.venv/backend/data/node_modules/docs. - .gitignore now tracks frontend/dist/ (prebuilt bundle required by the image); backend/data stays untracked. - Backend runtime verified: test_client GET /api/v1/dashboard/summary=200 (the HEALTHCHECK path). entrypoint sh -n, compose YAML parse, and all Dockerfile-referenced files exist. NOTE: no local docker here, so the image itself was not built — that happens on EasyPanel. --- .dockerignore | 14 +++++++++ .gitignore | 3 +- Dockerfile | 40 +++++++++++++++++++++++++ deploy/entrypoint.sh | 26 ++++++++++++++++ deploy/nginx.conf | 29 ++++++++++++++++++ docker-compose.yml | 26 ++++++++++++++++ frontend/dist/assets/index-DDItjwYy.js | 18 +++++++++++ frontend/dist/assets/index-z73iDem3.css | 1 + frontend/dist/index.html | 14 +++++++++ 9 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 deploy/entrypoint.sh create mode 100644 deploy/nginx.conf create mode 100644 docker-compose.yml create mode 100644 frontend/dist/assets/index-DDItjwYy.js create mode 100644 frontend/dist/assets/index-z73iDem3.css create mode 100644 frontend/dist/index.html diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d8e3c53 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,14 @@ +.git +.venv +.hermes +__pycache__ +*.pyc +.pytest_cache +backend/.pytest_cache +backend/data +backend/.venv +frontend/node_modules +reports +.DS_Store +.env +docs diff --git a/.gitignore b/.gitignore index a3126c0..d1a9e88 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ __pycache__/ backend/.pytest_cache/ backend/data/ frontend/node_modules/ -frontend/dist/ +# note: frontend/dist/ is intentionally TRACKED (prebuilt static bundle used by +# the Docker image — see Dockerfile). Rebuild with `cd frontend && npm run build`. reports/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..06706d3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# SET50 alternative-data platform - single-container image. +# Serves: built Vue SPA (frontend/dist) via nginx, proxying /api to the +# Flask backend (127.0.0.1:5000). Data persists under /app/backend/data +# (mount a volume there or set DATA_DIR to a mounted path). +# +# Build strategy: PREBUILT frontend dist (no node/npm/vite in this image) — +# build with `cd frontend && npm run build` and commit frontend/dist/. +FROM python:3.11-slim + +# nginx for serving the SPA +RUN apt-get update && apt-get install -y --no-install-recommends nginx \ + && rm -rf /var/lib/apt/lists/* \ + && rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf 2>/dev/null || true + +WORKDIR /app + +# 1) frontend static (prebuilt) — must exist on-disk (committed) +COPY frontend/dist/ ./frontend/dist/ + +# 2) backend deps + code +COPY backend/requirements.txt ./backend/requirements.txt +RUN pip install --no-cache-dir -r backend/requirements.txt +COPY backend/ ./backend/ + +# 3) deploy config (nginx conf + entrypoint) +COPY deploy/nginx.conf /etc/nginx/conf.d/set50.conf +COPY deploy/entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +# persistent data (factor vintages, dividend ledger, forward runs, prices) +ENV DATA_DIR=/app/backend/data +ENV HOST=0.0.0.0 +ENV PORT=5000 +VOLUME ["/app/backend/data"] + +EXPOSE 80 +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1/api/v1/dashboard/summary', timeout=4).status==200 else 1)" + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh new file mode 100644 index 0000000..762773d --- /dev/null +++ b/deploy/entrypoint.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env sh +set -e + +# Start the Flask backend on 0.0.0.0:5000 (bind all interfaces so nginx can +# proxy to it inside the container). DATA_DIR is /app/backend/data by default +# (a mounted volume makes it survive container recreate). +cd /app/backend +export HOST="${HOST:-0.0.0.0}" +export PORT="${PORT:-5000}" +export PAPER_BIND_HOST="$HOST" + +# pid1 helper: run nginx in foreground + Flask subprocess so the container +# stays alive and signals are handled. Keep it simple and robust. + +# Start Flask in the background +python run.py & +FLASK_PID=$! + +# Start nginx in the foreground (its own master + workers) +nginx -g "daemon off;" & +NGINX_PID=$! + +# forward signals to both and wait +trap 'kill $FLASK_PID $NGINX_PID 2>/dev/null || true' INT TERM +wait $FLASK_PID +wait $NGINX_PID diff --git a/deploy/nginx.conf b/deploy/nginx.conf new file mode 100644 index 0000000..cb2e151 --- /dev/null +++ b/deploy/nginx.conf @@ -0,0 +1,29 @@ +# nginx: serve the built Vue SPA + reverse-proxy /api to the Flask backend. +server { + listen 80; + server_name _; + + root /app/frontend/dist; + index index.html; + + # SPA fallback: any non-API GET that isn't a real file -> index.html + location / { + try_files $uri $uri/ /index.html; + } + + # API traffic goes to the Flask backend on 127.0.0.1:5000 + location /api/ { + proxy_pass http://127.0.0.1:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 120s; + } + + # never serve dotfiles + location ~ /\. { deny all; } + + gzip on; + gzip_types text/css application/javascript application/json; +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..30829b3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +# Local/self-hosted single-container run for the SET50 alternative-data platform. +# Production (EasyPanel) builds from the Dockerfile directly; this compose file +# adds a persistent volume so factor vintages, the dividend ledger, forward runs +# and prices survive container recreate. +services: + set50: + build: . + image: set50-alternative-data:latest + ports: + - "8080:80" + environment: + # bind backend on all interfaces inside the container (nginx proxies /api) + HOST: "0.0.0.0" + PORT: "5000" + PAPER_BIND_HOST: "0.0.0.0" + # optional: make the dividend refresh faster for demos () + # DIVIDEND_REFRESH_COOLDOWN_SECONDS: "300" + volumes: + - ./backend/data:/app/backend/data + restart: unless-stopped + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1/api/v1/dashboard/summary', timeout=4).status==200 else 1)"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s diff --git a/frontend/dist/assets/index-DDItjwYy.js b/frontend/dist/assets/index-DDItjwYy.js new file mode 100644 index 0000000..7719abe --- /dev/null +++ b/frontend/dist/assets/index-DDItjwYy.js @@ -0,0 +1,18 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))n(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function s(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function n(l){if(l.ep)return;l.ep=!0;const i=s(l);fetch(l.href,i)}})();/** +* @vue/shared v3.5.41 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function bn(e){const t=Object.create(null);for(const s of e.split(","))t[s]=1;return s=>s in t}const Q={},At=[],ze=()=>{},yl=()=>!1,Ns=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Ls=e=>e.startsWith("onUpdate:"),be=Object.assign,yn=(e,t)=>{const s=e.indexOf(t);s>-1&&e.splice(s,1)},Ai=Object.prototype.hasOwnProperty,J=(e,t)=>Ai.call(e,t),L=Array.isArray,Mt=e=>us(e)==="[object Map]",Lt=e=>us(e)==="[object Set]",Hn=e=>us(e)==="[object Date]",V=e=>typeof e=="function",re=e=>typeof e=="string",Ge=e=>typeof e=="symbol",Z=e=>e!==null&&typeof e=="object",xl=e=>(Z(e)||V(e))&&V(e.then)&&V(e.catch),wl=Object.prototype.toString,us=e=>wl.call(e),Mi=e=>us(e).slice(8,-1),Sl=e=>us(e)==="[object Object]",xn=e=>re(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Yt=bn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),js=e=>{const t=Object.create(null);return(s=>t[s]||(t[s]=e(s)))},Ri=/-\w/g,Ie=js(e=>e.replace(Ri,t=>t.slice(1).toUpperCase())),Ii=/\B([A-Z])/g,Et=js(e=>e.replace(Ii,"-$1").toLowerCase()),Cl=js(e=>e.charAt(0).toUpperCase()+e.slice(1)),Ys=js(e=>e?`on${Cl(e)}`:""),We=(e,t)=>!Object.is(e,t),Ts=(e,...t)=>{for(let s=0;s{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:n,value:s})},Vs=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let Bn;const $s=()=>Bn||(Bn=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function ss(e){if(L(e)){const t={};for(let s=0;s{if(s){const n=s.split(Di);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function ee(e){let t="";if(re(e))t=e;else if(L(e))for(let s=0;sjt(s,t))}const Ol=e=>!!(e&&e.__v_isRef===!0),_=e=>re(e)?e:e==null?"":L(e)||Z(e)&&(e.toString===wl||!V(e.toString))?Ol(e)?_(e.value):JSON.stringify(e,kl,2):String(e),kl=(e,t)=>Ol(t)?kl(e,t.value):Mt(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((s,[n,l],i)=>(s[Xs(n,i)+" =>"]=l,s),{})}:Lt(t)?{[`Set(${t.size})`]:[...t.values()].map(s=>Xs(s))}:Ge(t)?Xs(t):Z(t)&&!L(t)&&!Sl(t)?String(t):t,Xs=(e,t="")=>{var s;return Ge(e)?`Symbol(${(s=e.description)!=null?s:t})`:e};/** +* @vue/reactivity v3.5.41 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let he;class Hi{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&he&&(he.active?(this.parent=he,this.index=(he.scopes||(he.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,s;if(this.scopes){const n=this.scopes.slice();for(t=0,s=n.length;t0&&--this._on===0){if(he===this)he=this.prevScope;else{let t=he;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let s,n;for(s=0,n=this.effects.length;s0)return;if(Zt){let t=Zt;for(Zt=void 0;t;){const s=t.next;t.next=void 0,t.flags&=-9,t=s}}let e;for(;Xt;){let t=Xt;for(Xt=void 0;t;){const s=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(n){e||(e=n)}t=s}}if(e)throw e}function Rl(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function Il(e){let t,s=e.depsTail,n=s;for(;n;){const l=n.prevDep;n.version===-1?(n===s&&(s=l),Tn(n),Ki(n)):t=n,n.dep.activeLink=n.prevActiveLink,n.prevActiveLink=void 0,n=l}e.deps=t,e.depsTail=s}function cn(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Fl(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Fl(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===ns)||(e.globalVersion=ns,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!cn(e))))return;e.flags|=2;const t=e.dep,s=te,n=Fe;te=e,Fe=!0;try{Rl(e);const l=e.fn(e._value);(t.version===0||We(l,e._value))&&(e.flags|=128,e._value=l,t.version++)}catch(l){throw t.version++,l}finally{te=s,Fe=n,Il(e),e.flags&=-3}}function Tn(e,t=!1){const{dep:s,prevSub:n,nextSub:l}=e;if(n&&(n.nextSub=l,e.prevSub=void 0),l&&(l.prevSub=n,e.nextSub=void 0),s.subs===e&&(s.subs=n,!n&&s.computed)){s.computed.flags&=-5;for(let i=s.computed.deps;i;i=i.nextDep)Tn(i,!0)}!t&&!--s.sc&&s.map&&s.map.delete(s.key)}function Ki(e){const{prevDep:t,nextDep:s}=e;t&&(t.nextDep=s,e.prevDep=void 0),s&&(s.prevDep=t,e.nextDep=void 0)}let Fe=!0;const Dl=[];function ct(){Dl.push(Fe),Fe=!1}function ut(){const e=Dl.pop();Fe=e===void 0?!0:e}function Kn(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const s=te;te=void 0;try{t()}finally{te=s}}}let ns=0;class Ui{constructor(t,s){this.sub=t,this.dep=s,this.version=s.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class En{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!te||!Fe||te===this.computed)return;let s=this.activeLink;if(s===void 0||s.sub!==te)s=this.activeLink=new Ui(te,this),te.deps?(s.prevDep=te.depsTail,te.depsTail.nextDep=s,te.depsTail=s):te.deps=te.depsTail=s,Nl(s);else if(s.version===-1&&(s.version=this.version,s.nextDep)){const n=s.nextDep;n.prevDep=s.prevDep,s.prevDep&&(s.prevDep.nextDep=n),s.prevDep=te.depsTail,s.nextDep=void 0,te.depsTail.nextDep=s,te.depsTail=s,te.deps===s&&(te.deps=n)}return s}trigger(t){this.version++,ns++,this.notify(t)}notify(t){Sn();try{for(let s=this.subs;s;s=s.prevSub)s.sub.notify()&&s.sub.dep.notify()}finally{Cn()}}}function Nl(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let n=t.deps;n;n=n.nextDep)Nl(n)}const s=e.dep.subs;s!==e&&(e.prevSub=s,s&&(s.nextSub=e)),e.dep.subs=e}}const un=new WeakMap,St=Symbol(""),fn=Symbol(""),ls=Symbol("");function me(e,t,s){if(Fe&&te){let n=un.get(e);n||un.set(e,n=new Map);let l=n.get(s);l||(n.set(s,l=new En),l.map=n,l.key=s),l.track()}}function rt(e,t,s,n,l,i){const o=un.get(e);if(!o){ns++;return}const a=u=>{u&&u.trigger()};if(Sn(),t==="clear")o.forEach(a);else{const u=L(e),h=u&&xn(s);if(u&&s==="length"){const p=Number(n);o.forEach((x,A)=>{(A==="length"||A===ls||!Ge(A)&&A>=p)&&a(x)})}else switch((s!==void 0||o.has(void 0))&&a(o.get(s)),h&&a(o.get(ls)),t){case"add":u?h&&a(o.get("length")):(a(o.get(St)),Mt(e)&&a(o.get(fn)));break;case"delete":u||(a(o.get(St)),Mt(e)&&a(o.get(fn)));break;case"set":Mt(e)&&a(o.get(St));break}}Cn()}function kt(e){const t=z(e);return t===e?t:(me(t,"iterate",ls),Re(e)?t:t.map(De))}function Hs(e){return me(e=z(e),"iterate",ls),e}function Ke(e,t){return ft(e)?Ft(Ct(e)?De(t):t):De(t)}const Wi={__proto__:null,[Symbol.iterator](){return Qs(this,Symbol.iterator,e=>Ke(this,e))},concat(...e){return kt(this).concat(...e.map(t=>L(t)?kt(t):t))},entries(){return Qs(this,"entries",e=>(e[1]=Ke(this,e[1]),e))},every(e,t){return lt(this,"every",e,t,void 0,arguments)},filter(e,t){return lt(this,"filter",e,t,s=>s.map(n=>Ke(this,n)),arguments)},find(e,t){return lt(this,"find",e,t,s=>Ke(this,s),arguments)},findIndex(e,t){return lt(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return lt(this,"findLast",e,t,s=>Ke(this,s),arguments)},findLastIndex(e,t){return lt(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return lt(this,"forEach",e,t,void 0,arguments)},includes(...e){return en(this,"includes",e)},indexOf(...e){return en(this,"indexOf",e)},join(e){return kt(this).join(e)},lastIndexOf(...e){return en(this,"lastIndexOf",e)},map(e,t){return lt(this,"map",e,t,void 0,arguments)},pop(){return qt(this,"pop")},push(...e){return qt(this,"push",e)},reduce(e,...t){return Un(this,"reduce",e,t)},reduceRight(e,...t){return Un(this,"reduceRight",e,t)},shift(){return qt(this,"shift")},some(e,t){return lt(this,"some",e,t,void 0,arguments)},splice(...e){return qt(this,"splice",e)},toReversed(){return kt(this).toReversed()},toSorted(e){return kt(this).toSorted(e)},toSpliced(...e){return kt(this).toSpliced(...e)},unshift(...e){return qt(this,"unshift",e)},values(){return Qs(this,"values",e=>Ke(this,e))}};function Qs(e,t,s){const n=Hs(e),l=n[t]();return n!==e&&!Re(e)&&(l._next=l.next,l.next=()=>{const i=l._next();return i.done||(i.value=s(i.value)),i}),l}const qi=Array.prototype;function lt(e,t,s,n,l,i){const o=Hs(e),a=o!==e&&!Re(e),u=o[t];if(u!==qi[t]){const x=u.apply(e,i);return a?De(x):x}let h=s;o!==e&&(a?h=function(x,A){return s.call(this,Ke(e,x),A,e)}:s.length>2&&(h=function(x,A){return s.call(this,x,A,e)}));const p=u.call(o,h,n);return a&&l?l(p):p}function Un(e,t,s,n){const l=Hs(e),i=l!==e&&!Re(e);let o=s,a=!1;l!==e&&(i?(a=n.length===0,o=function(h,p,x){return a&&(a=!1,h=Ke(e,h)),s.call(this,h,Ke(e,p),x,e)}):s.length>3&&(o=function(h,p,x){return s.call(this,h,p,x,e)}));const u=l[t](o,...n);return a?Ke(e,u):u}function en(e,t,s){const n=z(e);me(n,"iterate",ls);const l=n[t](...s);return(l===-1||l===!1)&&An(s[0])?(s[0]=z(s[0]),n[t](...s)):l}function qt(e,t,s=[]){ct(),Sn();const n=z(e)[t].apply(e,s);return Cn(),ut(),n}const zi=bn("__proto__,__v_isRef,__isVue"),Ll=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ge));function Ji(e){Ge(e)||(e=String(e));const t=z(this);return me(t,"has",e),t.hasOwnProperty(e)}class jl{constructor(t=!1,s=!1){this._isReadonly=t,this._isShallow=s}get(t,s,n){if(s==="__v_skip")return t.__v_skip;const l=this._isReadonly,i=this._isShallow;if(s==="__v_isReactive")return!l;if(s==="__v_isReadonly")return l;if(s==="__v_isShallow")return i;if(s==="__v_raw")return n===(l?i?lo:Bl:i?Hl:$l).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(n)?t:void 0;const o=L(t);if(!l){let u;if(o&&(u=Wi[s]))return u;if(s==="hasOwnProperty")return Ji}const a=Reflect.get(t,s,_e(t)?t:n);if((Ge(s)?Ll.has(s):zi(s))||(l||me(t,"get",s),i))return a;if(_e(a)){const u=o&&xn(s)?a:a.value;return l&&Z(u)?pn(u):u}return Z(a)?l?pn(a):kn(a):a}}class Vl extends jl{constructor(t=!1){super(!1,t)}set(t,s,n,l){let i=t[s];const o=L(t)&&xn(s);if(!this._isShallow){const h=ft(i);if(!Re(n)&&!ft(n)&&(i=z(i),n=z(n)),!o&&_e(i)&&!_e(n))return h||(i.value=n),!0}const a=o?Number(s)e,ys=e=>Reflect.getPrototypeOf(e);function Qi(e,t,s){return function(...n){const l=this.__v_raw,i=z(l),o=Mt(i),a=e==="entries"||e===Symbol.iterator&&o,u=e==="keys"&&o,h=l[e](...n),p=s?dn:t?Ft:De;return!t&&me(i,"iterate",u?fn:St),be(Object.create(h),{next(){const{value:x,done:A}=h.next();return A?{value:x,done:A}:{value:a?[p(x[0]),p(x[1])]:p(x),done:A}}})}}function xs(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function eo(e,t){const s={get(l){const i=this.__v_raw,o=z(i),a=z(l);e||(We(l,a)&&me(o,"get",l),me(o,"get",a));const{has:u}=ys(o),h=t?dn:e?Ft:De;if(u.call(o,l))return h(i.get(l));if(u.call(o,a))return h(i.get(a));i!==o&&i.get(l)},get size(){const l=this.__v_raw;return!e&&me(z(l),"iterate",St),l.size},has(l){const i=this.__v_raw,o=z(i),a=z(l);return e||(We(l,a)&&me(o,"has",l),me(o,"has",a)),l===a?i.has(l):i.has(l)||i.has(a)},forEach(l,i){const o=this,a=o.__v_raw,u=z(a),h=t?dn:e?Ft:De;return!e&&me(u,"iterate",St),a.forEach((p,x)=>l.call(i,h(p),h(x),o))}};return be(s,e?{add:xs("add"),set:xs("set"),delete:xs("delete"),clear:xs("clear")}:{add(l){const i=z(this),o=ys(i),a=z(l),u=!t&&!Re(l)&&!ft(l)?a:l;return o.has.call(i,u)||We(l,u)&&o.has.call(i,l)||We(a,u)&&o.has.call(i,a)||(i.add(u),rt(i,"add",u,u)),this},set(l,i){!t&&!Re(i)&&!ft(i)&&(i=z(i));const o=z(this),{has:a,get:u}=ys(o);let h=a.call(o,l);h||(l=z(l),h=a.call(o,l));const p=u.call(o,l);return o.set(l,i),h?We(i,p)&&rt(o,"set",l,i):rt(o,"add",l,i),this},delete(l){const i=z(this),{has:o,get:a}=ys(i);let u=o.call(i,l);u||(l=z(l),u=o.call(i,l)),a&&a.call(i,l);const h=i.delete(l);return u&&rt(i,"delete",l,void 0),h},clear(){const l=z(this),i=l.size!==0,o=l.clear();return i&&rt(l,"clear",void 0,void 0),o}}),["keys","values","entries",Symbol.iterator].forEach(l=>{s[l]=Qi(l,e,t)}),s}function On(e,t){const s=eo(e,t);return(n,l,i)=>l==="__v_isReactive"?!e:l==="__v_isReadonly"?e:l==="__v_raw"?n:Reflect.get(J(s,l)&&l in n?s:n,l,i)}const to={get:On(!1,!1)},so={get:On(!1,!0)},no={get:On(!0,!1)};const $l=new WeakMap,Hl=new WeakMap,Bl=new WeakMap,lo=new WeakMap;function io(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function kn(e){return ft(e)?e:Pn(e,!1,Yi,to,$l)}function oo(e){return Pn(e,!1,Zi,so,Hl)}function pn(e){return Pn(e,!0,Xi,no,Bl)}function Pn(e,t,s,n,l){if(!Z(e)||e.__v_raw&&!(t&&e.__v_isReactive)||e.__v_skip||!Object.isExtensible(e))return e;const i=l.get(e);if(i)return i;const o=io(Mi(e));if(o===0)return e;const a=new Proxy(e,o===2?n:s);return l.set(e,a),a}function Ct(e){return ft(e)?Ct(e.__v_raw):!!(e&&e.__v_isReactive)}function ft(e){return!!(e&&e.__v_isReadonly)}function Re(e){return!!(e&&e.__v_isShallow)}function An(e){return e?!!e.__v_raw:!1}function z(e){const t=e&&e.__v_raw;return t?z(t):e}function ro(e){return!J(e,"__v_skip")&&Object.isExtensible(e)&&Tl(e,"__v_skip",!0),e}const De=e=>Z(e)?kn(e):e,Ft=e=>Z(e)?pn(e):e;function _e(e){return e?e.__v_isRef===!0:!1}function B(e){return ao(e,!1)}function ao(e,t){return _e(e)?e:new co(e,t)}class co{constructor(t,s){this.dep=new En,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=s?t:z(t),this._value=s?t:De(t),this.__v_isShallow=s}get value(){return this.dep.track(),this._value}set value(t){const s=this._rawValue,n=this.__v_isShallow||Re(t)||ft(t);t=n?t:z(t),We(t,s)&&(this._rawValue=t,this._value=n?t:De(t),this.dep.trigger())}}function uo(e){return _e(e)?e.value:e}const fo={get:(e,t,s)=>t==="__v_raw"?e:uo(Reflect.get(e,t,s)),set:(e,t,s,n)=>{const l=e[t];return _e(l)&&!_e(s)?(l.value=s,!0):Reflect.set(e,t,s,n)}};function Kl(e){return Ct(e)?e:new Proxy(e,fo)}class po{constructor(t,s,n){this.fn=t,this.setter=s,this._value=void 0,this.dep=new En(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=ns-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!s,this.isSSR=n}notify(){if(this.flags|=16,!(this.flags&8)&&te!==this)return Ml(this,!0),!0}get value(){const t=this.dep.track();return Fl(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function ho(e,t,s=!1){let n,l;return V(e)?n=e:(n=e.get,l=e.set),new po(n,l,s)}const ws={},Ps=new WeakMap;let wt;function go(e,t=!1,s=wt){if(s){let n=Ps.get(s);n||Ps.set(s,n=[]),n.push(e)}}function vo(e,t,s=Q){const{immediate:n,deep:l,once:i,scheduler:o,augmentJob:a,call:u}=s,h=R=>l?R:Re(R)||l===!1||l===0?at(R,1):at(R);let p,x,A,I,U=!1,N=!1;if(_e(e)?(x=()=>e.value,U=Re(e)):Ct(e)?(x=()=>h(e),U=!0):L(e)?(N=!0,U=e.some(R=>Ct(R)||Re(R)),x=()=>e.map(R=>{if(_e(R))return R.value;if(Ct(R))return h(R);if(V(R))return u?u(R,2):R()})):V(e)?t?x=u?()=>u(e,2):e:x=()=>{if(A){ct();try{A()}finally{ut()}}const R=wt;wt=p;try{return u?u(e,3,[I]):e(I)}finally{wt=R}}:x=ze,t&&l){const R=x,le=l===!0?1/0:l;x=()=>at(R(),le)}const j=Bi(),G=()=>{p.stop(),j&&j.active&&yn(j.effects,p)};if(i&&t){const R=t;t=(...le)=>{const se=R(...le);return G(),se}}let $=N?new Array(e.length).fill(ws):ws;const K=R=>{if(!(!(p.flags&1)||!p.dirty&&!R))if(t){const le=p.run();if(R||l||U||(N?le.some((se,ge)=>We(se,$[ge])):We(le,$))){A&&A();const se=wt;wt=p;try{const ge=[le,$===ws?void 0:N&&$[0]===ws?[]:$,I];$=le,u?u(t,3,ge):t(...ge)}finally{wt=se}}}else p.run()};return a&&a(K),p=new Pl(x),p.scheduler=o?()=>o(K,!1):K,I=R=>go(R,!1,p),A=p.onStop=()=>{const R=Ps.get(p);if(R){if(u)u(R,4);else for(const le of R)le();Ps.delete(p)}},t?n?K(!0):$=p.run():o?o(K.bind(null,!0),!0):p.run(),G.pause=p.pause.bind(p),G.resume=p.resume.bind(p),G.stop=G,G}function at(e,t=1/0,s){if(t<=0||!Z(e)||e.__v_skip||(s=s||new Map,(s.get(e)||0)>=t))return e;if(s.set(e,t),t--,_e(e))at(e.value,t,s);else if(L(e))for(let n=0;n{at(n,t,s)});else if(Sl(e)){for(const n in e)at(e[n],t,s);for(const n of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,n)&&at(e[n],t,s)}return e}/** +* @vue/runtime-core v3.5.41 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/function fs(e,t,s,n){try{return n?e(...n):e()}catch(l){Bs(l,t,s)}}function Ne(e,t,s,n){if(V(e)){const l=fs(e,t,s,n);return l&&xl(l)&&l.catch(i=>{Bs(i,t,s)}),l}if(L(e)){const l=[];for(let i=0;i>>1,l=xe[n],i=is(l);i=is(s)?xe.push(e):xe.splice(_o(t),0,e),e.flags|=1,ql()}}function ql(){As||(As=Ul.then(Jl))}function bo(e){if(!L(e))gt&&e.id===-1?gt.splice(Pt+1,0,e):e.flags&1||(Rt.push(e),e.flags|=1);else for(let t=0;tis(s)-is(n));if(Rt.length=0,gt){for(let s=0;se.id==null?e.flags&2?-1:1/0:e.id;function Jl(e){try{for(Be=0;Be{n._d&&sl(-1);const i=Ms(t),o=Tt.length;let a;try{a=e(...l)}finally{for(let u=Tt.length;u>o;u--)yi();Ms(i),n._d&&sl(1)}return a};return n._n=!0,n._c=!0,n._d=!0,n}function bt(e,t){if(Me===null)return e;const s=zs(Me),n=e.dirs||(e.dirs=[]);for(let l=0;l1)return s&&V(t)?t.call(n&&n.proxy):t}}const wo=Symbol.for("v-scx"),So=()=>Es(wo);function tn(e,t,s){return Yl(e,t,s)}function Yl(e,t,s=Q){const{immediate:n,deep:l,flush:i,once:o}=s,a=be({},s),u=t&&n||!t&&i!=="post";let h;if(as){if(i==="sync"){const I=So();h=I.__watcherHandles||(I.__watcherHandles=[])}else if(!u){const I=()=>{};return I.stop=ze,I.resume=ze,I.pause=ze,I}}const p=we;a.call=(I,U,N)=>Ne(I,p,U,N);let x=!1;i==="post"?a.scheduler=I=>{Te(I,p&&p.suspense)}:i!=="sync"&&(x=!0,a.scheduler=(I,U)=>{U?I():Mn(I)}),a.augmentJob=I=>{t&&(I.flags|=4),x&&(I.flags|=2,p&&(I.id=p.uid,I.i=p))};const A=vo(e,t,a);return as&&(h?h.push(A):u&&A()),A}function Co(e,t,s){const n=this.proxy,l=re(e)?e.includes(".")?Xl(n,e):()=>n[e]:e.bind(n,n);let i;V(t)?i=t:(i=t.handler,s=t);const o=ds(this),a=Yl(l,i.bind(n),s);return o(),a}function Xl(e,t){const s=t.split(".");return()=>{let n=e;for(let l=0;le.__isTeleport,sn=Symbol("_leaveCb");function Eo(e){let t=e[0];if(e.length>1){for(const s of e)if(s.type!==dt){t=s;break}}return t}function Zl(e){if(!In(e))return Ks(e.type)&&e.children?Eo(e.children):e;if(e.component)return e.component.subTree;const{shapeFlag:t,children:s}=e;if(s){if(t&16)return s[0];if(t&32&&V(s.default))return s.default()}}function Rn(e,t){if(e.shapeFlag&6&&e.component){e.transition=t;const s=e.component.subTree;Rn(Ks(s.type)&&Zl(s)||s,t)}else e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function Ql(e){e.ids=[e.ids[0]+e.ids[2]+++"-",0,0]}function qn(e,t){let s;return!!((s=Object.getOwnPropertyDescriptor(e,t))&&!s.configurable)}const Rs=new WeakMap;function Qt(e,t,s,n,l=!1){if(L(e)){e.forEach((N,j)=>Qt(N,t&&(L(t)?t[j]:t),s,n,l));return}if(es(n)&&!l){n.shapeFlag&512&&n.type.__asyncResolved&&n.component.subTree.component&&Qt(e,t,s,n.component.subTree);return}const i=n.shapeFlag&4?zs(n.component):n.el,o=l?null:i,{i:a,r:u}=e,h=t&&t.r,p=a.refs===Q?a.refs={}:a.refs,x=a.setupState,A=z(x),I=x===Q?yl:N=>qn(p,N)?!1:J(A,N),U=(N,j)=>!(j&&qn(p,j));if(h!=null&&h!==u){if(zn(t),re(h))p[h]=null,I(h)&&(x[h]=null);else if(_e(h)){const N=t;U(h,N.k)&&(h.value=null),N.k&&(p[N.k]=null)}}if(V(u))fs(u,a,12,[o,p]);else{const N=re(u),j=_e(u);if(N||j){const G=()=>{if(e.f){const $=N?I(u)?x[u]:p[u]:U()||!e.k?u.value:p[e.k];if(l)L($)&&yn($,i);else if(L($))$.includes(i)||$.push(i);else if(N)p[u]=[i],I(u)&&(x[u]=p[u]);else{const K=[i];U(u,e.k)&&(u.value=K),e.k&&(p[e.k]=K)}}else N?(p[u]=o,I(u)&&(x[u]=o)):j&&(U(u,e.k)&&(u.value=o),e.k&&(p[e.k]=o))};if(o){const $=()=>{G(),Rs.delete(e)};$.id=-1,Rs.set(e,$),Te($,s)}else zn(e),G()}}}function zn(e){const t=Rs.get(e);t&&(t.flags|=8,Rs.delete(e))}$s().requestIdleCallback;$s().cancelIdleCallback;const es=e=>!!e.type.__asyncLoader,In=e=>e.type.__isKeepAlive;function Oo(e,t){ei(e,"a",t)}function ko(e,t){ei(e,"da",t)}function ei(e,t,s=we){const n=e.__wdc||(e.__wdc=()=>{let l=s;for(;l;){if(l.isDeactivated)return;l=l.parent}return e()});if(Us(t,n,s),s){let l=s.parent;for(;l&&l.parent;)In(l.parent.vnode)&&Po(n,t,s,l),l=l.parent}}function Po(e,t,s,n){const l=Us(t,e,n,!0);si(()=>{yn(n[t],l)},s)}function Us(e,t,s=we,n=!1){if(s){const l=s[e]||(s[e]=[]),i=t.__weh||(t.__weh=(...o)=>{ct();const a=ds(s),u=Ne(t,s,e,o);return a(),ut(),u});return n?l.unshift(i):l.push(i),i}}const pt=e=>(t,s=we)=>{(!as||e==="sp")&&Us(e,(...n)=>t(...n),s)},Ao=pt("bm"),ti=pt("m"),Mo=pt("bu"),Ro=pt("u"),Io=pt("bum"),si=pt("um"),Fo=pt("sp"),Do=pt("rtg"),No=pt("rtc");function Lo(e,t=we){Us("ec",e,t)}const jo=Symbol.for("v-ndc");function Ae(e,t,s,n){let l;const i=s,o=L(e);if(o||re(e)){const a=o&&Ct(e);let u=!1,h=!1;a&&(u=!Re(e),h=ft(e),e=Hs(e)),l=new Array(e.length);for(let p=0,x=e.length;pt(a,u,void 0,i));else{const a=Object.keys(e);l=new Array(a.length);for(let u=0,h=a.length;ue?Ci(e)?zs(e):hn(e.parent):null,ts=be(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>hn(e.parent),$root:e=>hn(e.root),$host:e=>e.ce,$emit:e=>e.emit,$options:e=>li(e),$forceUpdate:e=>e.f||(e.f=()=>{Mn(e.update)}),$nextTick:e=>e.n||(e.n=Wl.bind(e.proxy)),$watch:e=>Co.bind(e)}),nn=(e,t)=>e!==Q&&!e.__isScriptSetup&&J(e,t),Vo={get({_:e},t){if(t==="__v_skip")return!0;const{ctx:s,setupState:n,data:l,props:i,accessCache:o,type:a,appContext:u}=e;if(t[0]!=="$"){const A=o[t];if(A!==void 0)switch(A){case 1:return n[t];case 2:return l[t];case 4:return s[t];case 3:return i[t]}else{if(nn(n,t))return o[t]=1,n[t];if(l!==Q&&J(l,t))return o[t]=2,l[t];if(J(i,t))return o[t]=3,i[t];if(s!==Q&&J(s,t))return o[t]=4,s[t];gn&&(o[t]=0)}}const h=ts[t];let p,x;if(h)return t==="$attrs"&&me(e.attrs,"get",""),h(e);if((p=a.__cssModules)&&(p=p[t]))return p;if(s!==Q&&J(s,t))return o[t]=4,s[t];if(x=u.config.globalProperties,J(x,t))return x[t]},set({_:e},t,s){const{data:n,setupState:l,ctx:i}=e;return nn(l,t)?(l[t]=s,!0):n!==Q&&J(n,t)?(n[t]=s,!0):J(e.props,t)||t[0]==="$"&&t.slice(1)in e?!1:(i[t]=s,!0)},has({_:{data:e,setupState:t,accessCache:s,ctx:n,appContext:l,props:i,type:o}},a){let u;return!!(s[a]||e!==Q&&a[0]!=="$"&&J(e,a)||nn(t,a)||J(i,a)||J(n,a)||J(ts,a)||J(l.config.globalProperties,a)||(u=o.__cssModules)&&u[a])},defineProperty(e,t,s){return s.get!=null?e._.accessCache[t]=0:J(s,"value")&&this.set(e,t,s.value,null),Reflect.defineProperty(e,t,s)}};function Jn(e){return L(e)?e.reduce((t,s)=>(t[s]=null,t),{}):e}let gn=!0;function $o(e){const t=li(e),s=e.proxy,n=e.ctx;gn=!1,t.beforeCreate&&Gn(t.beforeCreate,e,"bc");const{data:l,computed:i,methods:o,watch:a,provide:u,inject:h,created:p,beforeMount:x,mounted:A,beforeUpdate:I,updated:U,activated:N,deactivated:j,beforeDestroy:G,beforeUnmount:$,destroyed:K,unmounted:R,render:le,renderTracked:se,renderTriggered:ge,errorCaptured:Le,serverPrefetch:Ot,expose:Ye,inheritAttrs:Xe,components:Ze,directives:Qe,filters:Vt}=t;if(h&&Ho(h,n,null),o)for(const ne in o){const Y=o[ne];V(Y)&&(n[ne]=Y.bind(s))}if(l){const ne=l.call(s,s);Z(ne)&&(e.data=kn(ne))}if(gn=!0,i)for(const ne in i){const Y=i[ne],je=V(Y)?Y.bind(s,s):V(Y.get)?Y.get.bind(s,s):ze,mt=!V(Y)&&V(Y.set)?Y.set.bind(s):ze,Se=ae({get:je,set:mt});Object.defineProperty(n,ne,{enumerable:!0,configurable:!0,get:()=>Se.value,set:Ce=>Se.value=Ce})}if(a)for(const ne in a)ni(a[ne],n,s,ne);if(u){const ne=V(u)?u.call(s):u;Reflect.ownKeys(ne).forEach(Y=>{xo(Y,ne[Y])})}p&&Gn(p,e,"c");function fe(ne,Y){L(Y)?Y.forEach(je=>ne(je.bind(s))):Y&&ne(Y.bind(s))}if(fe(Ao,x),fe(ti,A),fe(Mo,I),fe(Ro,U),fe(Oo,N),fe(ko,j),fe(Lo,Le),fe(No,se),fe(Do,ge),fe(Io,$),fe(si,R),fe(Fo,Ot),L(Ye))if(Ye.length){const ne=e.exposed||(e.exposed={});Ye.forEach(Y=>{Object.defineProperty(ne,Y,{get:()=>s[Y],set:je=>s[Y]=je,enumerable:!0})})}else e.exposed||(e.exposed={});le&&e.render===ze&&(e.render=le),Xe!=null&&(e.inheritAttrs=Xe),Ze&&(e.components=Ze),Qe&&(e.directives=Qe),Ot&&Ql(e)}function Ho(e,t,s=ze){L(e)&&(e=vn(e));for(const n in e){const l=e[n];let i;Z(l)?"default"in l?i=Es(l.from||n,l.default,!0):i=Es(l.from||n):i=Es(l),_e(i)?Object.defineProperty(t,n,{enumerable:!0,configurable:!0,get:()=>i.value,set:o=>i.value=o}):t[n]=i}}function Gn(e,t,s){Ne(L(e)?e.map(n=>n.bind(t.proxy)):e.bind(t.proxy),t,s)}function ni(e,t,s,n){let l=n.includes(".")?Xl(s,n):()=>s[n];if(re(e)){const i=t[e];V(i)&&tn(l,i)}else if(V(e))tn(l,e.bind(s));else if(Z(e))if(L(e))e.forEach(i=>ni(i,t,s,n));else{const i=V(e.handler)?e.handler.bind(s):t[e.handler];V(i)&&tn(l,i,e)}}function li(e){const t=e.type,{mixins:s,extends:n}=t,{mixins:l,optionsCache:i,config:{optionMergeStrategies:o}}=e.appContext,a=i.get(t);let u;return a?u=a:!l.length&&!s&&!n?u=t:(u={},l.length&&l.forEach(h=>Is(u,h,o,!0)),Is(u,t,o)),Z(t)&&i.set(t,u),u}function Is(e,t,s,n=!1){const{mixins:l,extends:i}=t;i&&Is(e,i,s,!0),l&&l.forEach(o=>Is(e,o,s,!0));for(const o in t)if(!(n&&o==="expose")){const a=Bo[o]||s&&s[o];e[o]=a?a(e[o],t[o]):t[o]}return e}const Bo={data:Yn,props:Xn,emits:Xn,methods:Jt,computed:Jt,beforeCreate:ye,created:ye,beforeMount:ye,mounted:ye,beforeUpdate:ye,updated:ye,beforeDestroy:ye,beforeUnmount:ye,destroyed:ye,unmounted:ye,activated:ye,deactivated:ye,errorCaptured:ye,serverPrefetch:ye,components:Jt,directives:Jt,watch:Uo,provide:Yn,inject:Ko};function Yn(e,t){return t?e?function(){return be(V(e)?e.call(this,this):e,V(t)?t.call(this,this):t)}:t:e}function Ko(e,t){return Jt(vn(e),vn(t))}function vn(e){if(L(e)){const t={};for(let s=0;st==="modelValue"||t==="model-value"?e.modelModifiers:e[`${t}Modifiers`]||e[`${Ie(t)}Modifiers`]||e[`${Et(t)}Modifiers`];function Jo(e,t,...s){if(e.isUnmounted)return;const n=e.vnode.props||Q;let l=s;const i=t.startsWith("update:"),o=i&&zo(n,t.slice(7));o&&(o.trim&&(l=s.map(p=>re(p)?p.trim():p)),o.number&&(l=s.map(Vs)));let a,u=n[a=Ys(t)]||n[a=Ys(Ie(t))];!u&&i&&(u=n[a=Ys(Et(t))]),u&&Ne(u,e,6,l);const h=n[a+"Once"];if(h){if(!e.emitted)e.emitted={};else if(e.emitted[a])return;e.emitted[a]=!0,Ne(h,e,6,l)}}const Go=new WeakMap;function oi(e,t,s=!1){const n=s?Go:t.emitsCache,l=n.get(e);if(l!==void 0)return l;const i=e.emits;let o={},a=!1;if(!V(e)){const u=h=>{const p=oi(h,t,!0);p&&(a=!0,be(o,p))};!s&&t.mixins.length&&t.mixins.forEach(u),e.extends&&u(e.extends),e.mixins&&e.mixins.forEach(u)}return!i&&!a?(Z(e)&&n.set(e,null),null):(L(i)?i.forEach(u=>o[u]=null):be(o,i),Z(e)&&n.set(e,o),o)}function Ws(e,t){return!e||!Ns(t)?!1:(t=t.slice(2),t=t==="Once"?t:t.replace(/Once$/,""),J(e,t[0].toLowerCase()+t.slice(1))||J(e,Et(t))||J(e,t))}function Zn(e){const{type:t,vnode:s,proxy:n,withProxy:l,propsOptions:[i],slots:o,attrs:a,emit:u,render:h,renderCache:p,props:x,data:A,setupState:I,ctx:U,inheritAttrs:N}=e,j=Ms(e);let G,$;try{if(s.shapeFlag&4){const R=l||n,le=R;G=Ue(h.call(le,R,p,x,I,A,U)),$=a}else{const R=t;G=Ue(R.length>1?R(x,{attrs:a,slots:o,emit:u}):R(x,null)),$=t.props?a:Yo(a)}}catch(R){Tt.length=0,Bs(R,e,1),G=Je(dt)}let K=G;if($&&N!==!1){const R=Object.keys($),{shapeFlag:le}=K;R.length&&le&7&&(i&&R.some(Ls)&&($=Xo($,i)),K=Dt(K,$,!1,!0))}if(s.dirs&&(K=Dt(K,null,!1,!0),K.dirs=K.dirs?K.dirs.concat(s.dirs):s.dirs),s.transition){const R=Ks(K.type)&&Zl(K)||K;Rn(R,s.transition)}return G=K,Ms(j),G}const Yo=e=>{let t;for(const s in e)(s==="class"||s==="style"||Ns(s))&&((t||(t={}))[s]=e[s]);return t},Xo=(e,t)=>{const s={};for(const n in e)(!Ls(n)||!(n.slice(9)in t))&&(s[n]=e[n]);return s};function Zo(e,t,s){const{props:n,children:l,component:i}=e,{props:o,children:a,patchFlag:u}=t,h=i.emitsOptions;if(t.dirs||t.transition)return!0;if(s&&u>=0){if(u&1024)return!0;if(u&16)return n?Qn(n,o,h):!!o;if(u&8){const p=t.dynamicProps;for(let x=0;xObject.create(ai),ui=e=>Object.getPrototypeOf(e)===ai;function er(e,t,s,n=!1){const l={},i=ci();e.propsDefaults=Object.create(null),fi(e,t,l,i);for(const o in e.propsOptions[0])o in l||(l[o]=void 0);s?e.props=n?l:oo(l):e.type.props?e.props=l:e.props=i,e.attrs=i}function tr(e,t,s,n){const{props:l,attrs:i,vnode:{patchFlag:o}}=e,a=z(l),[u]=e.propsOptions;let h=!1;if((n||o>0)&&!(o&16)){if(o&8){const p=e.vnode.dynamicProps;for(let x=0;x{u=!0;const[A,I]=di(x,t,!0);be(o,A),I&&a.push(...I)};!s&&t.mixins.length&&t.mixins.forEach(p),e.extends&&p(e.extends),e.mixins&&e.mixins.forEach(p)}if(!i&&!u)return Z(e)&&n.set(e,At),At;if(L(i))for(let p=0;pe==="_"||e==="_ctx"||e==="$stable",Dn=e=>L(e)?e.map(Ue):[Ue(e)],nr=(e,t,s)=>{if(t._n)return t;const n=yo((...l)=>Dn(t(...l)),s);return n._c=!1,n},pi=(e,t,s)=>{const n=e._ctx;for(const l in e){if(Fn(l))continue;const i=e[l];if(V(i))t[l]=nr(l,i,n);else if(i!=null){const o=Dn(i);t[l]=()=>o}}},hi=(e,t)=>{const s=Dn(t);e.slots.default=()=>s},gi=(e,t,s)=>{for(const n in t)(s||!Fn(n))&&(e[n]=t[n])},lr=(e,t,s)=>{const n=e.slots=ci();if(e.vnode.shapeFlag&32){const l=t._;l?(gi(n,t,s),s&&Tl(n,"_",l,!0)):pi(t,n)}else t&&hi(e,t)},ir=(e,t,s)=>{const{vnode:n,slots:l}=e;let i=!0,o=Q;if(n.shapeFlag&32){const a=t._;a?s&&a===1?i=!1:gi(l,t,s):(i=!t.$stable,pi(t,l)),o=t}else t&&(hi(e,t),o={default:1});if(i)for(const a in l)!Fn(a)&&o[a]==null&&delete l[a]},Te=ur;function or(e){return rr(e)}function rr(e,t){const s=$s();s.__VUE__=!0;const{insert:n,remove:l,patchProp:i,createElement:o,createText:a,createComment:u,setText:h,setElementText:p,parentNode:x,nextSibling:A,setScopeId:I=ze,insertStaticContent:U}=e,N=(c,d,m,C=null,S=null,b=null,T=void 0,y=null,E=!!d.dynamicChildren)=>{if(c===d)return;c&&!zt(c,d)&&(C=et(c),Ce(c,S,b,!0),c=null),d.patchFlag===-2&&(E=!1,d.dynamicChildren=null);const{type:w,ref:F,shapeFlag:O}=d;switch(w){case qs:j(c,d,m,C);break;case dt:G(c,d,m,C);break;case Os:c==null&&$(d,m,C,T);break;case oe:Ze(c,d,m,C,S,b,T,y,E);break;default:O&1?le(c,d,m,C,S,b,T,y,E):O&6?Qe(c,d,m,C,S,b,T,y,E):(O&64||O&128)&&w.process(c,d,m,C,S,b,T,y,E,ht)}F!=null&&S?Qt(F,c&&c.ref,b,d||c,!d):F==null&&c&&c.ref!=null&&Qt(c.ref,null,b,c,!0)},j=(c,d,m,C)=>{if(c==null)n(d.el=a(d.children),m,C);else{const S=d.el=c.el;d.children!==c.children&&h(S,d.children)}},G=(c,d,m,C)=>{c==null?n(d.el=u(d.children||""),m,C):d.el=c.el},$=(c,d,m,C)=>{[c.el,c.anchor]=U(c.children,d,m,C,c.el,c.anchor)},K=({el:c,anchor:d},m,C)=>{let S;for(;c&&c!==d;)S=A(c),n(c,m,C),c=S;n(d,m,C)},R=({el:c,anchor:d})=>{let m;for(;c&&c!==d;)m=A(c),l(c),c=m;l(d)},le=(c,d,m,C,S,b,T,y,E)=>{if(d.type==="svg"?T="svg":d.type==="math"&&(T="mathml"),c==null)se(d,m,C,S,b,T,y,E);else{const w=c.el&&c.el._isVueCE?c.el:null;try{w&&w._beginPatch(),Ot(c,d,S,b,T,y,E)}finally{w&&w._endPatch()}}},se=(c,d,m,C,S,b,T,y)=>{let E,w;const{props:F,shapeFlag:O,transition:D,dirs:M}=c;if(E=c.el=o(c.type,b,F&&F.is,F),O&8?p(E,c.children):O&16&&Le(c.children,E,null,C,S,ln(c,b),T,y),M&&yt(c,null,C,"created"),ge(E,c,c.scopeId,T,C),F){for(const X in F)X!=="value"&&!Yt(X)&&i(E,X,null,F[X],b,C);"value"in F&&i(E,"value",null,F.value,b),(w=F.onVnodeBeforeMount)&&He(w,C,c)}M&&yt(c,null,C,"beforeMount");const H=ar(S,D);H&&D.beforeEnter(E),n(E,d,m),((w=F&&F.onVnodeMounted)||H||M)&&Te(()=>{try{w&&He(w,C,c),H&&D.enter(E),M&&yt(c,null,C,"mounted")}finally{}},S)},ge=(c,d,m,C,S)=>{if(m&&I(c,m),C)for(let b=0;b{for(let w=E;w{const y=d.el=c.el;let{patchFlag:E,dynamicChildren:w,dirs:F}=d;E|=c.patchFlag&16;const O=c.props||Q,D=d.props||Q;let M;if(m&&xt(m,!1),(M=D.onVnodeBeforeUpdate)&&He(M,m,d,c),F&&yt(d,c,m,"beforeUpdate"),m&&xt(m,!0),w&&(!c.dynamicChildren||c.dynamicChildren.length!==w.length)&&(E=0,T=!1,w=null),(O.innerHTML&&D.innerHTML==null||O.textContent&&D.textContent==null)&&p(y,""),w?Ye(c.dynamicChildren,w,y,m,C,ln(d,S),b):T||Y(c,d,y,null,m,C,ln(d,S),b,!1),E>0){if(E&16)Xe(y,O,D,m,S);else if(E&2&&O.class!==D.class&&i(y,"class",null,D.class,S),E&4&&i(y,"style",O.style,D.style,S),E&8){const H=d.dynamicProps;for(let X=0;X{M&&He(M,m,d,c),F&&yt(d,c,m,"updated")},C)},Ye=(c,d,m,C,S,b,T)=>{for(let y=0;y{if(d!==m){if(d!==Q)for(const b in d)!Yt(b)&&!(b in m)&&i(c,b,d[b],null,S,C);for(const b in m){if(Yt(b))continue;const T=m[b],y=d[b];T!==y&&b!=="value"&&i(c,b,y,T,S,C)}"value"in m&&i(c,"value",d.value,m.value,S)}},Ze=(c,d,m,C,S,b,T,y,E)=>{const w=d.el=c?c.el:a(""),F=d.anchor=c?c.anchor:a("");let{patchFlag:O,dynamicChildren:D,slotScopeIds:M}=d;M&&(y=y?y.concat(M):M),c==null?(n(w,m,C),n(F,m,C),Le(d.children||[],m,F,S,b,T,y,E)):O>0&&O&64&&D&&c.dynamicChildren&&c.dynamicChildren.length===D.length?(Ye(c.dynamicChildren,D,m,S,b,T,y),(d.key!=null||S&&d===S.subTree)&&vi(c,d,!0)):Y(c,d,m,F,S,b,T,y,E)},Qe=(c,d,m,C,S,b,T,y,E)=>{d.slotScopeIds=y,c==null?d.shapeFlag&512?S.ctx.activate(d,m,C,T,E):Vt(d,m,C,S,b,T,E):ps(c,d,E)},Vt=(c,d,m,C,S,b,T)=>{const y=c.component=_r(c,C,S);if(In(c)&&(y.ctx.renderer=ht),yr(y,!1,T),y.asyncDep){if(S&&S.registerDep(y,fe,T),!c.el){const E=y.subTree=Je(dt);G(null,E,d,m),c.placeholder=E.el}}else fe(y,c,d,m,S,b,T)},ps=(c,d,m)=>{const C=d.component=c.component;if(Zo(c,d,m))if(C.asyncDep&&!C.asyncResolved){ne(C,d,m);return}else C.next=d,C.update();else d.el=c.el,C.vnode=d},fe=(c,d,m,C,S,b,T)=>{const y=()=>{if(c.isMounted){let{next:O,bu:D,u:M,parent:H,vnode:X}=c;{const Oe=mi(c);if(Oe){O&&(O.el=X.el,ne(c,O,T)),Oe.asyncDep.then(()=>{Te(()=>{c.isUnmounted||w()},S)});return}}let W=O,ie;xt(c,!1),O?(O.el=X.el,ne(c,O,T)):O=X,D&&Ts(D),(ie=O.props&&O.props.onVnodeBeforeUpdate)&&He(ie,H,O,X),xt(c,!0);const ce=Zn(c),de=c.subTree;c.subTree=ce,N(de,ce,x(de.el),et(de),c,S,b),O.el=ce.el,W===null&&Qo(c,ce.el),M&&Te(M,S),(ie=O.props&&O.props.onVnodeUpdated)&&Te(()=>He(ie,H,O,X),S)}else{let O;const{el:D,props:M}=d,{bm:H,m:X,parent:W,root:ie,type:ce}=c,de=es(d);xt(c,!1),H&&Ts(H),!de&&(O=M&&M.onVnodeBeforeMount)&&He(O,W,d),xt(c,!0);{ie.ce&&ie.ce._hasShadowRoot()&&ie.ce._injectChildStyle(ce,c.parent?c.parent.type:void 0);const Oe=c.subTree=Zn(c);N(null,Oe,m,C,c,S,b),d.el=Oe.el}if(X&&Te(X,S),!de&&(O=M&&M.onVnodeMounted)){const Oe=d;Te(()=>He(O,W,Oe),S)}(d.shapeFlag&256||W&&es(W.vnode)&&W.vnode.shapeFlag&256)&&c.a&&Te(c.a,S),c.isMounted=!0,d=m=C=null}};c.scope.on();const E=c.effect=new Pl(y);c.scope.off();const w=c.update=E.run.bind(E),F=c.job=E.runIfDirty.bind(E);F.i=c,F.id=c.uid,E.scheduler=()=>Mn(F),xt(c,!0),w()},ne=(c,d,m)=>{d.component=c;const C=c.vnode.props;c.vnode=d,c.next=null,tr(c,d.props,C,m),ir(c,d.children,m),ct(),Wn(c),ut()},Y=(c,d,m,C,S,b,T,y,E=!1)=>{const w=c&&c.children,F=c?c.shapeFlag:0,O=d.children,{patchFlag:D,shapeFlag:M}=d;if(D>0){if(D&128){mt(w,O,m,C,S,b,T,y,E);return}else if(D&256){je(w,O,m,C,S,b,T,y,E);return}}M&8?(F&16&&Ve(w,S,b),O!==w&&p(m,O)):F&16?M&16?mt(w,O,m,C,S,b,T,y,E):Ve(w,S,b,!0):(F&8&&p(m,""),M&16&&Le(O,m,C,S,b,T,y,E))},je=(c,d,m,C,S,b,T,y,E)=>{c=c||At,d=d||At;const w=c.length,F=d.length,O=Math.min(w,F);let D;for(D=0;DF?Ve(c,S,b,!0,!1,O):Le(d,m,C,S,b,T,y,E,O)},mt=(c,d,m,C,S,b,T,y,E)=>{let w=0;const F=d.length;let O=c.length-1,D=F-1;for(;w<=O&&w<=D;){const M=c[w],H=d[w]=E?ot(d[w]):Ue(d[w]);if(zt(M,H))N(M,H,m,null,S,b,T,y,E);else break;w++}for(;w<=O&&w<=D;){const M=c[O],H=d[D]=E?ot(d[D]):Ue(d[D]);if(zt(M,H))N(M,H,m,null,S,b,T,y,E);else break;O--,D--}if(w>O){if(w<=D){const M=D+1,H=MD)for(;w<=O;)Ce(c[w],S,b,!0),w++;else{const M=w,H=w,X=new Map;for(w=H;w<=D;w++){const ue=d[w]=E?ot(d[w]):Ue(d[w]);ue.key!=null&&X.set(ue.key,w)}let W,ie=0;const ce=D-H+1;let de=!1,Oe=0;const tt=new Array(ce);for(w=0;w=ce){Ce(ue,S,b,!0);continue}let ke;if(ue.key!=null)ke=X.get(ue.key);else for(W=H;W<=D;W++)if(tt[W-H]===0&&zt(ue,d[W])){ke=W;break}ke===void 0?Ce(ue,S,b,!0):(tt[ke-H]=w+1,ke>=Oe?Oe=ke:de=!0,N(ue,d[ke],m,null,S,b,T,y,E),ie++)}const Ut=de?cr(tt):At;for(W=Ut.length-1,w=ce-1;w>=0;w--){const ue=H+w,ke=d[ue],gs=d[ue+1],vs=ue+1{const{el:b,type:T,transition:y,children:E,shapeFlag:w}=c;if(w&6){Se(c.component.subTree,d,m,C);return}if(w&128){c.suspense.move(d,m,C);return}if(w&64){T.move(c,d,m,ht);return}if(T===oe){n(b,d,m);for(let O=0;Oy.enter(b),S));else{const{leave:O,delayLeave:D,afterLeave:M}=y,H=()=>{c.ctx.isUnmounted?l(b):n(b,d,m)},X=()=>{const W=b._isLeaving||!!b[sn];b._isLeaving&&b[sn](!0),y.persisted&&!W?H():O(b,()=>{H(),M&&M()})};D?D(b,H,X):X()}else n(b,d,m)},Ce=(c,d,m,C=!1,S=!1)=>{const{type:b,props:T,ref:y,children:E,dynamicChildren:w,shapeFlag:F,patchFlag:O,dirs:D,cacheIndex:M,memo:H}=c;if(O===-2&&(S=!1),y!=null&&(ct(),Qt(y,null,m,c,!0),ut()),M!=null&&(d.renderCache[M]=void 0),F&256){d.ctx.deactivate(c);return}const X=F&1&&D,W=!es(c);let ie;if(W&&(ie=T&&T.onVnodeBeforeUnmount)&&He(ie,d,c),F&6)Js(c.component,m,C);else{if(F&128){c.suspense.unmount(m,C);return}X&&yt(c,null,d,"beforeUnmount"),F&64?c.type.remove(c,d,m,ht,C):w&&!w.hasOnce&&(b!==oe||O>0&&O&64)?Ve(w,d,m,!1,!0):(b===oe&&O&384||!S&&F&16)&&Ve(E,d,m),C&&$t(c)}const ce=H!=null&&M==null;(W&&(ie=T&&T.onVnodeUnmounted)||X||ce)&&Te(()=>{ie&&He(ie,d,c),X&&yt(c,null,d,"unmounted"),ce&&(c.el=null)},m)},$t=c=>{const{type:d,el:m,anchor:C,transition:S}=c;if(d===oe){Ht(m,C);return}if(d===Os){R(c);return}const b=()=>{l(m),S&&!S.persisted&&S.afterLeave&&S.afterLeave()};if(c.shapeFlag&1&&S&&!S.persisted){const{leave:T,delayLeave:y}=S,E=()=>T(m,b);y?y(c.el,b,E):E()}else b()},Ht=(c,d)=>{let m;for(;c!==d;)m=A(c),l(c),c=m;l(d)},Js=(c,d,m)=>{const{bum:C,scope:S,job:b,subTree:T,um:y,m:E,a:w}=c;tl(E),tl(w),C&&Ts(C),S.stop(),b&&(b.flags|=8,Ce(T,c,d,m)),y&&Te(y,d),Te(()=>{c.isUnmounted=!0},d)},Ve=(c,d,m,C=!1,S=!1,b=0)=>{for(let T=b;T{if(c.shapeFlag&6)return et(c.component.subTree);if(c.shapeFlag&128)return c.suspense.next();const d=A(c.anchor||c.el),m=d&&d[To];return m?A(m):d};let Bt=!1;const Kt=(c,d,m)=>{let C;c==null?d._vnode&&(Ce(d._vnode,null,null,!0),C=d._vnode.component):N(d._vnode||null,c,d,null,null,null,m),d._vnode=c,Bt||(Bt=!0,Wn(C),zl(),Bt=!1)},ht={p:N,um:Ce,m:Se,r:$t,mt:Vt,mc:Le,pc:Y,pbc:Ye,n:et,o:e};return{render:Kt,hydrate:void 0,createApp:qo(Kt)}}function ln({type:e,props:t},s){return s==="svg"&&e==="foreignObject"||s==="mathml"&&e==="annotation-xml"&&t&&t.encoding&&t.encoding.includes("html")?void 0:s}function xt({effect:e,job:t},s){s?(e.flags|=32,t.flags|=4):(e.flags&=-33,t.flags&=-5)}function ar(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function vi(e,t,s=!1){const n=e.children,l=t.children;if(L(n)&&L(l))for(let i=0;i>1,e[s[a]]0&&(t[n]=s[i-1]),s[i]=n)}}for(i=s.length,o=s[i-1];i-- >0;)s[i]=o,o=t[o];return s}function mi(e){const t=e.subTree.component;if(t)return t.asyncDep&&!t.asyncResolved?t:mi(t)}function tl(e){if(e)for(let t=0;te.__isSuspense;function ur(e,t){t&&t.pendingBranch?L(e)?t.effects.push(...e):t.effects.push(e):bo(e)}const oe=Symbol.for("v-fgt"),qs=Symbol.for("v-txt"),dt=Symbol.for("v-cmt"),Os=Symbol.for("v-stc"),Tt=[];let Ee=null;function k(e=!1){Tt.push(Ee=e?null:[])}function yi(){Tt.pop(),Ee=Tt[Tt.length-1]||null}let os=1;function sl(e,t=!1){os+=e,e<0&&Ee&&t&&(Ee.hasOnce=!0)}function xi(e){return e.dynamicChildren=os>0?Ee||At:null,yi(),os>0&&Ee&&Ee.push(e),e}function P(e,t,s,n,l,i){return xi(r(e,t,s,n,l,i,!0))}function fr(e,t,s,n,l){return xi(Je(e,t,s,n,l,!0))}function wi(e){return e?e.__v_isVNode===!0:!1}function zt(e,t){return e.type===t.type&&e.key===t.key}const Si=({key:e})=>e??null,ks=({ref:e,ref_key:t,ref_for:s})=>(typeof e=="number"&&(e=""+e),e!=null?re(e)||_e(e)||V(e)?{i:Me,r:e,k:t,f:!!s}:e:null);function r(e,t=null,s=null,n=0,l=null,i=e===oe?0:1,o=!1,a=!1){const u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&Si(t),ref:t&&ks(t),scopeId:Gl,slotScopeIds:null,children:s,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetStart:null,targetAnchor:null,staticCount:0,shapeFlag:i,patchFlag:n,dynamicProps:l,dynamicChildren:null,appContext:null,ctx:Me};return a?(Fs(u,s),i&128&&e.normalize(u)):s&&(u.shapeFlag|=re(s)?8:16),os>0&&!o&&Ee&&(u.patchFlag>0||i&6)&&u.patchFlag!==32&&Ee.push(u),u}const Je=dr;function dr(e,t=null,s=null,n=0,l=null,i=!1){if((!e||e===jo)&&(e=dt),wi(e)){const a=Dt(e,t,!0);return s&&Fs(a,s),os>0&&!i&&Ee&&(a.shapeFlag&6?Ee[Ee.indexOf(e)]=a:Ee.push(a)),a.patchFlag=-2,a}if(Cr(e)&&(e=e.__vccOpts),t){t=pr(t);let{class:a,style:u}=t;a&&!re(a)&&(t.class=ee(a)),Z(u)&&(An(u)&&!L(u)&&(u=be({},u)),t.style=ss(u))}const o=re(e)?1:bi(e)?128:Ks(e)?64:Z(e)?4:V(e)?2:0;return r(e,t,s,n,l,o,i,!0)}function pr(e){return e?An(e)||ui(e)?be({},e):e:null}function Dt(e,t,s=!1,n=!1){const{props:l,ref:i,patchFlag:o,children:a,transition:u}=e,h=t?gr(l||{},t):l,p={__v_isVNode:!0,__v_skip:!0,type:e.type,props:h,key:h&&Si(h),ref:t&&t.ref?s&&i?L(i)?i.concat(ks(t)):[i,ks(t)]:ks(t):i,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:a,target:e.target,targetStart:e.targetStart,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==oe?o===-1?16:o|16:o,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:u,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&Dt(e.ssContent),ssFallback:e.ssFallback&&Dt(e.ssFallback),placeholder:e.placeholder,el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce};return u&&n&&Rn(p,u.clone(p)),p}function q(e=" ",t=0){return Je(qs,null,e,t)}function hr(e,t){const s=Je(Os,null,e);return s.staticCount=t,s}function pe(e="",t=!1){return t?(k(),fr(dt,null,e)):Je(dt,null,e)}function Ue(e){return e==null||typeof e=="boolean"?Je(dt):L(e)?Je(oe,null,e.slice()):wi(e)?ot(e):Je(qs,null,String(e))}function ot(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:Dt(e)}function Fs(e,t){let s=0;const{shapeFlag:n}=e;if(t==null)t=null;else if(L(t))s=16;else if(typeof t=="object")if(n&65){const l=t.default;l&&(l._c&&(l._d=!1),Fs(e,l()),l._c&&(l._d=!0));return}else{s=32;const l=t._;!l&&!ui(t)?t._ctx=Me:l===3&&Me&&(Me.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else if(V(t)){if(n&65){Fs(e,{default:t});return}t={default:t,_ctx:Me},s=32}else t=String(t),n&64?(s=16,t=[q(t)]):s=8;e.children=t,e.shapeFlag|=s}function gr(...e){const t={};for(let s=0;swe||Me;let Ds,rs;{const e=$s(),t=(s,n)=>{let l;return(l=e[s])||(l=e[s]=[]),l.push(n),i=>{l.length>1?l.forEach(o=>o(i)):l[0](i)}};Ds=t("__VUE_INSTANCE_SETTERS__",s=>we=s),rs=t("__VUE_SSR_SETTERS__",s=>as=s)}const ds=e=>{const t=we;return Ds(e),e.scope.on(),()=>{e.scope.off(),Ds(t)}},nl=()=>{we&&we.scope.off(),Ds(null)};function Ci(e){return e.vnode.shapeFlag&4}let as=!1;function yr(e,t=!1,s=!1){t&&rs(t);const{props:n,children:l}=e.vnode,i=Ci(e);er(e,n,i,t),lr(e,l,s||t);const o=i?xr(e,t):void 0;return t&&rs(!1),o}function xr(e,t){const s=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,Vo);const{setup:n}=s;if(n){ct();const l=e.setupContext=n.length>1?Sr(e):null,i=ds(e),o=fs(n,e,0,[e.props,l]),a=xl(o);if(ut(),i(),(a||e.sp)&&!es(e)&&Ql(e),a){if(o.then(nl,nl),t)return o.then(u=>{rs(!0);try{ll(e,u,t)}finally{rs(!1)}}).catch(u=>{Bs(u,e,0)});e.asyncDep=o}else ll(e,o)}else Ti(e)}function ll(e,t,s){V(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Z(t)&&(e.setupState=Kl(t)),Ti(e)}function Ti(e,t,s){const n=e.type;e.render||(e.render=n.render||ze);{const l=ds(e);ct();try{$o(e)}finally{ut(),l()}}}const wr={get(e,t){return me(e,"get",""),e[t]}};function Sr(e){const t=s=>{e.exposed=s||{}};return{attrs:new Proxy(e.attrs,wr),slots:e.slots,emit:e.emit,expose:t}}function zs(e){return e.exposed?e.exposeProxy||(e.exposeProxy=new Proxy(Kl(ro(e.exposed)),{get(t,s){if(s in t)return t[s];if(s in ts)return ts[s](e)},has(t,s){return s in t||s in ts}})):e.proxy}function Cr(e){return V(e)&&"__vccOpts"in e}const ae=(e,t)=>ho(e,t,as),Tr="3.5.41";/** +* @vue/runtime-dom v3.5.41 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/let _n;const il=typeof window<"u"&&window.trustedTypes;if(il)try{_n=il.createPolicy("vue",{createHTML:e=>e})}catch{}const Ei=_n?e=>_n.createHTML(e):e=>e,Er="http://www.w3.org/2000/svg",Or="http://www.w3.org/1998/Math/MathML",it=typeof document<"u"?document:null,ol=it&&it.createElement("template"),kr={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const l=t==="svg"?it.createElementNS(Er,e):t==="mathml"?it.createElementNS(Or,e):s?it.createElement(e,{is:s}):it.createElement(e);return e==="select"&&n&&n.multiple!=null&&l.setAttribute("multiple",n.multiple),l},createText:e=>it.createTextNode(e),createComment:e=>it.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>it.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,l,i){const o=s?s.previousSibling:t.lastChild;if(l&&(l===i||l.nextSibling))for(;t.insertBefore(l.cloneNode(!0),s),!(l===i||!(l=l.nextSibling)););else{ol.innerHTML=Ei(n==="svg"?`${e}`:n==="mathml"?`${e}`:e);const a=ol.content;if(n==="svg"||n==="mathml"){const u=a.firstChild;for(;u.firstChild;)a.appendChild(u.firstChild);a.removeChild(u)}t.insertBefore(a,s)}return[o?o.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},Pr=Symbol("_vtc");function Ar(e,t,s){const n=e[Pr];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const rl=Symbol("_vod"),Mr=Symbol("_vsh"),Rr=Symbol(""),Ir=/(?:^|;)\s*display\s*:/;function Fr(e,t,s){const n=e.style,l=re(s);let i=!1;if(s&&!l){if(t)if(re(t))for(const o of t.split(";")){const a=o.slice(0,o.indexOf(":")).trim();s[a]==null&&Gt(n,a,"")}else for(const o in t)s[o]==null&&Gt(n,o,"");for(const o in s){o==="display"&&(i=!0);const a=s[o];a!=null?Nr(e,o,!re(t)&&t?t[o]:void 0,a)||Gt(n,o,a):Gt(n,o,"")}}else if(l){if(t!==s){const o=n[Rr];o&&(s+=";"+o),n.cssText=s,i=Ir.test(s)}}else t&&e.removeAttribute("style");rl in e&&(e[rl]=i?n.display:"",e[Mr]&&(n.display="none"))}const al=/\s*!important$/;function Gt(e,t,s){if(L(s))s.forEach(n=>Gt(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=Dr(e,t);al.test(s)?e.setProperty(Et(n),s.replace(al,""),"important"):e[n]=s}}const cl=["Webkit","Moz","ms"],on={};function Dr(e,t){const s=on[t];if(s)return s;let n=Ie(t);if(n!=="filter"&&n in e)return on[t]=n;n=Cl(n);for(let l=0;lrn||(Br.then(()=>rn=0),rn=Date.now());function Ur(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;const l=s.value;if(L(l)){const i=n.stopImmediatePropagation;n.stopImmediatePropagation=()=>{i.call(n),n._stopped=!0};const o=l.slice(),a=[n];for(let u=0;ue.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Wr=(e,t,s,n,l,i)=>{const o=l==="svg";t==="class"?Ar(e,n,o):t==="style"?Fr(e,s,n):Ns(t)?Ls(t)||jr(e,t,s,n,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):qr(e,t,n,o))?(dl(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&fl(e,t,n,o,i,t!=="value")):e._isVueCE&&(zr(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!re(n)))?dl(e,Ie(t),n,i,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._falseValue=n),fl(e,t,n,o))};function qr(e,t,s,n){if(n)return!!(t==="innerHTML"||t==="textContent"||t in e&&hl(t)&&V(s));if(t==="spellcheck"||t==="draggable"||t==="translate"||t==="autocorrect"||t==="sandbox"&&e.tagName==="IFRAME"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA")return!1;if(t==="width"||t==="height"){const l=e.tagName;if(l==="IMG"||l==="VIDEO"||l==="CANVAS"||l==="SOURCE")return!1}return hl(t)&&re(s)?!1:t in e}function zr(e,t){const s=e._def.props;if(!s)return!1;const n=Ie(t);return Array.isArray(s)?s.some(l=>Ie(l)===n):Object.keys(s).some(l=>Ie(l)===n)}const Nt=e=>{const t=e.props["onUpdate:modelValue"]||!1;return L(t)?s=>Ts(t,s):t};function Jr(e){e.target.composing=!0}function gl(e){const t=e.target;t.composing&&(t.composing=!1,t.dispatchEvent(new Event("input")))}const qe=Symbol("_assign"),Ss=Symbol("_initialValue");function an(e,t,s){return t&&(e=e.trim()),s&&(e=Vs(e)),e}const Cs={created(e,{modifiers:{lazy:t,trim:s,number:n}},l){e.parentNode&&(e.type==="text"?e[Ss]=e.defaultValue.replace(/[\r\n]/g,""):e.type==="textarea"&&(e[Ss]=e.defaultValue.replace(/\r\n?/g,` +`))),e[qe]=Nt(l);const i=n||l.props&&l.props.type==="number";vt(e,t?"change":"input",o=>{o.target.composing||e[qe](an(e.value,s,i))}),(s||i)&&vt(e,"change",()=>{e.value=an(e.value,s,i)}),t||(vt(e,"compositionstart",Jr),vt(e,"compositionend",gl),vt(e,"change",gl))},mounted(e,{value:t,modifiers:{trim:s,number:n}}){const l=t??"",i=e[Ss];delete e[Ss],i!==void 0&&(e.type==="text"||e.type==="textarea")&&e.value!==i?e[qe](an(e.value,s,n)):e.value=l},beforeUpdate(e,{value:t,oldValue:s,modifiers:{lazy:n,trim:l,number:i}},o){if(e[qe]=Nt(o),e.composing)return;const a=(i||e.type==="number")&&!/^0\d/.test(e.value)?Vs(e.value):e.value,u=t??"";if(a===u)return;const h=e.getRootNode();(h instanceof Document||h instanceof ShadowRoot)&&h.activeElement===e&&e.type!=="range"&&(n&&t===s||l&&e.value.trim()===u)||(e.value=u)}},Gr={deep:!0,created(e,t,s){e[qe]=Nt(s),vt(e,"change",()=>{const n=e._modelValue,l=cs(e),i=e.checked,o=e[qe];if(L(n)){const a=wn(n,l),u=a!==-1;if(i&&!u)o(n.concat(l));else if(!i&&u){const h=[...n];h.splice(a,1),o(h)}}else if(Lt(n)){const a=new Set(n);i?a.add(l):a.delete(l),o(a)}else o(Oi(e,i))})},mounted:vl,beforeUpdate(e,t,s){e[qe]=Nt(s),vl(e,t,s)}};function vl(e,{value:t,oldValue:s},n){e._modelValue=t;let l;if(L(t))l=wn(t,n.props.value)>-1;else if(Lt(t))l=t.has(n.props.value);else{if(t===s)return;l=jt(t,Oi(e,!0))}e.checked!==l&&(e.checked=l)}const ml={deep:!0,created(e,{value:t,modifiers:{number:s}},n){e._modelValue=t,vt(e,"change",()=>{const l=Array.prototype.filter.call(e.options,i=>i.selected).map(i=>s?Vs(cs(i)):cs(i));e[qe](e.multiple?Lt(e._modelValue)?new Set(l):l:l[0]),e._assigning=!0,Wl(()=>{e._assigning=!1})}),e[qe]=Nt(n)},mounted(e,{value:t}){_l(e,t)},beforeUpdate(e,{value:t},s){e._modelValue=t,e[qe]=Nt(s)},updated(e,{value:t}){e._assigning||_l(e,t)}};function _l(e,t){const s=e.multiple,n=L(t);if(!(s&&!n&&!Lt(t))){for(let l=0,i=e.options.length;lString(h)===String(a)):o.selected=wn(t,a)>-1}else o.selected=t.has(a);else if(jt(cs(o),t)){e.selectedIndex!==l&&(e.selectedIndex=l);return}}!s&&e.selectedIndex!==-1&&(e.selectedIndex=-1)}}function cs(e){return"_value"in e?e._value:e.value}function Oi(e,t){const s=t?"_trueValue":"_falseValue";return s in e?e[s]:t}const Yr=["ctrl","shift","alt","meta"],Xr={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Yr.some(s=>e[`${s}Key`]&&!t.includes(s))},Zr=(e,t)=>{if(!e)return e;const s=e._withMods||(e._withMods={}),n=t.join(".");return s[n]||(s[n]=((l,...i)=>{for(let o=0;o{const t=ea().createApp(...e),{mount:s}=t;return t.mount=n=>{const l=na(n);if(!l)return;const i=t._component;!V(i)&&!i.render&&!i.template&&(i.template=l.innerHTML),l.nodeType===1&&(l.textContent="");const o=s(l,!1,sa(l));return l instanceof Element&&(l.removeAttribute("v-cloak"),l.setAttribute("data-v-app","")),o},t});function sa(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function na(e){return re(e)?document.querySelector(e):e}const la={class:"app-shell"},ia={class:"content",id:"overview"},oa={class:"topbar"},ra={class:"topbar-meta"},aa={class:"as-of"},ca={key:0,class:"state-card"},ua={key:1,class:"state-card error-state"},fa={class:"kpi-grid","aria-label":"Signal summary"},da={class:"kpi-card accent-card"},pa={class:"kpi-value"},ha={class:"kpi-foot"},ga={class:"long-count"},va={class:"short-count"},ma={class:"neutral-count"},_a={class:"kpi-card"},ba={class:"kpi-value"},ya={class:"kpi-foot"},xa={class:"panel theme-panel",id:"themes"},wa={class:"panel-header signal-header"},Sa={class:"status-tag"},Ca={class:"theme-grid"},Ta={class:"theme-card-head"},Ea={class:"theme-chip"},Oa={class:"theme-label-th"},ka={class:"theme-surprise"},Pa={class:"theme-surprise-value"},Aa={class:"theme-read"},Ma={key:0,class:"theme-read-value"},Ra={key:1,class:"theme-read-value"},Ia={key:2,class:"theme-read-value"},Fa={key:3,class:"theme-read-value"},Da={key:0,class:"theme-narrative"},Na={key:0,class:"macro-panel"},La={class:"macro-chips"},ja={class:"macro-chip"},Va={class:"macro-chip"},$a={class:"macro-chip"},Ha={class:"macro-chip"},Ba={class:"macro-chip"},Ka={class:"panel stock-panel",id:"stocks"},Ua={class:"panel-header signal-header"},Wa={class:"stock-controls"},qa={class:"toggle-filter"},za={key:0,class:"empty-research"},Ja={key:1,class:"table-wrap"},Ga={class:"factor-table"},Ya=["onClick"],Xa={key:1,class:"muted-cell"},Za={class:"combined-cell"},Qa={class:"symbol-name"},ec={key:0,class:"muted-cell"},tc={class:"score-cell"},sc={key:0,class:"dividend-dot",title:"จ่ายปันผล"},nc={class:"panel lineage-panel",id:"lineage"},lc={class:"panel-header signal-header"},ic={class:"status-tag"},oc={class:"table-wrap"},rc={class:"source-table"},ac={class:"source-name"},cc={class:"muted-cell"},uc={class:"muted-cell"},fc={class:"muted-cell"},dc={class:"muted-cell"},pc={class:"panel sim-panel",id:"simulation"},hc={class:"panel-header signal-header"},gc={class:"status-tag neutral-tag"},vc={class:"sim-controls"},mc={class:"sim-field"},_c={class:"sim-field"},bc=["disabled"],yc={key:0,class:"sim-result"},xc={class:"sim-sums"},wc={class:"sim-sum"},Sc={class:"sim-sum"},Cc={class:"sim-note"},Tc={class:"sim-buckets"},Ec={class:"sim-bucket"},Oc={class:"sim-order-table"},kc={key:0},Pc={class:"muted-cell"},Ac={class:"score-cell"},Mc={class:"score-cell"},Rc={key:1},Ic={class:"sim-bucket"},Fc={class:"sim-order-table"},Dc={key:0},Nc={class:"muted-cell"},Lc={class:"score-cell"},jc={class:"score-cell"},Vc={key:1},$c={class:"sim-bucket"},Hc={class:"sim-order-table"},Bc={key:0},Kc={class:"muted-cell"},Uc={class:"score-cell"},Wc={class:"score-cell"},qc={key:1},zc={key:1,class:"empty-research"},Jc={key:2,class:"fwd-panel"},Gc={key:0,class:"empty-research muted-cell"},Yc={key:1,class:"source-table"},Xc={class:"muted-cell"},Zc={key:0,class:"status-tag warning-tag",title:"ใช้คะแนนปัจจุบัน ไม่ใช่ PIT"},Qc={class:"positive-text"},eu={class:"muted-cell"},tu=["onClick"],su=["onClick"],nu={key:2,class:"muted-cell"},lu={class:"panel backtest-panel",id:"backtest"},iu={class:"backtest-controls"},ou=["disabled"],ru={key:0,class:"state-card error-state"},au={key:1,class:"backtest-results"},cu={class:"bt-kpi-grid"},uu={class:"bt-kpi"},fu={class:"bt-kpi"},du={class:"positive-text"},pu={class:"bt-kpi"},hu={class:"bt-kpi"},gu={class:"bt-meta muted-cell"},vu={class:"bt-meta muted-cell"},mu={key:0,class:"bt-meta muted-cell"},_u={key:1,class:"bt-holdings"},bu={key:2,class:"empty-research"},yu={key:3,class:"bt-history"},xu={class:"source-table"},wu={key:0,class:"status-tag warning-tag",title:"ใช้คะแนนปัจจุบันย้อนหลัง ไม่ใช่ point-in-time"},Su={class:"positive-text"},Cu=["title"],Tu={class:"muted-cell"},Eu={class:"modal-card"},Ou={class:"modal-head"},ku={key:0,class:"empty-research"},Pu={key:1,class:"state-card error-state"},Au={key:2,class:"modal-body"},Mu={class:"modal-section"},Ru={key:0,class:"modal-themes"},Iu={class:"contrib-name"},Fu={key:0,class:"contrib-calc"},Du={key:1,class:"muted-cell"},Nu={key:1,class:"muted-cell"},Lu={class:"modal-section"},ju={class:"fund-grid"},Vu={class:"modal-sub"},$u={class:"modal-section"},Hu={class:"calc-box"},Bu={class:"calc-line"},Ku={class:"calc-step-head"},Uu={class:"calc-step-note"},Wu={key:0,class:"calc-z"},qu={class:"modal-sub"},zu={__name:"App",setup(e){const t=B(null),s=B(null),n=B(null),l=B(null),i=B(null),o=B(null),a=B(1e6),u=B(null),h=B(null),p=B(!1),x=B("2024-06-01"),A=B("2026-06-01"),I=B(1e6),U=B("monthly"),N=B(!1),j=B(null),G=B([]),$=B("backtest"),K=B(!1),R=B(null),le=B(!1),se=B("signal_score"),ge=B("desc"),Le=B({entries:[]}),Ot=B(null),Ye=B(null),Xe=B(!0),Ze=B(""),Qe=B(""),Vt=B(!1),ps=B("token"),fe=B(!0),ne=B(""),Y=ae(()=>{var v;return((v=l.value)==null?void 0:v.factors)??[]}),je=ae(()=>{var v;return((v=o.value)==null?void 0:v.themes)??[]}),mt=ae(()=>{var v;return((v=o.value)==null?void 0:v.sources)??[]}),Se=ae(()=>{var v;return((v=o.value)==null?void 0:v.macro)??{}}),Ce=ae(()=>mt.value.length),$t=ae(()=>{var v,f;return((f=(v=o.value)==null?void 0:v.source_summary)==null?void 0:f.factor_keys)??Ce.value}),Ht=ae(()=>{var v;return((v=o.value)==null?void 0:v.available)??!1}),Js=ae(()=>{var v;return((v=o.value)==null?void 0:v.board)??Y.value}),Ve=ae(()=>{const v={};for(const f of Js.value)v[f.symbol]=f;return v}),et=ae(()=>{var f;const v=(f=t.value)==null?void 0:f.signal_summary;return{long:(v==null?void 0:v.long)??0,short:(v==null?void 0:v.short)??0,neutral:(v==null?void 0:v.neutral)??0,total:(v==null?void 0:v.total)??0}}),Bt=v=>({monthly:"รายเดือน",quarterly:"รายไตรมาส",annual:"รายปี",daily:"รายวัน"})[v]||v,Kt=ae(()=>{const v={};for(const f of je.value)v[f.id]=f.label_th;return v});function ht(v){const f=Ve.value[v];return((f==null?void 0:f.themes)??[]).map(Pe=>Kt.value[Pe]||Pe)}const hs=ae(()=>{var v;return((v=l.value)==null?void 0:v.available)??!1}),c=ae(()=>{var v;return((v=l.value)==null?void 0:v.dividend_count)??0}),d=ae(()=>{var v;return((v=i.value)==null?void 0:v.combined_count)??0}),m=ae(()=>{let v=Y.value;return le.value&&(v=v.filter(f=>f.is_dividend)),v});function C(v,f){var ve;return f==="signal_score"?v.signal_score??(v.signal_side==="LONG"?9999:0):f==="combined"?((ve=Ve.value[v.symbol])==null?void 0:ve.combined)??-9999:f==="symbol"?v.symbol:f==="dividend_yield"?v.dividend_yield??-1:f==="eps_growth_yoy"?v.eps_growth_yoy??-1:f==="pe"?v.pe??0:f==="eps"?v.eps??0:f==="pbv"?v.pbv??0:f==="roe"?v.roe??0:v[f]}const S=ae(()=>{const v=[...m.value],f=ge.value==="asc"?1:-1;return v.sort((ve,Pe)=>{const $e=C(ve,se.value),st=C(Pe,se.value);return typeof $e=="string"?$e.localeCompare(st)*f:$e===st?ve.symbol.localeCompare(Pe.symbol):$e==null?1:st==null?-1:($e-st)*f}),v});function b(v){se.value===v?ge.value=ge.value==="asc"?"desc":"asc":(se.value=v,ge.value="desc")}function T(v){return se.value!==v?"":ge.value==="asc"?"↑":"↓"}function y(v,f=2){return Number(v??0).toFixed(f)}function E(v){return v==="dated_ledger"?"ปันผล (ตามวันจริง)":v==="dps_annual_proxy"?"ประมาณการปันผล/หุ้น (DPS)":"ประมาณการปันผล (Proxy)"}function w(v){return v==="dated_ledger"}function F(v){return w(v)?{label:"ตามวันจริง",cls:"status-tag",style:"background:#1a7f37;color:#fff"}:v==="dps_annual_proxy"?{label:"Proxy (ต่อหุ้น)",cls:"status-tag warning-tag"}:{label:"Proxy",cls:"status-tag warning-tag"}}function O(v){return w(v)?"ปันผลตามวันจริงจาก ledger (ex-date × จำนวนหุ้น) — กระแสเงินสดจริง":v==="dps_annual_proxy"?"ประมาณการปันผลต่อหุ้น (DPS ล่าสุด × จำนวนหุ้น) ไม่ใช่กระแสเงินสดตามวันจริง":"ประมาณจาก dividend yield ของพอร์ตสุดท้าย ไม่ใช่กระแสเงินสดปันผลจริง"}function D(v){return v?new Date(v).toLocaleString("en-GB",{day:"2-digit",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"}):"—"}async function M(v,f){const ve=await fetch(v,f);if(!ve.ok){const Pe=await ve.json().catch(()=>({}));throw new Error(Pe.error||`Request failed: ${ve.status}`)}return ve.json()}async function H(){const v=await fetch("/api/v1/backtest/tourism?min_events=12"),f=await v.json().catch(()=>({}));if(![200,409].includes(v.status))throw new Error(f.error||`Request failed: ${v.status}`);return f}async function X(){const v=await fetch("/api/v1/research/tourism/latest");if(v.status===404)return null;const f=await v.json().catch(()=>({}));if(!v.ok)throw new Error(f.error||`Request failed: ${v.status}`);return f}const W=ae(()=>{var v;return((v=R.value)==null?void 0:v.orders)??[]}),ie=ae(()=>{var v;return((v=R.value)==null?void 0:v.invested)??0}),ce=ae(()=>{var v;return((v=R.value)==null?void 0:v.unallocated_cash)??0}),de=v=>W.value.filter(f=>f.bucket===v);async function Oe(){K.value=!0,R.value=null;try{$.value==="forward"?(R.value=await M("/api/v1/forward",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({capital:Number(a.value),use_pit:!1})}),await ue()):R.value=await M("/api/v1/simulation",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({capital:Number(a.value),mode:"backtest"})})}catch(v){Qe.value=v.message}finally{K.value=!1}}const tt=B([]),Ut=B(!1);async function ue(){Ut.value=!0;try{const v=await M("/api/v1/forward");tt.value=v.runs??[]}catch(v){Qe.value=v.message}finally{Ut.value=!1}}async function ke(v){try{await M(`/api/v1/forward/${v}/mark`,{method:"POST"}),await ue()}catch(f){Qe.value=f.message}}async function gs(v){try{await M(`/api/v1/forward/${v}/mature`,{method:"POST"}),await ue()}catch(f){Qe.value=f.message}}async function vs(){Xe.value=!0,Ze.value="";try{const[v,f,ve,Pe,$e,st,ms,_t,_s,bs]=await Promise.all([M("/api/v1/dashboard/summary"),M("/api/v1/factors/tourism/observations"),M("/api/v1/signals"),M("/api/v1/factors"),M("/api/v1/themes"),M("/api/v1/dashboard"),M("/api/v1/paper/ledger"),M("/api/v1/auth/paper",{credentials:"include"}),H(),X()]);t.value=v,s.value=f,n.value=ve,l.value=Pe,i.value=$e,o.value=st,Le.value=ms,Vt.value=!!_t.authenticated,ps.value=_t.mode||"token",fe.value=_t.enabled!==!1,ne.value=_t.warning||"",Ot.value=_s,Ye.value=bs,await ue()}catch(v){Ze.value=v.message}finally{Xe.value=!1}}async function ki(v){u.value=v,h.value=null,p.value=!0;try{h.value=await M(`/api/v1/symbols/${v}`)}catch(f){h.value={error:f.message,symbol:v}}finally{p.value=!1}}function Nn(){u.value=null,h.value=null}async function Pi(){N.value=!0,j.value=null;try{j.value=await M("/api/v1/backtest",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({start:x.value,end:A.value,capital:Number(I.value),freq:U.value})}),await Ln()}catch(v){j.value={error:v.message}}finally{N.value=!1}}async function Ln(){try{G.value=(await M("/api/v1/backtest/runs")).runs||[]}catch{G.value=[]}}const Wt=v=>v!=null?v>=0?"positive-text":"negative-text":"";return ti(async()=>{await vs(),await Ln()}),(v,f)=>{var ve,Pe,$e,st,ms,_t,_s,bs,jn,Vn,$n;return k(),P("div",la,[f[75]||(f[75]=hr('',1)),r("main",ia,[r("header",oa,[f[17]||(f[17]=r("div",null,[r("div",{class:"eyebrow"},"Alternative data · SET50"),r("h1",null,"SET50 Signal Lab"),r("p",{class:"subtitle"},"ภาพรวม alternative factors ไทย ไปจนถึงสัญญาณลงทุนที่อธิบายได้ — research + paper only")],-1)),r("div",ra,[r("div",{class:ee(["freshness-pill",Ht.value?"pill-live":"pill-fixture"])},[f[16]||(f[16]=r("span",{class:"freshness-dot"},null,-1)),q(_(Ht.value?"ข้อมูลจริงจากแหล่งไทย":"ข้อมูลจำลอง (fixture)"),1)],2),r("div",aa,"ข้อมูล "+_(((ve=t.value)==null?void 0:ve.as_of)||"—"),1)])]),Xe.value?(k(),P("div",ca,"กำลังโหลดข้อมูล…")):Ze.value?(k(),P("div",ua,_(Ze.value),1)):(k(),P(oe,{key:2},[r("section",fa,[r("article",da,[f[20]||(f[20]=r("div",{class:"kpi-label"},"สัญญาณที่ใช้งาน",-1)),r("div",pa,_(et.value.long),1),r("div",ha,[r("span",ga,_(et.value.long)+" ซื้อ",1),f[18]||(f[18]=q(" · ",-1)),r("span",va,_(et.value.short)+" ขาย",1),f[19]||(f[19]=q(" · ",-1)),r("span",ma,_(et.value.neutral)+" เป็นกลาง",1)])]),r("article",_a,[f[21]||(f[21]=r("div",{class:"kpi-label"},"แหล่งข้อมูลที่ใช้",-1)),r("div",ba,_($t.value)+" ปัจจัย · "+_(Ce.value)+" แหล่ง",1),r("div",ya,"ข้อมูลจริงจากแหล่งไทย "+_(Ht.value?"(จริง)":"—"),1)])]),r("section",xa,[r("div",wa,[f[22]||(f[22]=r("div",null,[r("div",{class:"section-kicker"},"ธีม"),r("h2",null,"ธีม (Themes)"),r("p",{class:"panel-subtitle"},"ภาพรวม alternative factors ของไทย — แต่ละธีมมีความถี่ข้อมูลต่างกัน (monthly / quarterly) ดังนั้นอย่าเทียบเป็นจุดเวลาเดียวกัน.")],-1)),r("span",Sa,"รวม "+_(d.value)+" symbols",1)]),r("div",Ca,[(k(!0),P(oe,null,Ae(je.value,g=>(k(),P("article",{key:g.id,class:"theme-card"},[r("div",Ta,[r("span",Ea,_(Bt(g.frequency)),1),r("span",Oa,_(g.label_th),1)]),r("div",ka,[f[23]||(f[23]=r("span",{class:"theme-surprise-label"},"ความต่าง (surprise)",-1)),r("span",Pa,_(g.surprise!=null?y(g.surprise,2)+"σ":"—"),1)]),r("div",Aa,[g.id==="auto_credit"&&g.read.new_car_sales_yoy!=null?(k(),P("div",Ma,_(y(g.read.new_car_sales_yoy))+"% YoY ยอดขายรถ",1)):g.id==="auto_credit"&&g.read.auto_npl_pct!=null?(k(),P("div",Ra,"NPL "+_(y(g.read.auto_npl_pct))+"%",1)):g.id==="refining_energy"&&(g.read.quarterly||g.read.net_profit)?(k(),P("div",Ia,"กำไรสุทธิ TOP (รายไตรมาส)")):g.id==="tourism"?(k(),P("div",Fa,"signal tourism "+_(g.surprise!=null?y(g.surprise,2):"—")+"σ",1)):pe("",!0)]),g.narrative?(k(),P("div",Da,_(g.narrative),1)):pe("",!0)]))),128))]),Object.keys(Se.value).length?(k(),P("div",Na,[f[29]||(f[29]=r("div",{class:"section-kicker"},"ภาพรวมประเทศไทย",-1)),r("div",La,[r("span",ja,[f[24]||(f[24]=q("การบริโภคภาคเอกชน ",-1)),r("strong",null,_(Se.value.private_consumption_yoy)+"%",1)]),r("span",Va,[f[25]||(f[25]=q("การลงทุนเอกชน ",-1)),r("strong",null,_(Se.value.private_investment_yoy)+"%",1)]),r("span",$a,[f[26]||(f[26]=q("เงินเฟ้อ ",-1)),r("strong",null,_(Se.value.headline_inflation_yoy)+"%",1)]),r("span",Ha,[f[27]||(f[27]=q("การว่างงาน ",-1)),r("strong",null,_(Se.value.unemployment_pct)+"%",1)]),r("span",Ba,[f[28]||(f[28]=q("นักท่องเที่ยว YTD ",-1)),r("strong",null,_(Se.value.tourists_ytd_mn)+" ล้าน",1)])])])):pe("",!0)]),r("section",Ka,[r("div",Ua,[f[30]||(f[30]=r("div",null,[r("div",{class:"section-kicker"},"ตารางหุ้น"),r("h2",null,"ตารางหุ้น"),r("p",{class:"panel-subtitle"},[q("ตารางเดียวรวมทุกธีม — สัญญาณ + คะแนนรวม (60% ธีม / 40% พื้นฐาน) + มูลค่าพื้นฐานจาก Siamchart. เรียงได้โดยคลิกหัวตาราง; เปิด "),r("em",null,"เฉพาะหุ้นปันผล"),q(" เพื่อกรองหุ้นที่จ่ายปันผล.")])],-1)),r("div",Wa,[r("label",qa,[bt(r("input",{type:"checkbox","onUpdate:modelValue":f[0]||(f[0]=g=>le.value=g)},null,512),[[Gr,le.value]]),r("span",null,"เฉพาะหุ้นปันผล ("+_(c.value)+")",1)]),r("span",{class:ee(["status-tag",hs.value?"":"warning-tag"])},_(hs.value?"Siamchart ใช้งานได้":"ไม่มี factor"),3)])]),hs.value?(k(),P("div",Ja,[r("table",Ga,[r("thead",null,[r("tr",null,[r("th",{class:ee(["sortable",{active:se.value==="signal_score"}]),onClick:f[1]||(f[1]=g=>b("signal_score"))},"สัญญาณ "+_(T("signal_score")),3),r("th",{class:ee(["sortable",{active:se.value==="combined"}]),onClick:f[2]||(f[2]=g=>b("combined")),title:"60% ธีม + 40% พื้นฐาน"},"คะแนนรวม (60/40) "+_(T("combined")),3),r("th",{class:ee(["sortable",{active:se.value==="symbol"}]),onClick:f[3]||(f[3]=g=>b("symbol"))},"หุ้น "+_(T("symbol")),3),f[32]||(f[32]=r("th",null,"ธีม",-1)),r("th",{class:ee(["sortable",{active:se.value==="pe"}]),onClick:f[4]||(f[4]=g=>b("pe"))},"P/E "+_(T("pe")),3),r("th",{class:ee(["sortable",{active:se.value==="eps"}]),onClick:f[5]||(f[5]=g=>b("eps"))},"EPS "+_(T("eps")),3),r("th",{class:ee(["sortable",{active:se.value==="eps_growth_yoy"}]),onClick:f[6]||(f[6]=g=>b("eps_growth_yoy"))},"EPS YoY "+_(T("eps_growth_yoy")),3),r("th",{class:ee(["sortable",{active:se.value==="dividend_yield"}]),onClick:f[7]||(f[7]=g=>b("dividend_yield"))},"ปันผล % "+_(T("dividend_yield")),3),r("th",{class:ee(["sortable",{active:se.value==="pbv"}]),onClick:f[8]||(f[8]=g=>b("pbv"))},"P/BV "+_(T("pbv")),3),r("th",{class:ee(["sortable",{active:se.value==="roe"}]),onClick:f[9]||(f[9]=g=>b("roe"))},"ROE "+_(T("roe")),3)])]),r("tbody",null,[(k(!0),P(oe,null,Ae(S.value,g=>{var nt;return k(),P("tr",{key:g.symbol,class:"clickable-row",onClick:Gs=>ki(g.symbol)},[r("td",null,[g.signal_side?(k(),P("span",{key:0,class:ee(["side-pill",g.signal_side.toLowerCase()])},_(g.signal_side),3)):(k(),P("span",Xa,"—"))]),r("td",Za,_(((nt=Ve.value[g.symbol])==null?void 0:nt.combined)!=null?y(Ve.value[g.symbol].combined):"—"),1),r("td",null,[r("strong",Qa,_(g.symbol),1)]),r("td",null,[(k(!0),P(oe,null,Ae(ht(g.symbol),Gs=>(k(),P("span",{key:Gs,class:"theme-tag"},_(Gs),1))),128)),ht(g.symbol).length?pe("",!0):(k(),P("span",ec,"—"))]),r("td",tc,_(g.pe!=null?y(g.pe):"—"),1),r("td",null,_(g.eps!=null?y(g.eps):"—"),1),r("td",{class:ee(g.eps_growth_yoy>=0?"positive-text":"negative-text")},_(g.eps_growth_yoy!=null?(g.eps_growth_yoy>=0?"+":"")+y(g.eps_growth_yoy)+"%":"—"),3),r("td",{class:ee(g.dividend_yield>=0?"positive-text":"")},[q(_(g.dividend_yield!=null?y(g.dividend_yield)+"%":"—"),1),g.is_dividend?(k(),P("span",sc,"●")):pe("",!0)],2),r("td",null,_(g.pbv!=null?y(g.pbv):"—"),1),r("td",{class:ee(g.roe>=0?"positive-text":"negative-text")},_(g.roe!=null?y(g.roe)+"%":"—"),3)],8,Ya)}),128))])])])):(k(),P("div",za,[...f[31]||(f[31]=[q("Siamchart snapshot ไม่อยู่บน disk. รัน ",-1),r("code",null,"collect_siamchart.py --group SET50 --with-info",-1),q(" เพื่อเก็บข้อมูล.",-1)])]))]),r("section",nc,[r("div",lc,[f[33]||(f[33]=r("div",null,[r("div",{class:"section-kicker"},"ที่มาของข้อมูล"),r("h2",null,"แหล่งข้อมูลทั้งหมด"),r("p",{class:"panel-subtitle"},"รายการแหล่งข้อมูลจริงที่ใช้ — ดึงมาเมื่อใด และข้อมูลชุดไหน ข้อมูลทั้งหมดจากแหล่งไทย.")],-1)),r("span",ic,_($t.value)+" ปัจจัย · "+_(Ce.value)+" แหล่ง",1)]),r("div",oc,[r("table",rc,[f[34]||(f[34]=r("thead",null,[r("tr",null,[r("th",null,"ข้อมูล"),r("th",null,"แหล่ง"),r("th",null,"ช่วงข้อมูล"),r("th",null,"ความถี่"),r("th",null,"อัปเดตครั้งต่อไป"),r("th",null,"อัปเดตล่าสุด")])],-1)),r("tbody",null,[(k(!0),P(oe,null,Ae(mt.value,(g,nt)=>(k(),P("tr",{key:nt},[r("td",null,_(g.จาก||g.ขอบเขต),1),r("td",ac,_(g.แหล่ง),1),r("td",cc,_(g.ข้อมูล),1),r("td",uc,_(g.ความถี่||"—"),1),r("td",fc,_(g.อัปเดตครั้งต่อไป?D(g.อัปเดตครั้งต่อไป):"—"),1),r("td",dc,_(g.dึงมาเมื่อ?D(g.dึงมาเมื่อ):"—"),1)]))),128))])])])]),r("section",pc,[r("div",hc,[f[35]||(f[35]=r("div",null,[r("div",{class:"section-kicker"},"การจำลองการลงทุน"),r("h2",null,"จัดสรรทุน (Simulation)"),r("p",{class:"panel-subtitle"},"กรอกทุน และระบบจัดสรรตามสัดส่วน 50 / 20 / 30 — หุ้นที่ทำกำไรได้มากสุดแล้วจ่ายปันผล, หุ้นทำกำไรแต่ไม่ปันผล, และหุ้นปันผลสูงสุด (ไม่ซ้ำ) — ขั้นต่ำ 100 หุ้นต่อตัว.")],-1)),r("span",gc,_(R.value?"ใช้ได้":"รอใส่ทุน"),1)]),r("div",vc,[r("div",mc,[f[36]||(f[36]=r("label",null,"ทุน (บาท)",-1)),bt(r("input",{"onUpdate:modelValue":f[10]||(f[10]=g=>a.value=g),type:"number",min:"1000",step:"1000"},null,512),[[Cs,a.value]])]),r("div",_c,[f[38]||(f[38]=r("label",null,"โหมด",-1)),bt(r("select",{"onUpdate:modelValue":f[11]||(f[11]=g=>$.value=g)},[...f[37]||(f[37]=[r("option",{value:"backtest"},"Backtest",-1),r("option",{value:"forward"},"Forward test",-1)])],512),[[ml,$.value]])]),r("button",{class:"primary-button",disabled:K.value,onClick:Oe},_(K.value?"กำลังคำนวณ…":"คำนวณการจัดสรร"),9,bc)]),R.value?(k(),P("div",yc,[r("div",xc,[r("div",wc,[f[39]||(f[39]=r("span",null,"ลงทุนรวม",-1)),r("strong",null,_(y(ie.value,0))+" บาท",1)]),r("div",Sc,[f[40]||(f[40]=r("span",null,"เงินสดเหลือ",-1)),r("strong",null,_(y(ce.value,0))+" บาท",1)])]),r("div",Cc,_(R.value.data_note),1),r("div",Tc,[r("div",Ec,[f[42]||(f[42]=r("div",{class:"sim-bucket-head"},[r("span",{class:"sim-bucket-tag b1"},"50%"),r("strong",null,"ทำกำไร + จ่ายปันผล")],-1)),r("table",Oc,[de(1).length?(k(),P("tbody",kc,[(k(!0),P(oe,null,Ae(de(1),g=>(k(),P("tr",{key:"b1"+g.symbol},[r("td",null,_(g.symbol),1),r("td",Pc,"qty "+_(g.qty),1),r("td",Ac,"@ "+_(y(g.price)),1),r("td",Mc,_(y(g.notional,0)),1)]))),128))])):(k(),P("tbody",Rc,[...f[41]||(f[41]=[r("tr",null,[r("td",{class:"muted-cell"},"ไม่มีหุ้นที่เข้าเกณฑ์")],-1)])]))])]),r("div",Ic,[f[44]||(f[44]=r("div",{class:"sim-bucket-head"},[r("span",{class:"sim-bucket-tag b2"},"20%"),r("strong",null,"ทำกำไร ไม่ปันผล")],-1)),r("table",Fc,[de(2).length?(k(),P("tbody",Dc,[(k(!0),P(oe,null,Ae(de(2),g=>(k(),P("tr",{key:"b2"+g.symbol},[r("td",null,_(g.symbol),1),r("td",Nc,"qty "+_(g.qty),1),r("td",Lc,"@ "+_(y(g.price)),1),r("td",jc,_(y(g.notional,0)),1)]))),128))])):(k(),P("tbody",Vc,[...f[43]||(f[43]=[r("tr",null,[r("td",{class:"muted-cell"},"ไม่มีหุ้นที่เข้าเกณฑ์")],-1)])]))])]),r("div",$c,[f[46]||(f[46]=r("div",{class:"sim-bucket-head"},[r("span",{class:"sim-bucket-tag b3"},"30%"),r("strong",null,"ปันผลสูงสุด (ไม่ซ้ำ)")],-1)),r("table",Hc,[de(3).length?(k(),P("tbody",Bc,[(k(!0),P(oe,null,Ae(de(3),g=>(k(),P("tr",{key:"b3"+g.symbol},[r("td",null,_(g.symbol),1),r("td",Kc,"qty "+_(g.qty),1),r("td",Uc,"@ "+_(y(g.price)),1),r("td",Wc,_(y(g.notional,0)),1)]))),128))])):(k(),P("tbody",qc,[...f[45]||(f[45]=[r("tr",null,[r("td",{class:"muted-cell"},"ไม่มีหุ้นที่เข้าเกณฑ์")],-1)])]))])])])])):pe("",!0),R.value?pe("",!0):(k(),P("div",zc,"กด 'คำนวณการจัดสรร' เพื่อดูว่า 50/20/30 จัดสรรทุนของคุณไปที่หุ้นไหนบ้าง")),$.value==="forward"?(k(),P("div",Jc,[f[48]||(f[48]=r("div",{class:"section-kicker"},"Forward Test (Paper) — สัญญาณถูกตรึง ณ เวลาสร้าง",-1)),f[49]||(f[49]=r("p",{class:"panel-subtitle"},"สร้าง forward run → สัญญาณ (คะแนน) ถูก freeze ทันทีที่สร้าง แล้ว execute ด้วยราคาหลัง freeze. กด Mark ตามราคาล่าสุด, Mature เพื่อปิด run. เป็น Paper เท่านั้น.",-1)),tt.value.length===0?(k(),P("div",Gc,"ยังไม่มี forward run — กด 'คำนวณการจัดสรร' ข้างบนเพื่อสร้าง")):(k(),P("table",Yc,[f[47]||(f[47]=r("thead",null,[r("tr",null,[r("th",null,"#"),r("th",null,"สถานะ"),r("th",null,"ทุน"),r("th",null,"ลงทุน"),r("th",null,"ถือ"),r("th",null,"ผลตอบแทน"),r("th",null,"ตรวจ")])],-1)),r("tbody",null,[(k(!0),P(oe,null,Ae(tt.value.slice().reverse(),g=>(k(),P("tr",{key:g.id},[r("td",Xc,_(g.id.slice(0,12)),1),r("td",null,[r("span",{class:ee(["status-tag",g.status==="matured"?"warning-tag":g.status==="frozen"?"neutral-tag":"warning-tag"])},_(g.status),3),g.non_pit?(k(),P("span",Zc,"non-PIT")):pe("",!0)]),r("td",null,_(y(g.capital,0)),1),r("td",Qc,_(y(g.invested,0)),1),r("td",eu,_(Object.keys(g.holdings||{}).join(", ")||"—"),1),r("td",{class:ee(Wt(g.net_return))},_(g.net_return!=null?(g.net_return*100).toFixed(2)+"%":"—"),3),r("td",null,[g.status!=="matured"?(k(),P("button",{key:0,class:"primary-btn",style:{padding:"2px 8px","margin-right":"4px"},onClick:nt=>ke(g.id)},"Mark",8,tu)):pe("",!0),g.status!=="matured"?(k(),P("button",{key:1,class:"primary-btn",style:{padding:"2px 8px"},onClick:nt=>gs(g.id)},"Mature",8,su)):(k(),P("span",nu,"ปิดแล้ว"))])]))),128))])]))])):pe("",!0)]),r("section",lu,[f[61]||(f[61]=r("div",{class:"panel-header signal-header"},[r("div",null,[r("div",{class:"section-kicker"},"การย้อนทดสอบ"),r("h2",null,"Backtest (ย้อนทดสอบ)"),r("p",{class:"panel-subtitle"},"กำหนดช่วงวัน แล้วระบบจัดสรร 50/20/30 ณ วันที่เริ่ม ลงทุนและถือจนถึงวันสิ้นสุด — สรุปกำไร/ขาดทุนจากราคา + เงินปันผล.")])],-1)),r("div",iu,[r("label",null,[f[50]||(f[50]=q("ตั้งแต่ ",-1)),bt(r("input",{type:"date","onUpdate:modelValue":f[12]||(f[12]=g=>x.value=g)},null,512),[[Cs,x.value]])]),r("label",null,[f[51]||(f[51]=q("ถึง ",-1)),bt(r("input",{type:"date","onUpdate:modelValue":f[13]||(f[13]=g=>A.value=g)},null,512),[[Cs,A.value]])]),r("label",null,[f[52]||(f[52]=q("ทุน ",-1)),bt(r("input",{type:"number","onUpdate:modelValue":f[14]||(f[14]=g=>I.value=g),step:"100000"},null,512),[[Cs,I.value,void 0,{number:!0}]])]),r("label",null,[f[54]||(f[54]=q("ความถี่ ",-1)),bt(r("select",{"onUpdate:modelValue":f[15]||(f[15]=g=>U.value=g)},[...f[53]||(f[53]=[r("option",{value:"monthly"},"รายเดือน",-1),r("option",{value:"quarterly"},"รายไตรมาส",-1)])],512),[[ml,U.value]])]),r("button",{class:"primary-btn",disabled:N.value,onClick:Pi},_(N.value?"กำลังย้อนทดสอบ…":"รัน Backtest"),9,ou)]),(Pe=j.value)!=null&&Pe.error?(k(),P("div",ru,_(j.value.error),1)):j.value?(k(),P("div",au,[r("div",cu,[r("div",uu,[f[55]||(f[55]=r("span",null,"กำไรจากราคา",-1)),r("strong",{class:ee(Wt(j.value.price_pnl))},_(y(j.value.price_pnl))+" บาท",3)]),r("div",fu,[r("span",null,[q(_(E(j.value.dividend_method)),1),r("span",{class:ee(["status-tag",F(j.value.dividend_method).cls]),style:ss([F(j.value.dividend_method).style||void 0,{"margin-left":"6px"}])},_(F(j.value.dividend_method).label),7)]),r("strong",du,_(y(j.value.dividend_income))+" บาท",1)]),r("div",pu,[f[56]||(f[56]=r("span",null,"มูลค่าสุดท้าย",-1)),r("strong",null,_(y(j.value.final_value))+" บาท",1)]),r("div",hu,[f[57]||(f[57]=r("span",null,"ผลตอบแทนสุทธิ",-1)),r("strong",{class:ee(Wt(j.value.net_return))},_((j.value.net_return*100).toFixed(2))+"%",3)])]),r("div",gu,"Trades: "+_(j.value.trades)+" · ช่วง "+_(j.value.start)+" → "+_(j.value.end),1),r("div",vu,"*"+_(O(j.value.dividend_method)),1),j.value.leakage_guard?pe("",!0):(k(),P("div",mu,"คำเตือน: ผลนี้ใช้คะแนนปัจจุบันย้อนหลัง จึงเป็น descriptive non-PIT และไม่ใช่หลักฐานประสิทธิภาพกลยุทธ์")),Object.keys(j.value.holdings||{}).length?(k(),P("div",_u,[f[58]||(f[58]=r("strong",null,"พอร์ตสุดท้าย:",-1)),(k(!0),P(oe,null,Ae(j.value.holdings,(g,nt)=>(k(),P("span",{key:nt,class:"theme-tag"},_(nt)+" "+_(g)+" หุ้น",1))),128))])):pe("",!0)])):(k(),P("div",bu,"กำหนดช่วงวันแล้วกด 'รัน Backtest' เพื่อดูผล (กำไร/ขาดทุนจากราคา + ปันผล)")),G.value.length?(k(),P("div",yu,[f[60]||(f[60]=r("div",{class:"section-kicker"},"ประวัติการย้อนทดสอบ",-1)),r("table",xu,[f[59]||(f[59]=r("thead",null,[r("tr",null,[r("th",null,"#"),r("th",null,"ช่วง"),r("th",null,"ทุน"),r("th",null,"กำไรราคา"),r("th",null,"ปันผล"),r("th",null,"ผลตอบแทน"),r("th",null,"รันเมื่อ")])],-1)),r("tbody",null,[(k(!0),P(oe,null,Ae(G.value.slice().reverse(),g=>(k(),P("tr",{key:g.id},[r("td",null,_(g.id),1),r("td",null,[q(_(g.start)+" → "+_(g.end)+" ",1),g.leakage_guard===!1?(k(),P("span",wu,"descriptive non-PIT")):pe("",!0)]),r("td",null,_(y(g.capital)),1),r("td",{class:ee(Wt(g.price_pnl))},_(y(g.price_pnl)),3),r("td",Su,[q(_(y(g.dividend_income)),1),r("span",{class:ee(["status-tag",F(g.dividend_method).cls]),style:ss([F(g.dividend_method).style||void 0,{"margin-left":"4px"}]),title:O(g.dividend_method)},_(F(g.dividend_method).label),15,Cu)]),r("td",{class:ee(Wt(g.net_return))},_((g.net_return*100).toFixed(2))+"%",3),r("td",Tu,_(g.ran_at?D(g.ran_at):"—"),1)]))),128))])])])):pe("",!0)])],64))]),u.value?(k(),P("div",{key:0,class:"modal-overlay",onClick:Zr(Nn,["self"])},[r("div",Eu,[r("div",Ou,[r("div",null,[f[62]||(f[62]=r("div",{class:"modal-kicker"},"การวิเคราะห์รายหุ้น",-1)),r("h3",null,_(u.value),1)]),r("button",{class:"modal-close",onClick:Nn},"✕")]),p.value?(k(),P("div",ku,"กำลังโหลดการวิเคราะห์…")):($e=h.value)!=null&&$e.error?(k(),P("div",Pu,_(h.value.error),1)):h.value?(k(),P("div",Au,[r("div",Mu,[f[66]||(f[66]=r("div",{class:"modal-section-title"},"ธีมที่เกี่ยวข้อง (คะแนนต่อธีม)",-1)),(st=h.value.themes)!=null&&st.length?(k(),P("div",Ru,[(k(!0),P(oe,null,Ae(h.value.theme_contributions,g=>(k(),P("div",{key:g.theme,class:"contrib-line"},[r("span",Iu,_(g.label_th||Kt.value[g.theme]||g.theme),1),g.surprise!=null?(k(),P("span",Fu,[r("em",null,_(y(g.surprise))+"σ",1),f[63]||(f[63]=q(" × คุณภาพ ",-1)),r("em",null,_(g.quality),1),f[64]||(f[64]=q(" = ",-1)),r("strong",null,_(y(g.theme_score))+"σ",1)])):(k(),P("strong",Du,"ยังไม่มีข้อมูล"))]))),128)),f[65]||(f[65]=r("div",{class:"modal-sub"},"คะแนนธีม = ค่าเฉลี่ยของ (surprise × คุณภาพหุ้น) ที่หุ้นนี้อยู่ใน",-1))])):(k(),P("div",Nu,"หุ้นนี้ยังไม่ได้จัดอยู่ในธีมใด (จะอัปเดตเมื่อเพิ่มธีม)"))]),r("div",Lu,[f[72]||(f[72]=r("div",{class:"modal-section-title"},"มูลค่าพื้นฐาน (Siamchart)",-1)),r("div",ju,[r("span",null,[f[67]||(f[67]=q("P/E ",-1)),r("strong",null,_(((ms=h.value.fundamentals)==null?void 0:ms.pe)??"—"),1)]),r("span",null,[f[68]||(f[68]=q("EPS ",-1)),r("strong",null,_(((_t=h.value.fundamentals)==null?void 0:_t.eps)??"—"),1)]),r("span",null,[f[69]||(f[69]=q("P/BV ",-1)),r("strong",null,_(((_s=h.value.fundamentals)==null?void 0:_s.pbv)??"—"),1)]),r("span",null,[f[70]||(f[70]=q("ROE ",-1)),r("strong",null,_(((bs=h.value.fundamentals)==null?void 0:bs.roe)??"—"),1)]),r("span",null,[f[71]||(f[71]=q("ปันผล ",-1)),r("strong",null,_((jn=h.value.fundamentals)!=null&&jn.is_dividend?"จ่าย":"—"),1)])]),r("div",Vu,"ภาพรวม: "+_(h.value.company_name||u.value),1)]),r("div",$u,[f[74]||(f[74]=r("div",{class:"modal-section-title"},"ขั้นตอนการคำนวณคะแนนรวม",-1)),r("div",Hu,[r("div",Bu,_(h.value.combined_formula),1),(k(!0),P(oe,null,Ae(h.value.combined_calc,g=>(k(),P("div",{key:g.label,class:"calc-step"},[r("div",Ku,[r("span",null,_(g.label),1),r("strong",null,_(y(g.value))+" × "+_(g.weight),1)]),r("div",Uu,_(g.note),1)]))),128)),h.value.siamchart_z_note?(k(),P("div",Wu,[q(" คะแนนพื้นฐานได้จาก z-score: z = (ค่า"+_(h.value.siamchart_z_note.raw_i)+" − ค่าเฉลี่ย "+_(h.value.siamchart_z_note.population_mean)+") / ค่าเบี่ยงเบน "+_(h.value.siamchart_z_note.population_stdev),1),f[73]||(f[73]=r("br",null,null,-1)),q("เทียบกับ "+_(h.value.siamchart_z_note.universe_size)+" หุ้นใน SET50 ",1)])):pe("",!0)]),r("div",qu,"ราคาล่าสุด: "+_(((Vn=h.value.price)==null?void 0:Vn.latest)!=null?y(h.value.price.latest):"—")+" ("+_((($n=h.value.price)==null?void 0:$n.date)||"—")+")",1)])])):pe("",!0)])])):pe("",!0)])}}};ta(zu).mount("#app"); diff --git a/frontend/dist/assets/index-z73iDem3.css b/frontend/dist/assets/index-z73iDem3.css new file mode 100644 index 0000000..85b4742 --- /dev/null +++ b/frontend/dist/assets/index-z73iDem3.css @@ -0,0 +1 @@ +@import"https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Manrope:wght@400;500;600;700;800&display=swap";:root{color-scheme:dark;font-family:Manrope,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,sans-serif;color:#edf2f7;background:#0b1018;font-synthesis:none;text-rendering:optimizeLegibility;--bg: #0b1018;--panel: #111925;--panel-soft: #151f2d;--line: #263344;--line-bright: #35465c;--text: #edf2f7;--muted: #8794a6;--faint: #5b6a7e;--mint: #52d6bd;--mint-soft: rgba(82, 214, 189, .12);--amber: #e6b96c;--amber-soft: rgba(230, 185, 108, .12);--red: #ef8b8b;--red-soft: rgba(239, 139, 139, .12)}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;min-width:320px;background:var(--bg)}button,input{font:inherit}button{cursor:pointer}.app-shell{min-height:100vh;display:flex;background:radial-gradient(circle at 85% -10%,rgba(82,214,189,.08),transparent 32rem),var(--bg)}.sidebar{width:248px;flex:0 0 248px;min-height:100vh;padding:28px 18px 22px;border-right:1px solid var(--line);display:flex;flex-direction:column;background:#0b1018c2}.brand-lockup{display:flex;align-items:center;gap:11px;padding:0 9px 33px}.brand-mark{width:32px;height:32px;display:grid;place-items:center;border:1px solid rgba(82,214,189,.7);border-radius:9px;color:var(--mint);font:500 11px DM Mono,monospace;letter-spacing:-.08em;box-shadow:0 0 24px #52d6bd1f}.brand-name{font-size:13px;font-weight:800;letter-spacing:.01em}.brand-caption{margin-top:2px;color:var(--faint);font:10px DM Mono,monospace}.nav-stack{display:grid;gap:5px}.nav-item{display:flex;align-items:center;gap:11px;padding:11px 12px;border:1px solid transparent;border-radius:8px;color:var(--muted);text-decoration:none;font-size:12px;font-weight:600;transition:.2s ease}.nav-item:hover{color:var(--text);background:#ffffff06}.nav-item.active{color:var(--mint);background:var(--mint-soft);border-color:#52d6bd2e}.nav-glyph{width:16px;color:currentColor;font-size:15px;text-align:center}.sidebar-footer{margin-top:auto;padding:12px 8px 0}.mode-card{display:flex;gap:10px;align-items:center;padding:12px;border:1px solid var(--line);border-radius:10px;background:#ffffff05}.mode-dot,.freshness-dot{width:7px;height:7px;flex:0 0 7px;border-radius:99px;background:var(--mint);box-shadow:0 0 12px var(--mint)}.mode-label{font-size:11px;font-weight:700}.mode-detail,.version-line{margin-top:3px;color:var(--faint);font:10px DM Mono,monospace}.version-line{padding:14px 3px 0}.content{width:min(100%,1440px);margin:0 auto;padding:42px clamp(22px,4vw,64px) 70px}.topbar{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;padding-bottom:35px}.eyebrow,.section-kicker{color:var(--mint);font:500 10px DM Mono,monospace;letter-spacing:.14em;text-transform:uppercase}h1,h2,p{margin:0}h1{margin-top:10px;font-size:clamp(28px,4vw,46px);line-height:1.04;letter-spacing:-.055em}h2{margin-top:7px;font-size:17px;letter-spacing:-.025em}.subtitle{max-width:560px;margin-top:12px;color:var(--muted);font-size:13px;line-height:1.7}.topbar-meta{text-align:right;color:var(--muted);font:10px DM Mono,monospace}.freshness-pill{display:inline-flex;align-items:center;gap:8px;padding:7px 10px;border:1px solid rgba(82,214,189,.25);border-radius:99px;color:var(--mint);background:var(--mint-soft)}.freshness-pill.pill-fixture{border-color:#e6b96c59;color:var(--amber);background:var(--amber-soft)}.freshness-pill.pill-fixture .freshness-dot{background:var(--amber);box-shadow:0 0 12px var(--amber)}.as-of{margin-top:10px}.kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:12px}.kpi-card,.panel,.state-card{border:1px solid var(--line);background:linear-gradient(145deg,#151f2ddb,#0e151ff0);box-shadow:0 18px 42px #0000001f}.kpi-card{min-height:132px;padding:19px 19px 16px;border-radius:10px}.accent-card{border-color:#52d6bd4d;background:linear-gradient(145deg,#19383bcc,#0e1f26eb)}.kpi-label{color:var(--muted);font:10px DM Mono,monospace;text-transform:uppercase;letter-spacing:.08em}.kpi-value{margin-top:12px;color:var(--text);font-size:29px;font-weight:700;letter-spacing:-.055em}.kpi-unit{margin-left:4px;color:var(--mint);font:14px DM Mono,monospace}.quality-value{font-size:22px;text-transform:capitalize}.kpi-foot{margin-top:10px;color:var(--faint);font:10px DM Mono,monospace}.long-count,.positive-text{color:var(--mint)}.short-count,.negative-text{color:var(--red)}.hero-grid,.bottom-grid{display:grid;grid-template-columns:1.45fr 1fr;gap:12px;margin-bottom:12px}.panel{border-radius:10px;padding:22px}.panel-header{display:flex;justify-content:space-between;align-items:flex-start;gap:20px}.confidence-tag,.status-tag{padding:6px 8px;color:var(--mint);border:1px solid rgba(82,214,189,.22);border-radius:6px;background:var(--mint-soft);font:10px DM Mono,monospace;white-space:nowrap}.pulse-lead{display:flex;gap:15px;align-items:baseline;margin:26px 0 25px}.pulse-number{color:var(--mint);font-size:32px;font-weight:700;letter-spacing:-.06em}.pulse-copy{max-width:380px;color:var(--muted);font-size:12px;line-height:1.6}.observation-list{display:grid;gap:16px}.observation-row{display:grid;grid-template-columns:minmax(145px,1fr) 1.3fr 58px;align-items:center;gap:14px}.observation-name{color:var(--muted);font:10px DM Mono,monospace;text-transform:uppercase}.observation-track{height:6px;overflow:hidden;border-radius:99px;background:#253140}.observation-bar{height:100%;border-radius:inherit}.bar-positive{background:var(--mint);box-shadow:0 0 16px #52d6bd6b}.bar-negative{background:var(--red)}.observation-value{text-align:right;font:11px DM Mono,monospace}.lineage-panel{display:flex;flex-direction:column}.lineage-list{display:grid;gap:0;margin-top:24px;border-top:1px solid var(--line)}.lineage-item{display:flex;justify-content:space-between;gap:15px;padding:13px 0;border-bottom:1px solid var(--line);color:var(--muted);font-size:11px}.lineage-item strong{color:var(--text);font:10px DM Mono,monospace;text-align:right}.lineage-note{margin-top:auto;padding-top:22px;color:var(--faint);font-size:11px;line-height:1.7}.signal-panel{padding:0;overflow:hidden}.signal-header{padding:22px;border-bottom:1px solid var(--line)}.signal-header>div:first-child{flex:1 1 auto;min-width:0}.stock-panel .signal-header{align-items:center;flex-wrap:wrap}.stock-panel .panel-subtitle{max-width:620px}.strategy-meta{color:var(--faint);font:10px DM Mono,monospace}.strategy-meta span{color:var(--line-bright);padding:0 5px}.table-wrap{overflow-x:auto}table{width:100%;border-collapse:collapse;min-width:850px}th{padding:12px 16px;color:var(--faint);border-bottom:1px solid var(--line);font:10px DM Mono,monospace;font-weight:400;text-align:left;text-transform:uppercase;letter-spacing:.06em}td{padding:14px 16px;border-bottom:1px solid rgba(38,51,68,.72);color:var(--muted);font-size:11px;vertical-align:middle}tbody tr:last-child td{border-bottom:0}tbody tr:hover{background:#ffffff06}.muted-cell,.score-cell,.target-cell{font-family:DM Mono,monospace}.symbol-name{display:block;color:var(--text);font-size:12px}.confidence-cell{display:block;margin-top:4px;color:var(--faint);font:9px DM Mono,monospace}.side-pill{display:inline-block;min-width:52px;padding:5px 7px;border-radius:5px;font:10px DM Mono,monospace;text-align:center}.side-pill.long{color:var(--mint);background:var(--mint-soft)}.side-pill.short{color:var(--red);background:var(--red-soft)}.side-pill.neutral{color:var(--amber);background:var(--amber-soft)}.reason-code{display:inline-block;margin:2px 3px 2px 0;padding:4px 5px;border:1px solid var(--line-bright);border-radius:4px;color:var(--faint);font:9px DM Mono,monospace}.theme-panel{margin-top:18px}.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.theme-card{border:1px solid var(--line-bright);border-radius:10px;padding:14px;background:var(--card)}.theme-card-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}.theme-chip{background:var(--accent-soft, rgba(63,161,255,.12));color:var(--accent);font:9px DM Mono,monospace;padding:2px 6px;border-radius:4px;text-transform:uppercase}.theme-label-en{font:600 12px/1.4 var(--font);color:var(--foreground)}.theme-label-th{font-weight:700;margin-bottom:2px}.theme-source{font:10px DM Mono,monospace;color:var(--faint);margin-bottom:10px}.theme-read-value{font-size:22px;font-weight:700;color:var(--foreground)}.theme-read-meta{font-size:11px;color:var(--faint);margin-top:2px}.theme-read-error{font-size:11px;color:var(--danger, #e5484d)}@media(max-width:720px){.theme-grid{grid-template-columns:1fr}}.theme-surprise{display:flex;flex-direction:column;gap:2px;margin:8px 0 6px}.theme-surprise-label{font-size:10px;color:var(--faint)}.theme-surprise-value{font-size:22px;font-weight:700;color:var(--accent)}.theme-thesis{font-size:11px;color:var(--text-2, #99a);border-top:1px dashed var(--line-bright);padding-top:6px;margin-top:6px}.macro-panel{margin-top:14px;border-top:1px solid var(--line-bright);padding-top:12px}.macro-chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}.macro-chip{background:var(--card);border:1px solid var(--line-bright);border-radius:6px;padding:6px 9px;font-size:11px}.macro-chip strong{color:var(--mint)}.lineage-panel{margin-top:18px}.source-table{width:100%;border-collapse:collapse}.source-table th{text-align:left;font:700 10px DM Mono,monospace;color:var(--faint);padding:6px 8px;border-bottom:1px solid var(--line-bright)}.source-table td{padding:7px 8px;font-size:12px;border-bottom:1px solid var(--line-weak, rgba(255,255,255,.04))}.source-name{color:var(--accent)}.combined-cell{color:var(--mint);font-weight:600;font-family:DM Mono,monospace}.theme-tag{display:inline-block;margin:2px 3px 2px 0;padding:2px 6px;border-radius:4px;background:#3fa1ff1f;color:var(--accent);font-size:10px}.theme-tag.large{font-size:12px;padding:4px 8px}.clickable-row{cursor:pointer;transition:background .15s ease}.clickable-row:hover{background:#3fa1ff0f}.theme-narrative{font-size:12px;line-height:1.6;color:var(--text-2, #9aa);border-top:1px dashed var(--line-bright);padding-top:8px;margin-top:8px}.modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0009;display:flex;align-items:flex-start;justify-content:center;padding:40px 16px;z-index:50;overflow:auto}.modal-card{background:var(--card, #0e1218);border:1px solid var(--line-bright);border-radius:12px;max-width:640px;width:100%;padding:20px}.modal-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:14px}.modal-kicker{font:700 10px DM Mono,monospace;color:var(--faint);letter-spacing:.08em;text-transform:uppercase}.modal-head h3{font-size:24px;margin:4px 0 0}.modal-close{background:none;border:1px solid var(--line-bright);color:var(--text);width:30px;height:30px;border-radius:6px;cursor:pointer}.modal-body{display:flex;flex-direction:column;gap:16px}.modal-section{border-top:1px solid var(--line-weak, rgba(255,255,255,.06));padding-top:12px}.modal-section-title{font:700 11px DM Mono,monospace;color:var(--faint);margin-bottom:8px}.modal-sub{font-size:11px;color:var(--faint);margin-top:6px}.contrib-line{display:flex;justify-content:space-between;padding:3px 0;font-size:13px}.contrib-calc em{font-style:normal;color:var(--accent)}.contrib-calc strong{color:var(--mint);font-family:DM Mono,monospace}.contrib-calc{color:var(--text-2, #9aa);font-size:12px}.fund-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;font-size:12px}.fund-grid span{background:#ffffff08;border-radius:6px;padding:6px 8px}.fund-grid strong{color:var(--text);font-family:DM Mono,monospace}.score-table{width:100%;border-collapse:collapse;font-size:13px}.score-table td{padding:7px 6px;border-bottom:1px solid var(--line-weak, rgba(255,255,255,.05))}.score-table tr.score-total td{border-top:1px solid var(--line-bright);font-weight:700;color:var(--mint)}.calc-box{background:#00000040;border:1px solid var(--line-bright);border-radius:8px;padding:12px}.calc-line{font:700 14px DM Mono,monospace;color:var(--mint);padding:6px 0 10px;border-bottom:1px dashed var(--line-bright);margin-bottom:8px}.calc-step{padding:6px 0;border-bottom:1px solid var(--line-weak, rgba(255,255,255,.05))}.calc-step-head{display:flex;justify-content:space-between;font-size:13px}.calc-step-head strong{color:var(--text);font-family:DM Mono,monospace}.calc-step-note{font-size:11px;color:var(--faint);margin-top:3px;line-height:1.5}.calc-z{font-size:11px;color:var(--faint);margin-top:8px;line-height:1.6}.backtest-controls{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 0}.backtest-controls label{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--faint)}.backtest-controls input,.backtest-controls select{background:#0a0e14;border:1px solid var(--line-bright);color:var(--text);border-radius:6px;padding:7px 9px;font-size:12px}.primary-btn{background:var(--mint);color:#062a1f;border:none;border-radius:7px;padding:9px 16px;font-weight:700;cursor:pointer;font-size:12px}.primary-btn:disabled{opacity:.5;cursor:not-allowed}.bt-kpi-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin:12px 0}.bt-kpi{background:#ffffff08;border:1px solid var(--line-bright);border-radius:8px;padding:12px}.bt-kpi span{display:block;font-size:11px;color:var(--faint);margin-bottom:6px}.bt-kpi strong{font-size:15px;font-family:DM Mono,monospace}.bt-meta{margin:4px 0 10px;font-size:11px}.bt-holdings{margin-top:8px;font-size:12px;color:var(--text-2);display:flex;flex-wrap:wrap;gap:6px;align-items:center}.bt-history{margin-top:20px}.bt-history .source-table td{font-size:12px;padding:6px 8px}.thesis-list{display:flex;flex-direction:column;gap:10px;margin:12px 0}.thesis-row{display:flex;gap:10px;align-items:baseline;padding-bottom:8px;border-bottom:1px solid var(--line-weak, rgba(255,255,255,.05))}.thesis-theme{min-width:130px;color:var(--accent)}.thesis-text{flex:1;font-size:12px;color:var(--text-2, #99a)}.thesis-surprise{font-family:DM Mono,monospace;color:var(--mint)}.sim-panel{margin-top:18px}.sim-controls{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin-bottom:14px}.sim-field{display:flex;flex-direction:column;gap:4px}.sim-field label{font-size:11px;color:var(--faint)}.sim-field input,.sim-field select{background:var(--card);border:1px solid var(--line-bright);color:var(--text);padding:7px 9px;border-radius:5px;font-size:12px}.sim-result{display:flex;flex-direction:column;gap:12px}.sim-sums{display:flex;gap:24px}.sim-sum span{display:block;font-size:11px;color:var(--faint)}.sim-sum strong{font-size:20px}.sim-note{font-size:11px;color:var(--amber);font-style:italic}.sim-buckets{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}.sim-bucket{border:1px solid var(--line-bright);border-radius:8px;padding:10px}.sim-bucket-head{display:flex;align-items:center;gap:8px;margin-bottom:8px}.sim-bucket-tag{font:700 10px DM Mono,monospace;padding:2px 6px;border-radius:4px}.sim-bucket-tag.b1{background:var(--accent-soft, rgba(63,161,255,.15));color:var(--accent)}.sim-bucket-tag.b2{background:var(--amber-soft, rgba(245,158,11,.15));color:var(--amber)}.sim-bucket-tag.b3{background:var(--mint-soft, rgba(94,234,212,.15));color:var(--mint)}.sim-order-table{width:100%;border-collapse:collapse}.sim-order-table td{padding:3px 4px;font-size:12px}@media(max-width:720px){.sim-buckets{grid-template-columns:1fr}}.row-action,.primary-button{padding:8px 10px;border:1px solid var(--line-bright);border-radius:5px;color:var(--text);background:transparent;font-size:10px;white-space:nowrap;transition:.2s ease}.row-action:hover{color:var(--mint);border-color:var(--mint)}.stock-panel{padding:0;overflow:hidden;margin-bottom:12px}.panel-subtitle{margin-top:10px;color:var(--faint);font-size:11px;line-height:1.6}.panel-subtitle em{color:var(--mint);font-style:normal}.stock-controls{display:flex;align-items:center;gap:14px}.toggle-filter{display:inline-flex;align-items:center;gap:8px;color:var(--muted);font:10px DM Mono,monospace;cursor:pointer;-webkit-user-select:none;user-select:none}.toggle-filter input{width:auto;accent-color:var(--mint)}.toggle-filter span{white-space:nowrap}.dividend-dot{margin-left:6px;color:var(--amber)}th.sortable{cursor:pointer;transition:color .15s ease}th.sortable:hover{color:var(--text)}th.sortable.active{color:var(--mint)}.research-panel{margin-bottom:12px}.research-grid{display:grid;grid-template-columns:1fr 1.4fr;gap:24px;align-items:center;margin-top:22px}.research-status{display:inline-block;padding:7px 9px;border-radius:5px;font:11px DM Mono,monospace;text-transform:uppercase}.status-ready{color:var(--mint);background:var(--mint-soft)}.status-blocked,.status-descriptive{color:var(--amber);background:var(--amber-soft)}.research-reason{margin-top:12px;color:var(--muted);font-size:12px}.research-meta{margin-top:10px;color:var(--faint);font:9px DM Mono,monospace;overflow-wrap:anywhere}.gate-list{display:grid;gap:0;border-top:1px solid var(--line)}.gate-row{display:flex;justify-content:space-between;gap:15px;padding:12px 0;border-bottom:1px solid var(--line);color:var(--muted);font-size:11px}.gate-row strong{color:var(--text);font:10px DM Mono,monospace;text-align:right}.research-results{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-top:18px}.research-result-row{display:grid;gap:8px;padding:12px;border:1px solid var(--line);border-radius:6px;color:var(--faint);font:9px DM Mono,monospace}.research-result-row strong{font-size:14px}.empty-research{margin-top:18px;padding:14px;border:1px dashed var(--line-bright);border-radius:6px;color:var(--faint);font:10px DM Mono,monospace}.bottom-grid{grid-template-columns:1fr 1fr}.thesis-panel{background:linear-gradient(145deg,#243040e6,#0f1722f2)}.thesis-panel p,.ledger-panel p{margin-top:14px;color:var(--muted);font-size:12px;line-height:1.8}.thesis-rule{display:flex;align-items:center;gap:9px;margin-top:24px;color:var(--mint);font:10px DM Mono,monospace}.thesis-rule span{width:22px;height:1px;background:var(--mint)}.warning-tag{color:var(--amber);border-color:#e6b96c4d;background:var(--amber-soft)}.neutral-tag{color:var(--amber);border-color:#e6b96c40;background:var(--amber-soft)}.auth-form{display:grid;gap:10px;margin-top:16px}.auth-copy{color:var(--muted);font-size:11px;line-height:1.65}.paper-auth-warning{margin-top:14px;padding:9px 10px;border:1px solid rgba(230,185,108,.3);border-radius:5px;color:var(--amber);background:var(--amber-soft);font:10px DM Mono,monospace;line-height:1.55}.entry-form{display:grid;gap:10px;margin-top:16px}.selected-entry{display:flex;justify-content:space-between;gap:12px;align-items:center;color:var(--muted);font:10px DM Mono,monospace}.selected-entry strong{color:var(--text);font-size:13px}input{width:100%;padding:10px 11px;outline:none;border:1px solid var(--line-bright);border-radius:6px;color:var(--text);background:#0b1018b3;font:11px DM Mono,monospace}input:focus{border-color:var(--mint);box-shadow:0 0 0 3px #52d6bd17}.primary-button{color:#071411;border-color:var(--mint);background:var(--mint);font-weight:700}.primary-button:disabled{opacity:.5;cursor:wait}.empty-ledger{margin-top:18px;padding:14px;border:1px dashed var(--line-bright);border-radius:6px;color:var(--faint);font:10px DM Mono,monospace;text-align:center}.notice{margin-top:14px;padding:9px 10px;border-radius:5px;font:10px DM Mono,monospace}.notice-success{color:var(--mint);background:var(--mint-soft)}.notice-error{color:var(--red);background:var(--red-soft)}.state-card{margin-top:12px;padding:28px;border-radius:10px;color:var(--muted);font:12px DM Mono,monospace}.error-state{color:var(--red);border-color:#ef8b8b4d}@media(max-width:1040px){.sidebar{width:208px;flex-basis:208px}.kpi-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:760px){.app-shell{display:block}.sidebar{width:100%;min-height:auto;padding:15px 18px;border-right:0;border-bottom:1px solid var(--line)}.brand-lockup{padding:0}.nav-stack{display:flex;overflow-x:auto;margin-top:14px;gap:5px}.nav-item{flex:0 0 auto;padding:8px 10px;font-size:10px}.nav-glyph,.sidebar-footer{display:none}.content{padding:30px 16px 44px}.topbar{display:block;padding-bottom:25px}.topbar-meta{display:flex;justify-content:space-between;align-items:center;margin-top:18px;text-align:left}.hero-grid,.bottom-grid{grid-template-columns:1fr}.panel{padding:18px}.research-grid{grid-template-columns:1fr;gap:18px}.research-results{grid-template-columns:repeat(2,1fr)}}@media(max-width:500px){.kpi-grid{grid-template-columns:1fr 1fr;gap:7px}.kpi-card{min-height:112px;padding:14px}.kpi-value{font-size:22px}.kpi-foot{font-size:9px}.pulse-lead{display:block;margin:20px 0}.pulse-copy{display:block;margin-top:8px}.observation-row{grid-template-columns:1fr 55px;gap:8px}.observation-track{grid-column:1 / -1;grid-row:2}.observation-value{grid-column:2;grid-row:1}.lineage-item{display:block}.lineage-item strong{display:block;margin-top:5px;text-align:left}h1{font-size:31px}.subtitle{font-size:11px}} diff --git a/frontend/dist/index.html b/frontend/dist/index.html new file mode 100644 index 0000000..687cc4d --- /dev/null +++ b/frontend/dist/index.html @@ -0,0 +1,14 @@ + + + + + + + SET50 Signal Lab + + + + +
+ +