const{useState,useEffect,useRef,useCallback,useMemo}=React,VALVE_CHAMBER={MV:"LV",AV:"LV",TV:"RV",PV:"RV"},VIEW_PRESETS={front:{pos:[0,.6,12],target:[0,.3,0]},back:{pos:[0,.6,-12],target:[0,.3,0]},left:{pos:[11.5,.6,2],target:[0,.3,0]},right:{pos:[-11.5,.6,2],target:[0,.3,0]},apex:{pos:[0,-8,7],target:[0,-.5,0]},cor:{pos:[0,2.2,10.5],target:[0,.6,0]}},FOV_V=34,MIN_HFOV=20,AO_PULSE_REF=[STATES.normal.ao.dia,STATES.normal.ao.sys],ATRIAL_V_FOLLOWS={LA:"LV",RA:"RV"},BLOOD_ON=new URLSearchParams(location.search).get("blood")!=="0",VIEW_LABELS={front:["\u524D\u9762\u89C2","Anterior","Front"],back:["\u540E\u9762\u89C2","Posterior","Back"],left:["\u5DE6\u4FA7\u89C2","Left lateral","Left"],right:["\u53F3\u4FA7\u89C2","Right lateral","Right"],apex:["\u5FC3\u5C16\u89C2","Apical","Apex"],cor:["\u51A0\u72B6\u5207","Coronal","Coronal"]},VALVE_ZH={MV:"\u4E8C\u5C16\u74E3",TV:"\u4E09\u5C16\u74E3",AV:"\u4E3B\u52A8\u8109\u74E3",PV:"\u80BA\u52A8\u8109\u74E3"},VALVE_ZH_SHORT={MV:"\u4E8C\u5C16",TV:"\u4E09\u5C16",AV:"\u4E3B\u74E3",PV:"\u80BA\u74E3"},DISPLAY_MODES=[{id:"full",zh:"\u5B8C\u6574\u5916\u89C2",en:"Full"},{id:"transp",zh:"\u8154\u4F53\u900F\u89C6",en:"Cutaway"},{id:"cor",zh:"\u51A0\u72B6\u5207\u9762",en:"Coronal"}],SECTION_DEPTH_DEFAULT=1.2;function safeCycleFraction(Le){const c=Number(Le);return Number.isFinite(c)?Math.max(0,Math.min(.999999,c)):0}const PHASE_DETAIL=[{warn:"\u8003\u70B9:\u7B2C 1 \u65F6\u76F8\u5FC3\u623F\u6536\u7F29\u8D21\u732E\u8212\u5F20\u671F\u5145\u76C8\u91CF\u7684 ~20\u201325%;\u5FC3\u623F\u98A4\u52A8\u65F6\u8FD9\u90E8\u5206\u4E22\u5931,\u53EF\u89E3\u91CA\u5C04\u8840\u5206\u6570\u4FDD\u7559\u7684\u5FC3\u8870\uFF08HFpEF\uFF09\u60A3\u8005\u65B0\u53D1\u623F\u98A4\u540E\u5FC3\u8870\u6076\u5316\u3002",warnEn:"Exam point: atrial contraction (phase 1) supplies ~20\u201325% of diastolic filling; it is lost in AF, which is why new AF can tip HFpEF into decompensation.",ref:"\u4EBA\u536B\u300A\u751F\u7406\u5B66\u300B\u7B2C 9 \u7248",refEn:"PMPH Physiology, 9th ed."},{warn:"\u8003\u70B9:\u538B\u529B\u4E0A\u5347\u901F\u7387\u5CF0\u503C\uFF08dP/dt max\uFF09\u662F\u5E38\u7528\u7684\u6536\u7F29\u529B\u6307\u6807(\u53D7\u524D\u8D1F\u8377\u5F71\u54CD,\u66F4\u53EF\u9760\u7684\u662F\u6536\u7F29\u672B\u538B\u529B\u2013\u5BB9\u79EF\u5173\u7CFB\uFF08ESPVR\uFF09\u7684\u659C\u7387 Ees);\u5FC3\u8870\u65F6\u6B64\u671F\u5EF6\u957F\u3001dP/dt < 1000 mmHg/s\u3002",warnEn:"Exam point: dP/dt max is a common contractility index (load-dependent; the ESPVR slope Ees is more robust); in heart failure this phase lengthens and dP/dt < 1000 mmHg/s.",ref:"Guyton & Hall 14e"},{warn:"\u4E34\u5E8A:~70% \u7684\u6BCF\u640F\u91CF\u5728\u5C04\u8840\u671F\u524D 1/3 \u5C04\u51FA;\u4E3B\u52A8\u8109\u5CF0\u538B\u51B3\u5B9A\u540E\u8D1F\u8377,\u5F71\u54CD\u5DE6\u5BA4\u5BA4\u58C1\u5F20\u529B\u3002",warnEn:"Clinical: ~70% of the stroke volume leaves in the first third of ejection; peak aortic pressure sets afterload and LV wall stress.",ref:"Boron & Boulpaep 3e"},{warn:"\u8003\u70B9:\u5C04\u8840\u5206\u6570\uFF08EF\uFF09= \u6BCF\u640F\u91CF\uFF08SV\uFF09/ \u8212\u5F20\u672B\u5BB9\u79EF\uFF08EDV\uFF09;EF < 40% \u4E3A\u5C04\u8840\u5206\u6570\u964D\u4F4E\u7684\u5FC3\u8870\uFF08HFrEF\uFF09\u3002",warnEn:"Exam point: ejection fraction EF = SV / EDV; EF < 40% = HFrEF.",ref:"\u4EBA\u536B\u300A\u5185\u79D1\u5B66\u300B\u7B2C 9 \u7248",refEn:"PMPH Internal Medicine, 9th ed."},{warn:"\u8003\u70B9:\u7B2C\u4E8C\u5FC3\u97F3\uFF08S2\uFF09= \u4E3B\u52A8\u8109\u74E3 + \u80BA\u52A8\u8109\u74E3\u5173\u95ED;\u6DF1\u5438\u6C14\u65F6\u5206\u88C2\u4E3A\u4E3B\u52A8\u8109\u74E3\u6210\u5206\uFF08A2\uFF09\u4E0E\u80BA\u52A8\u8109\u74E3\u6210\u5206\uFF08P2\uFF09;\u56FA\u5B9A\u5206\u88C2\u63D0\u793A\u623F\u95F4\u9694\u7F3A\u635F\u3002",warnEn:"Exam point: S2 = aortic + pulmonary valve closure; A2\u2013P2 splits on deep inspiration; fixed splitting suggests ASD.",ref:"\u4EBA\u536B\u300A\u8BCA\u65AD\u5B66\u300B\u7B2C 9 \u7248",refEn:"PMPH Diagnostics, 9th ed."},{warn:"\u8003\u70B9:\u7B2C\u4E09\u5FC3\u97F3\uFF08S3\uFF09\u5728\u6B64\u671F\u51FA\u73B0,\u5E38\u89C1\u4E8E\u5FC3\u8870 / \u5BB9\u91CF\u8D1F\u8377\u8FC7\u91CD;\u513F\u7AE5\u4E0E\u5B55\u5987\u53EF\u751F\u7406\u6027\u5B58\u5728\u3002",warnEn:"Exam point: S3 occurs in this phase \u2014 common in heart failure and volume overload, physiological in children and pregnancy.",ref:"Braunwald 12e"},{warn:"\u8003\u70B9:\u6B64\u671F(75 \u6B21/\u5206\u65F6\u7EA6\u5360\u5468\u671F 37%)\u5728\u5FC3\u52A8\u8FC7\u901F\u65F6\u6700\u5148\u88AB\u538B\u7F29 \u2192 \u5145\u76C8\u4E0D\u8DB3;\u4E8C\u5C16\u74E3\u72ED\u7A84\u65F6\u672C\u5C31\u53D7\u9650,\u5FC3\u52A8\u8FC7\u901F\u6025\u5267\u6076\u5316\u3002\u62D6\u52A8\u5FC3\u7387\u6ED1\u5757\u53EF\u4EE5\u770B\u5230\u5B83\u53D8\u77ED\u3002",warnEn:"Exam point: this phase (~37% of the cycle at 75 BPM) is the first to shrink in tachycardia \u2192 underfilling; MS is already filling-limited and decompensates sharply with a fast rate. Drag the heart-rate slider to watch it shorten.",ref:"\u4EBA\u536B\u300A\u751F\u7406\u5B66\u300B\u7B2C 9 \u7248",refEn:"PMPH Physiology, 9th ed."}];function App(){const Le=useRef(null),c=useRef({}),k=useRef(null),Ae=useRef(null),rt=useRef(null),[Y,ke]=useState(!0),[f,it]=useState(75),[M,ot]=useState("normal"),[_,X]=useState(0),[ce,Te]=useState(!1),[j,It]=useState(()=>{const e=parseFloat(new URLSearchParams(location.search).get("speed"));return isFinite(e)?Math.max(.1,Math.min(1,e)):1}),[a,ct]=useState(()=>{const e=new URLSearchParams(location.search).get("lang");if(e==="en"||e==="zh")return e;try{const t=localStorage.getItem("heart3d.lang");if(t==="en"||t==="zh")return t}catch{}return"zh"});useEffect(()=>{document.title=a==="en"?"Heart3D \xB7 3D Cardiac Cycle":"Heart3D \xB7 \u4E09\u7EF4\u5FC3\u52A8\u5468\u671F",document.documentElement.lang=a==="en"?"en":"zh";try{localStorage.setItem("heart3d.lang",a)}catch{}},[a]);const[T,zt]=useState("full"),[le,Wt]=useState(SECTION_DEPTH_DEFAULT),[B,Bt]=useState(!0),[fe,Ut]=useState(1-TISSUE_OPACITY_DEFAULT),[ge,$t]=useState(BLOOD.clear),[q,De]=useState(null),[U,lt]=useState(null),[Fe,Gt]=useState(!1),[Oe,Zt]=useState("C"),[He,Yt]=useState(!1),[dt,ut]=useState(null),[Qe,_e]=useState(!1),[be,Ie]=useState(null),[Se,jt]=useState(0),[ze,We]=useState(!1),[Me,pt]=useState(!1),[de,Be]=useState({ready:!1,error:null}),[mt,Kt]=useState(null),ue=useRef(Y),ht=useRef(f),Ue=useRef(j),Pe=useRef(M),vt=useRef(BLOOD.clear),w=useRef(0),pe=useRef(0),ft=useRef(-1),$=useRef(T),$e=useRef(B);useEffect(()=>{$e.current=B},[B]),useEffect(()=>{ue.current=Y},[Y]),useEffect(()=>{ht.current=f},[f]),useEffect(()=>{Ue.current=j},[j]),useEffect(()=>{Pe.current=M},[M]),useEffect(()=>{$.current=T},[T]);const d=STATES[M],y=useMemo(()=>(setHeartRate(f),buildWiggersCurves(d,f)),[M,f]),J=useMemo(()=>ecgTiming(d,f),[d,f,y]),[we,Xt]=useState(null),gt=useRef(null),qt=useRef({beats:0,last:0,flash:0}),[ye,Jt]=useState("mitral"),Qt=useRef(null),ea=useRef({beats:0,last:0});useEffect(()=>{it(STATES[M].HR)},[M]);const bt=Math.round(d.forwardSV*f/10)/100,ee=useRef(y);useEffect(()=>{ee.current=y},[y]);const Ge=useMemo(()=>buildFlowCurves(d,f),[M,f]),wt=useRef(Ge);useEffect(()=>{wt.current=Ge},[Ge]),useEffect(()=>{const e=c.current&&c.current.blood;e&&e.setState(d)},[M]),useEffect(()=>{vt.current=ge;const e=c.current&&c.current.blood;e&&e.setClear(ge)},[ge]),useEffect(()=>{jt(e=>e+1)},[M]),useEffect(()=>{const e=Le.current,t=e.clientWidth,r=e.clientHeight,i=window.GFX||{mode:"webgl",tsl:!1};let u=!1,l=0,o=null,F=null,N=null;return(async()=>{o=i.tsl?new THREE.WebGPURenderer({antialias:!0,alpha:!0,stencil:!0}):new THREE.WebGLRenderer({antialias:!0,alpha:!0,stencil:!0}),o.init&&await o.init();const C=new OITPass(o);if(C.enabled=new URLSearchParams(location.search).get("oit")!=="0",u){o.dispose();return}N=new THREE.Scene,N.background=null,N.fog=new THREE.Fog(16777215,22,48);const R=new THREE.PerspectiveCamera(FOV_V,t/r,.1,100);R.position.set(...VIEW_PRESETS.front.pos),o.setPixelRatio(Math.min(window.devicePixelRatio,2)),o.setSize(t,r),o.shadowMap.enabled=!0,o.shadowMap.type=THREE.PCFShadowMap,o.toneMapping=THREE.ACESFilmicToneMapping,o.toneMappingExposure=1.1,e.appendChild(o.domElement);const G=new OrbitControls(R,o.domElement);G.enableDamping=!0,G.dampingFactor=.08,G.minDistance=5,G.maxDistance=26,G.maxPolarAngle=Math.PI*.95,G.target.set(...VIEW_PRESETS.front.target);const Et=new THREE.PMREMGenerator(o);N.environment=Et.fromScene(new RoomEnvironment,.04).texture,N.environmentIntensity=.55,Et.dispose();const z=new THREE.DirectionalLight(16773336,2.4);z.position.set(6,7,8),z.castShadow=!0,z.shadow.mapSize.set(2048,2048),z.shadow.camera.near=.5,z.shadow.camera.far=30,z.shadow.camera.left=-8,z.shadow.camera.right=8,z.shadow.camera.top=8,z.shadow.camera.bottom=-8,z.shadow.bias=-9e-4,N.add(z);const ua=new THREE.HemisphereLight(10404095,3809040,.7);N.add(ua);const Lt=new THREE.DirectionalLight(16756848,1.5);Lt.position.set(-7,4,-9),N.add(Lt);let O=null;loadHeart(new URLSearchParams(location.search).get("glb")||void 0,n=>Kt(Math.round(n*100))).then(n=>{if(O=n,N.add(n),c.current.heart=n,c.current.rig=buildSectionRig(n,Je),c.current.inset=createValveInset(n,N.environment),applyDisplayMode(n,$.current),Be({ready:!0,error:null}),!BLOOD_ON)return;const h=p=>{c.current.flow=buildFlowViz(n,p),c.current.flow.setMode($.current,$e.current)},E=new URLSearchParams(location.search).get("flow")||"assets/flow",H=new URLSearchParams(location.search).get("flip")||void 0,x=new URLSearchParams(location.search).get("fluid")==="1",m=new URLSearchParams(location.search);buildBlood(n,o,{base:E,flip:H,fluid:x,fluidSub:+m.get("fluidSub")||void 0,fluidCycles:+m.get("fluidCycles")||void 0,fluidVort:m.has("fluidVort")?+m.get("fluidVort"):void 0,fluidMac:m.get("fluidMac")==="0"?!1:void 0,fluidChambers:m.get("fluidChambers")?m.get("fluidChambers").split(",").map(p=>(p=p.trim(),/^(LV|LA|RV|RA)$/.test(p)?p+"_cavity":p)):void 0}).then(p=>{h(p.data.manifest),c.current.blood=p,Yt(!!p.fluid),p.setState(STATES[Pe.current]),p.setClear(vt.current),c.current.rig&&(p.attachSection(c.current.rig),p.setCapDepth(c.current.rig.depth)),p.setMode($.current,$e.current),p.setClipping($.current==="cor"?[Je]:null)}).catch(p=>{console.error("[blood] \u6D41\u573A\u8F7D\u5165\u5931\u8D25",p),c.current.flow||h(null)})}).catch(n=>{console.error("[heart] GLB \u8F7D\u5165\u5931\u8D25",n),Be({ready:!1,error:String(n&&n.message||n)})});const At=new THREE.Raycaster,Ke=new THREE.Vector2,pa=372,ma=334,ha=window.matchMedia("(max-width: 900px), (max-height: 520px)");function Xe(){const n=e.clientWidth,h=e.clientHeight;if(!n||!h)return;const H=!document.body.classList.contains("fs-mode")&&!ha.matches,x=H?pa:0,m=H&&document.querySelector(".drawer.open")?ma:0,p=te=>Math.tan(te*Math.PI/360),Ne=Math.max(1,n-x-m)/h;if(R.fov=Math.atan(Math.max(p(FOV_V),p(MIN_HFOV)/Ne))*360/Math.PI,!x&&!m)R.clearViewOffset(),R.aspect=n/h;else{const te=n+x-m;R.aspect=te/h,R.setViewOffset(te,h,x-m,0,n,h)}R.updateProjectionMatrix()}function St(){const n=e.clientWidth,h=e.clientHeight;!n||!h||(o.setSize(n,h),Xe())}window.addEventListener("resize",St),Xe();function Mt(n){if(!O)return;const h=Pt(n.clientX,n.clientY),E=h?{anatomy:h,x:n.clientX,y:n.clientY}:null;lt(E),o.domElement.style.cursor=E?"pointer":"grab"}function Pt(n,h){if(!O)return null;const E=o.domElement.getBoundingClientRect();Ke.x=(n-E.left)/E.width*2-1,Ke.y=-((h-E.top)/E.height)*2+1,At.setFromCamera(Ke,R);for(const H of At.intersectObjects(O.children,!0)){let x=!(H.object.material&&H.object.material.visible===!1);for(let p=H.object;x&&p&&p!==O;p=p.parent)if(!p.visible){x=!1;break}if(!x)continue;let m=H.object;for(;m&&!m.userData?.anatomy;)m=m.parent;if(m&&m.userData.anatomy&&ANATOMY[m.userData.anatomy])return m.userData.anatomy}return null}let Ve=null;function Ct(n){Ve=[n.clientX,n.clientY]}function Rt(n){if(Ve&&Math.hypot(n.clientX-Ve[0],n.clientY-Ve[1])>6)return;const h=Pt(n.clientX,n.clientY);h&&(De(ANATOMY[h]),lt(null))}o.domElement.addEventListener("pointerdown",Ct),o.domElement.addEventListener("pointermove",Mt),o.domElement.addEventListener("click",Rt);let qe=null;function xt(n,h=performance.now()){if(!e.clientWidth||!e.clientHeight)return;const E=STATES[Pe.current],H=60/ht.current,x=n*Ue.current;ue.current&&(w.current=safeCycleFraction(w.current)+x/H,w.current>=1&&(w.current-=1,pe.current+=1),w.current=safeCycleFraction(w.current),Math.floor(h/85)!==c.current.lastUiTick&&(c.current.lastUiTick=Math.floor(h/85),X(w.current)));const m=w.current,p=getPhaseIndex(m),Ne=qe!=null?(h-qe)/1e3:n;if(qe=h,k.current&&k.current.enabled){const g=n>0&&Ne>n?Ne/n:1,b=ue.current&&Ue.current>=.999;k.current.update(m,H*g,b,pe.current,Math.max(.15,1.5*Ne)),b&&p!==ft.current&&k.current.triggerPhaseEvents(p,E,`${pe.current}-${p}`)}if(ft.current=p,!O){G.update(),o.render(N,R);return}const te=O.userData.parts.chambers.userData,A=te.pivots,va=E.chamberMod;for(const g of["LV","RV","LA","RA"]){const b=A[g].scale.x,v=b+(va[g]-b)*Math.min(1,n*6);A[g].scale.set(v,v,v)}const Tt=ventricleContractionAt(m,E)*contractionAmplitude(E),et=atrialContractionAt(m),me=ee.current.AO,tt=m*me.length,ae=Math.min(me.length-1,Math.floor(tt)),Dt=Math.min(me.length-1,ae+1),Ft=me[ae]+(me[Dt]-me[ae])*(tt-ae),fa=Math.max(-1,Math.min(2,(Ft-AO_PULSE_REF[0])/(AO_PULSE_REF[1]-AO_PULSE_REF[0]))),at=ee.current.aoMin,Ot=ee.current.aoMax,ga=Ot>at?(Ft-at)/(Ot-at):0,nt=ee.current.RA,st=ee.current.raMin,Ht=ee.current.raMax,Qa=nt[ae]+(nt[Dt]-nt[ae])*(tt-ae),he=E.venous||{ra:[0,1],pv:[0,1]},ba=he.ra[0]+(he.ra[1]-he.ra[0])*(Ht>st?(Qa-st)/(Ht-st):0),wa=he.pv[0]+(he.pv[1]-he.pv[0])*Math.max(0,Math.min(1,(et+1)/2)),Ee=Math.min(1,x*18);O.traverse(g=>{const b=g.morphTargetInfluences,v=g.morphTargetDictionary;if(!b||!v||g.userData.stencilWriter||g.userData.morphFollower)return;const ne=["LV","RV","LA","RA"].find(S=>A[S]&&g.parent===A[S]),Z=ne?A[ne].scale.x:1;if(g.name.includes("_leaflet_"))return;const se=ATRIAL_V_FOLLOWS[ne],_t=se&&A[se]?A[se].scale.x/Z:1;if(v.V!==void 0&&(b[v.V]+=(Tt*_t-b[v.V])*Ee),v.A!==void 0&&(b[v.A]+=(et-b[v.A])*Ee),v.V_LA!==void 0){const S=A.LV?A.LV.scale.x/Z:1;b[v.V_LA]+=(Tt*S-b[v.V_LA])*Ee}if(v.A_LA!==void 0){const S=A.LA?A.LA.scale.x/Z:1;b[v.A_LA]+=(et*S-b[v.A_LA])*Ee}if(v.P!==void 0){const S=g.name==="PA"?ga:g.name==="SVC"||g.name==="IVC"?ba:g.name==="PULM_VEINS"?wa:fa;b[v.P]+=(S-b[v.P])*Ee}for(const S of["LV","RV","LA","RA"]){const K=v["S_"+S];K!==void 0&&A[S]&&(b[K]=(A[S].scale.x-1)/SCALE_KEY_STEP/Z)}});const ya=O.userData.parts.valves.userData.valves;for(const g of["MV","TV","AV","PV"]){const b=valveOpenAt(m,E,g),v=ya[g],ne=te.walls[VALVE_CHAMBER[g]],Z=A[VALVE_CHAMBER[g]],se=ne&&ne.morphTargetDictionary,S=se&&se.V!==void 0?ne.morphTargetInfluences[se.V]:0,K=v.userData.affine;if(K&&Z){const V=(L,D)=>L===D?1:0,Q=[],W=[0,0,0];for(let L=0;L<3;L++)for(let D=0;D<3;D++)Q.push(V(L,D)+S*(K.A[L*3+D]-V(L,D)));if(["x","y","z"].forEach((L,D)=>{W[D]=S*K.t[L]}),K.S)for(const{k:L,A:D,t:re}of K.S){const ve=A[L]?(A[L].scale.x-1)/SCALE_KEY_STEP:0;if(ve){for(let ie=0;ie<3;ie++)for(let oe=0;oe<3;oe++)Q[ie*3+oe]+=ve*(D[ie*3+oe]-V(ie,oe));["x","y","z"].forEach((ie,oe)=>{W[oe]+=ve*re[ie]})}}else{const L=Z.scale.x,D=Z.position;for(let re=0;re<9;re++)Q[re]*=L;["x","y","z"].forEach((re,ve)=>{W[ve]=L*W[ve]+(1-L)*D[re]})}v.matrix.set(Q[0],Q[1],Q[2],W[0],Q[3],Q[4],Q[5],W[1],Q[6],Q[7],Q[8],W[2],0,0,0,1),v.matrixWorldNeedsUpdate=!0}for(const V of v.userData.leaflets){const Q=V.morphTargetDictionary;Q&&Q.V!==void 0&&(V.morphTargetInfluences[Q.V]=S);for(const W of["LV","RV","LA","RA"]){const L=Q&&Q["S_"+W];L!==void 0&&(V.morphTargetInfluences[L]=A[W]?(A[W].scale.x-1)/SCALE_KEY_STEP:0)}Q&&Q.SV!==void 0&&(V.morphTargetInfluences[Q.SV]=(Z.scale.x-1)/SCALE_KEY_STEP*S),V.userData.open+=(b-V.userData.open)*Math.min(1,x*18),setLeafletOpen(V,V.userData.open)}const Na=(E.calcified||[]).includes(g);for(const V of v.userData.leaflets)V.material.color.setHex(Na?COL.valveCalc:COL.valveHealthy)}O.userData.parts.chambers.userData.walls.LV.material.color.setHex(E.myoDark?COL.myoDark:COL.myocardium),c.current.blood&&c.current.blood.update(m,ue.current?x:0,wt.current),c.current.blood&&c.current.blood.preRender(N,R),yt.current&&(O.rotation.y+=n*.3),c.current.rig&&$.current==="cor"&&c.current.rig.update(),G.update(),C.enabled&&$.current==="transp"?C.render(N,R,O):o.render(N,R),c.current.inset&&c.current.inset.render(o)}let Vt=performance.now();function kt(n){l=requestAnimationFrame(kt);const h=Math.min(.05,(n-Vt)/1e3);Vt=n,xt(h,n)}l=requestAnimationFrame(kt);const Je=new THREE.Plane(new THREE.Vector3(0,0,-1),0);c.current={scene:N,camera:R,renderer:o,controls:G,heart:null,raf:l,clipPlane:Je,lastUiTick:0,stepFrame:xt,applyViewOffset:Xe,oit:C},["localhost","127.0.0.1",""].includes(location.hostname)&&(c.current.getCycleT=()=>w.current,c.current.setCycleT=n=>{w.current=safeCycleFraction(n)},c.current.seek=n=>{w.current=safeCycleFraction(n),X(w.current)},c.current.cycles=()=>pe.current+w.current,c.current.freeze=n=>{ue.current=!n},window.__ctx=c.current),F={onResize:St,onPointerMove:Mt,onPointerDown:Ct,onClick:Rt}})().catch(C=>{console.error("[renderer] \u521D\u59CB\u5316\u5931\u8D25",C),Be({ready:!1,error:String(C&&C.message||C)})}),()=>{u=!0,cancelAnimationFrame(l),F&&(window.removeEventListener("resize",F.onResize),o.domElement.removeEventListener("pointermove",F.onPointerMove),o.domElement.removeEventListener("pointerdown",F.onPointerDown),o.domElement.removeEventListener("click",F.onClick)),o&&o.dispose(),N&&N.traverse(C=>{C.geometry&&C.geometry.dispose(),C.material&&(Array.isArray(C.material)?C.material.forEach(R=>R.dispose()):C.material.dispose())}),o&&e.contains(o.domElement)&&e.removeChild(o.domElement)}},[]);const ta=useRef(null);useEffect(()=>{ta.current=U},[U]);const yt=useRef(!1);useEffect(()=>{yt.current=Fe},[Fe]),useEffect(()=>{const e=c.current;if(!e||!e.heart)return;applyDisplayMode(e.heart,T,{tissueOpacity:1-fe}),e.flow&&e.flow.setMode(T,B);const t=T==="cor";e.blood&&(e.blood.setMode(T,B),e.blood.setClipping(t?[e.clipPlane]:null)),e.renderer.clippingPlanes=[],e.renderer.localClippingEnabled=t;const r=e.heart.userData.clipGroup;r?(r.enabled=t,r.clippingPlanes=t?[e.clipPlane]:[],r.clipShadows=t):e.heart.traverse(i=>{if(i.material&&!i.userData.stencilWriter&&!i.userData.sectionCap){const u=Array.isArray(i.material)?i.material:[i.material];for(const l of u)l.clippingPlanes=t?[e.clipPlane]:null,l.clipShadows=t,l.needsUpdate=!0}}),e.rig&&e.rig.setEnabled(t)},[T,de.ready]),useEffect(()=>{const e=c.current;e&&e.heart&&T==="transp"&&setTissueOpacity(e.heart,1-fe)},[fe]),useEffect(()=>{const e=c.current;e&&e.blood&&He&&e.blood.setFluidOn(Oe==="C")},[Oe,He]),useEffect(()=>{const e=c.current;e&&e.flow&&e.flow.setMode($.current,B),e&&e.blood&&e.blood.setMode($.current,B)},[B]),useEffect(()=>{const e=c.current;e&&e.rig&&e.rig.setDepth(le),e&&e.blood&&e.blood.setCapDepth(le)},[le,de.ready]),useEffect(()=>{k.current||(k.current=new HeartAudio,k.current.setState(Pe.current),window.__ctx&&(window.__ctx.audio=k.current)),k.current.setEnabled(ce)},[ce]),useEffect(()=>{k.current&&k.current.setState(M)},[M]),useEffect(()=>{k.current&&k.current.setSite(ye)},[ye,ce]),useEffect(()=>{const e=Ae.current;if(!e)return;const t=Math.min(window.devicePixelRatio,2);e.width=WIG_W*t,e.height=WIG_H*t,e.style.width=WIG_W+"px",e.style.height=WIG_H+"px";const r=e.getContext("2d");drawWiggers(r,t,y,safeCycleFraction(_),d,dt,a)},[_,y,d,dt,a]),useEffect(()=>{const e=gt.current;if(!e)return;const t=e.clientWidth,r=e.clientHeight;if(!t||!r)return;const i=Math.min(window.devicePixelRatio,2);(e.width!==Math.round(t*i)||e.height!==Math.round(r*i))&&(e.width=Math.round(t*i),e.height=Math.round(r*i));const u=safeCycleFraction(_),l=qt.current;u<l.last-.5&&(l.beats+=1,l.flash=1),l.last=u,l.flash=Math.max(0,l.flash-.06),drawEcgMonitor(e.getContext("2d"),i,t,r,{T:J,tAbs:l.beats+u,lang:a,activeWave:we,flash:l.flash})},[_,J,a,we,Me]),useEffect(()=>{const e=Qt.current;if(!e)return;const t=e.clientWidth,r=e.clientHeight;if(!t||!r)return;const i=Math.min(window.devicePixelRatio,2);(e.width!==Math.round(t*i)||e.height!==Math.round(r*i))&&(e.width=Math.round(t*i),e.height=Math.round(r*i));const u=safeCycleFraction(_),l=ea.current;u<l.last-.5&&(l.beats+=1),l.last=u,drawAuscMonitor(e.getContext("2d"),i,t,r,{stateId:M,siteId:ye,tAbs:l.beats+u,hr:f,lang:a})},[_,M,ye,f,a,y,Me]),useEffect(()=>{const e=rt.current;if(!e)return;const t=Math.min(window.devicePixelRatio,2);e.width=PV_W*t,e.height=PV_H*t,e.style.width=PV_W+"px",e.style.height=PV_H+"px";const r=e.getContext("2d");drawPVLoop(r,t,d,safeCycleFraction(_),a)},[_,d,a]);const Ze=e=>{const t=Ae.current;if(!t)return;const r=t.getBoundingClientRect(),i=e.clientX-r.left,u=PAD_L,l=WIG_W-PAD_R,o=Math.max(0,Math.min(.999,(i-u)/(l-u))),F=getPhaseIndex(o);ut(F),Qe&&(w.current=o,X(o))},aa=e=>{ke(!1),_e(!0),Ze(e)},na=()=>_e(!1),sa=e=>{if(Qe)return;const r=Ae.current.getBoundingClientRect(),i=e.clientX-r.left,u=PAD_L,l=WIG_W-PAD_R,o=Math.max(0,Math.min(.999,(i-u)/(l-u))),F=getPhaseIndex(o);Ie({phase:F,x:e.clientX,y:e.clientY})};useEffect(()=>{if(!Qe)return;const e=()=>_e(!1),t=r=>Ze(r);return window.addEventListener("mouseup",e),window.addEventListener("mousemove",t),()=>{window.removeEventListener("mouseup",e),window.removeEventListener("mousemove",t)}},[Qe]),useEffect(()=>{const e=t=>{if(t.target.tagName==="INPUT"||t.target.tagName==="TEXTAREA")return;t.code==="Space"&&(t.preventDefault(),ke(u=>!u)),t.code==="KeyL"&&Te(u=>!u),t.code==="KeyF"&&We(u=>!u),t.code==="Escape"&&(De(null),Ie(null),We(!1)),t.code==="KeyR"&&(w.current=0,X(0),pe.current=0);const r=/^Digit([0-9])$/.exec(t.code),i=r?r[1]==="0"?10:parseInt(r[1],10):t.code==="Minus"?11:t.code==="Equal"?12:0;if(i&&!(t.ctrlKey||t.metaKey||t.altKey)){const l=Object.keys(STATES)[i-1];l&&ot(l)}if((t.code==="ArrowLeft"||t.code==="ArrowRight")&&!ue.current){const u=getPhaseIndex(w.current),l=t.code==="ArrowLeft"?(u+6)%7:(u+1)%7,o=PHASE_BOUNDS[l]+.001;w.current=o,X(o)}};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[]);const ra=e=>{const t=c.current;if(!t)return;const{pos:r,target:i}=VIEW_PRESETS[e];t.camera.position.set(...r),t.controls.target.set(...i),t.controls.update()},Ce=safeCycleFraction(_),Re=getPhaseIndex(Ce),I=PHASES[Re],ia=60/f,Nt=PHASE_BOUNDS[Re],oa=PHASE_BOUNDS[Re+1],ca=Math.max(0,Math.min(1,(Ce-Nt)/(oa-Nt))),Ye=useMemo(()=>{const e=safeCycleFraction(_),t=Math.max(0,Math.min(199,Math.floor(e*200))),r=Math.min(199,t+1),i=Math.max(0,Math.min(1,e*200-t));return{LA:y.LA[t]*(1-i)+y.LA[r]*i,LV:y.LV[t]*(1-i)+y.LV[r]*i,AO:y.AO[t]*(1-i)+y.AO[r]*i}},[_,y]);useEffect(()=>{const e=document.querySelector(".loading");e&&e.remove()},[]),useEffect(()=>{document.body.classList.toggle("fs-mode",ze),c.current.applyViewOffset?.()},[ze,q]);const P=(e,t)=>a==="en"?t:e,s=(e,t)=>a==="en"?t:e,la=e=>String(e).split(/\*\*(.+?)\*\*/g).map((t,r)=>r%2?React.createElement("b",{key:r},t):t),da=Math.round(Ce*100),je=He&&React.createElement("div",{style:{marginTop:8}},React.createElement("div",{className:"ctrl-label"},a==="en"?"Blood":"\u8840\u6DB2"),React.createElement("div",{className:"row",style:{gap:4}},[{id:"A",zh:"A \u9884\u7B97\u6D41\u5411",en:"A Pre-baked",tipZh:"\u5FC3\u8154\u91CC\u7684\u8840\u6309\u9884\u5148\u70D8\u597D\u7684\u6D41\u5411\u8D70\uFF1A\u8840\u7EC6\u80DE\u6D41\u7EBF + \u5747\u5300\u7684\u6D53\u8840",tipEn:"Blood follows a pre-baked flow field: cell streaks + uniform thick blood"},{id:"C",zh:"C \u5B9E\u65F6\u6DB2\u4F53",en:"C Live fluid",tipZh:"\u56DB\u4E2A\u5FC3\u8154\u548C\u4E94\u6761\u5927\u8840\u7BA1\u91CC\u7684\u8840\u6BCF\u5E27\u5728\u6D4F\u89C8\u5668\u91CC\u6309\u4E0D\u53EF\u538B\u7F29\u6D41\u5B9E\u65F6\u8BA1\u7B97\uFF1A\u4EAE\u7EA2 = \u521A\u6D41\u8FDB\u6765\u7684\u65B0\u8840\uFF0C\u6697\u7EA2 = \u7559\u7740\u7684\u8001\u8840\uFF1B\u6D41\u7EBF\u662F\u6DB2\u4F53\u91CC\u7684\u8840\u7EC6\u80DE\uFF0C\u4E0E\u6DB2\u4F53\u540C\u901F\u3002\u6CA1\u6709\u4EFB\u4F55\u9884\u5148\u7B97\u597D\u7684\u6D41\u5411\uFF08\u51A0\u8109\u91CC\u7684\u5C0F\u9897\u7C92\u5C5E\u4E8E A\uFF0CC \u91CC\u4E0D\u753B\uFF09",tipEn:"Blood in the four chambers and five great vessels is solved live every frame as an incompressible fluid: bright red = just entered, dark red = stayed; streaks are cells moving with the fluid. Nothing pre-baked (coronary dots belong to A and are hidden in C)"}].map(e=>React.createElement("button",{key:e.id,className:`btn tiny ${Oe===e.id?"primary":"ghost"}`,style:{flex:1},title:s(e.tipZh,e.tipEn),onClick:()=>Zt(e.id)},a==="en"?e.en:e.zh))),React.createElement("div",{style:{fontSize:9.5,color:"var(--ink-mute)",marginTop:4}},s(`B\uFF08WebGPU\uFF09\u662F\u753B\u56FE\u901A\u9053\uFF0C\u4E0D\u662F\u53E6\u4E00\u79CD\u8840\uFF1B\u73B0\u5728\u7528 ${window.GFX&&window.GFX.tsl?"WebGPU":"WebGL"}`,`B (WebGPU) is a drawing backend, not another kind of blood; now using ${window.GFX&&window.GFX.tsl?"WebGPU":"WebGL"}`)));return React.createElement(React.Fragment,null,React.createElement("div",{ref:Le,style:{position:"fixed",inset:0,zIndex:1,cursor:"grab"}}),!de.ready&&React.createElement("div",{className:"model-status glass"},de.error?React.createElement(React.Fragment,null,React.createElement("div",{className:"t err"},"\u26A0 ",P("\u5FC3\u810F\u6A21\u578B\u8F7D\u5165\u5931\u8D25","Failed to load the heart model")),React.createElement("div",{className:"d"},de.error),React.createElement("div",{className:"d"},P("\u9700\u8981","Requires")," ",React.createElement("code",null,"assets/heart.glb"),P("\u3002\u91CD\u65B0\u751F\u6210\uFF1A",". Rebuild with:"),React.createElement("br",null),React.createElement("code",null,"blender --background --factory-startup --python blender/build_heart.py"))):React.createElement(React.Fragment,null,React.createElement("div",{className:"t"},P("\u6B63\u5728\u8F7D\u5165\u5FC3\u810F\u6A21\u578B\u2026","Loading the heart model\u2026"),mt!=null?` ${mt}%`:""),React.createElement("div",{className:"d"},"assets/heart.glb"))),React.createElement("div",{className:"topbar"},React.createElement("div",{className:"title-card glass"},React.createElement("h1",null,"Heart3D"),React.createElement("p",{className:"sub"},s("\u4EA4\u4E92\u5F0F\u4E09\u7EF4\u5FC3\u52A8\u5468\u671F \xB7 v2.0","INTERACTIVE 3D CARDIAC CYCLE \xB7 v2.0"))),React.createElement("div",{className:"badges"},React.createElement("div",{className:"badge glass lang",title:a==="en"?"\u5207\u6362\u4E3A\u5168\u4E2D\u6587\u754C\u9762":"Switch to the all-English interface"},["zh","en"].map(e=>React.createElement("button",{key:e,className:`btn tiny ${a===e?"primary":"ghost"}`,onClick:()=>ct(e)},e==="zh"?"\u4E2D\u6587":"English"))),React.createElement("div",{className:"badge glass bpm",key:`bpm-${Se}`},React.createElement("span",{className:"dot",style:{animation:`heartpulse ${ia}s ease-in-out infinite`}}),s("\u5FC3\u7387","BPM")," ",React.createElement("span",{className:"v gold-pulse"},f)),React.createElement("div",{className:"badge glass state",key:`st-${Se}`},s("\u72B6\u6001","STATE")," ",React.createElement("span",{className:"v gold-pulse"},a==="en"?d.en:d.zh)),React.createElement("div",{className:"badge glass",key:`ef-${Se}`},s("\u5C04\u8840\u5206\u6570","EF")," ",React.createElement("span",{className:"v gold-pulse",style:{color:"var(--gold)",fontWeight:700}},d.EF,"%")),React.createElement("div",{className:"badge glass",key:`co-${Se}`,title:d.regurgFrac>0?s("\u53CD\u6D41\u72B6\u6001\u4E0B\u8FD9\u91CC\u663E\u793A\u7684\u662F\u524D\u5411\u5FC3\u8F93\u51FA\u91CF\uFF08\u771F\u6B63\u6CF5\u5411\u4F53\u5FAA\u73AF\u7684\u91CF\uFF09\uFF1B\u6309\u5F53\u524D\u5FC3\u7387\u8BA1\u7B97","With regurgitation this is the forward CO (what actually reaches the systemic circulation); computed at the current heart rate"):s("\u6309\u5F53\u524D\u5FC3\u7387\u8BA1\u7B97\uFF1A\u524D\u5411\u6BCF\u640F\u91CF \xD7 \u5FC3\u7387","Computed at the current heart rate: forward SV \xD7 HR")},s("\u5FC3\u8F93\u51FA\u91CF","CO")," ",React.createElement("span",{className:"v gold-pulse",style:{color:"var(--gold)",fontWeight:700}},bt.toFixed(2)),d.regurgFrac>0&&React.createElement("span",{style:{fontSize:9,color:"var(--ink-mute)"}},s("\u524D\u5411","fwd"))))),React.createElement("div",{className:"phase-hud glass-strong glass"},React.createElement("div",{className:"ph-num"},I.id+1),React.createElement("div",{className:"ph-name"},React.createElement("div",{className:"zh"},a==="en"?I.en:I.zh),React.createElement("div",{className:"en"},a==="en"?`${I.shortEn} \xB7 `:"",I.pct,"% \xB7 ",(ca*100).toFixed(0),"%")),React.createElement("div",{className:"ph-event"},a==="en"?I.eventEn:I.event),React.createElement("div",{className:"ph-valves"},["MV","TV","AV","PV"].map(e=>React.createElement("div",{key:e,className:`ph-valve ${I.valves[e]}`,title:s(VALVE_ZH[e],e)},React.createElement("div",{className:"vdot"}),a==="en"?e:VALVE_ZH_SHORT[e]))),React.createElement("div",{className:"ph-pressure"},React.createElement("div",{className:"row"},React.createElement("span",{className:"lbl"},s("\u5DE6\u5BA4","LV")),React.createElement("span",{className:"val"},Ye.LV.toFixed(0))),React.createElement("div",{className:"row"},React.createElement("span",{className:"lbl"},s("\u5DE6\u623F","LA")),React.createElement("span",{className:"val"},Ye.LA.toFixed(0))),React.createElement("div",{className:"row"},React.createElement("span",{className:"lbl"},s("\u4E3B\u52A8\u8109","AO")),React.createElement("span",{className:"val"},Ye.AO.toFixed(0))))),React.createElement("div",{className:"sig-mark","aria-hidden":"true"},React.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"-93.72 -840.72 3521.44 1413.44",role:"img","aria-label":"Chen Yigeng"},React.createElement("path",{fill:"currentColor",d:"M67 14Q128 14 312 -110L379 -152Q386 -156 394.0 -156.0Q402 -156 402.0 -154.0Q402 -152 399 -150L327 -106Q315 -98 271.0 -68.5Q227 -39 206.0 -26.0Q185 -13 151 6Q87 43 46 43Q-18 43 -18 -53Q-18 -116 20.0 -204.0Q58 -292 126.5 -383.0Q195 -474 280.5 -553.0Q366 -632 472.5 -682.5Q579 -733 680 -733Q735 -733 735 -691Q735 -641 668.0 -554.5Q601 -468 512.5 -400.0Q424 -332 371 -332Q347 -332 347 -346Q347 -356 368.5 -378.5Q390 -401 403 -401Q407 -401 407.0 -397.5Q407 -394 394.5 -382.5Q382 -371 382.0 -367.5Q382 -364 384 -364Q414 -364 496.0 -426.0Q578 -488 650.0 -567.5Q722 -647 722 -688Q722 -721 672 -721Q586 -721 489.5 -669.5Q393 -618 312.0 -537.5Q231 -457 164.5 -366.0Q98 -275 60.0 -189.0Q22 -103 22.0 -44.5Q22 14 67 14ZM647 -426 502 -257Q581 -310 745.0 -477.0Q909 -644 909 -676Q909 -681 904.0 -681.0Q899 -681 893 -678Q828 -642 735 -531Q731 -527 693.5 -481.5Q656 -436 647 -426ZM933 -687Q933 -640 759.5 -467.5Q586 -295 469 -218L453 -199Q428 -176 352 -74Q346 -64 346.0 -63.0Q346 -62 347.5 -62.0Q349 -62 359.0 -68.5Q369 -75 434 -122Q584 -231 653 -265Q659 -267 661 -267Q672 -267 672.0 -248.5Q672 -230 643.0 -191.5Q614 -153 579 -120Q485 -31 485 -20Q485 -14 489 -14Q545 -32 587 -57L685 -119L686 -106Q581 -36 529.5 -17.0Q478 2 463.5 2.0Q449 2 449 -7Q449 -25 500.0 -79.0Q551 -133 601.5 -184.5Q652 -236 652 -246Q652 -248 649 -248Q636 -248 525.0 -173.0Q414 -98 358.5 -55.5Q303 -13 297.0 -6.5Q291 0 266 3Q256 3 256.0 -2.0Q256 -7 270 -26Q342 -114 502.0 -300.5Q662 -487 674.0 -498.5Q686 -510 708.5 -533.0Q731 -556 748.5 -573.5Q766 -591 793.5 -616.5Q821 -642 841 -659Q892 -701 916 -701Q923 -701 928.0 -696.5Q933 -692 933 -687ZM903 -257Q903 -260 899 -260Q872 -260 815.0 -213.0Q758 -166 716 -110Q766 -126 834.5 -182.0Q903 -238 903 -257ZM672 -21Q672 -8 682 -8Q694 -8 736.0 -24.5Q778 -41 805 -57L903 -119L904 -106Q799 -36 747.5 -17.0Q696 2 679 2Q651 2 651 -33Q651 -80 685.0 -127.0Q719 -174 764.5 -204.0Q810 -234 852.5 -253.0Q895 -272 917.0 -272.0Q939 -272 939 -257Q939 -220 851.5 -167.0Q764 -114 706 -97Q672 -48 672 -21ZM892 -98 889 -110 922 -131Q997 -181 1016.0 -201.5Q1035 -222 1039 -227Q1065 -260 1068 -264Q1080 -260 1080 -240Q1060 -211 1026.0 -170.5Q992 -130 970.0 -103.5Q948 -77 948.0 -73.0Q948 -69 949.5 -69.0Q951 -69 964.5 -79.5Q978 -90 1038 -132Q1159 -216 1192.0 -238.5Q1225 -261 1234.5 -261.0Q1244 -261 1244.0 -241.5Q1244 -222 1214.0 -183.0Q1184 -144 1148 -111Q1052 -23 1052 -14Q1052 -13 1056 -13Q1068 -13 1191 -92L1232 -119L1233 -106Q1072 1 1037 1Q1031 1 1031 -5Q1031 -42 1077.5 -92.5Q1124 -143 1170.0 -183.5Q1216 -224 1216 -237Q1216 -239 1214 -239Q1185 -225 1079.5 -150.5Q974 -76 956 -63Q909 -28 906.5 -26.5Q904 -25 896 -16Q878 3 863 3Q839 1 838 0Q837 -1 837 -2Q837 -3 854 -21Q870 -38 886 -55Q939 -114 959 -139ZM1308 466Q1378 465 1760 -11Q1566 124 1436.0 251.0Q1306 378 1306 463Q1306 466 1308 466ZM1451 -405 1445 -396Q1445 -392 1452 -392Q1505 -392 1566.0 -408.0Q1627 -424 1676 -446Q1778 -493 1830 -530L1852 -546L1864 -558Q1876 -571 1893.0 -589.0Q1910 -607 1932.0 -629.5Q1954 -652 1974 -672Q2008 -708 2041.0 -736.5Q2074 -765 2091 -765Q2097 -765 2102.5 -761.0Q2108 -757 2108.0 -749.5Q2108 -742 2069.5 -702.5Q2031 -663 1977.5 -611.5Q1924 -560 1891.0 -523.0Q1858 -486 1808.5 -417.0Q1759 -348 1759 -315Q1759 -308 1769 -308Q1869 -308 2146 -520Q2230 -632 2262.0 -667.0Q2294 -702 2319.5 -724.0Q2345 -746 2358.5 -753.0Q2372 -760 2379.0 -760.0Q2386 -760 2391.0 -755.0Q2396 -750 2396.0 -746.0Q2396 -742 2389 -732Q2366 -696 2312 -652Q2304 -644 2211.0 -526.5Q2118 -409 2099 -385Q2019 -276 1885 -109Q2112 -253 2128 -253Q2133 -253 2133.0 -248.0Q2133 -243 2125 -238Q2028 -189 1863 -81Q1741 69 1635.5 188.5Q1530 308 1427.0 402.5Q1324 497 1282 497Q1277 497 1272.0 490.5Q1267 484 1267 479Q1267 428 1313.0 360.5Q1359 293 1438 222Q1582 92 1787 -45Q1975 -282 2111 -471Q1848 -293 1764 -293Q1738 -293 1738 -319Q1738 -365 1802 -470L1824 -505Q1824 -507 1821 -507L1794 -490Q1776 -480 1724.0 -454.0Q1672 -428 1622.5 -408.5Q1573 -389 1508.0 -372.5Q1443 -356 1391 -356Q1373 -356 1373 -367Q1373 -384 1402.0 -397.0Q1431 -410 1441.0 -410.0Q1451 -410 1451 -405ZM2283.0 -333.0Q2266 -333 2266.0 -348.5Q2266 -364 2281.0 -378.0Q2296 -392 2306.5 -392.0Q2317 -392 2322.5 -386.0Q2328 -380 2328.0 -372.0Q2328 -364 2314.0 -348.5Q2300 -333 2283.0 -333.0ZM2030 -17Q2041 -42 2118.5 -131.0Q2196 -220 2236 -260Q2242 -268 2242.0 -271.5Q2242 -275 2234 -276L2211 -278Q2203 -278 2196 -270Q2128 -201 2067.5 -119.5Q2007 -38 2007.0 -18.5Q2007 1 2019 1Q2035 1 2084.0 -25.5Q2133 -52 2174 -79L2215 -106L2214 -119Q2053 -13 2035 -13Q2030 -13 2030 -17ZM2352 -118Q2369 -131 2418.0 -187.0Q2467 -243 2467 -252Q2467 -256 2459 -256Q2388 -256 2297.0 -172.5Q2206 -89 2206 -30Q2206 -24 2212.0 -24.0Q2218 -24 2231.5 -31.5Q2245 -39 2264.5 -52.5Q2284 -66 2297 -76Q2346 -112 2352 -118ZM1966 344Q1978 344 2140 150L2194 86Q2194 84 2192 84Q2124 133 2065.0 184.5Q2006 236 1984.5 271.0Q1963 306 1963 338Q1963 344 1966 344ZM2322 -13Q2339 -13 2463 -92L2505 -118L2506 -106Q2442 -62 2386 -32L2295 15Q2216 122 2097.5 244.5Q1979 367 1958.0 367.0Q1937 367 1937 353Q1937 280 2047 184Q2087 149 2149.0 103.5Q2211 58 2225 47Q2248 19 2273 -11Q2327 -74 2331 -80Q2331 -82 2327.5 -82.0Q2324 -82 2269 -42Q2215 -2 2198.5 -2.0Q2182 -2 2182 -32Q2182 -115 2276.5 -194.0Q2371 -273 2504 -273Q2515 -273 2515 -261Q2332 -31 2322 -13ZM2723 -257Q2723 -260 2719 -260Q2692 -260 2635.0 -213.0Q2578 -166 2536 -110Q2586 -126 2654.5 -182.0Q2723 -238 2723 -257ZM2492 -21Q2492 -8 2502 -8Q2514 -8 2556.0 -24.5Q2598 -41 2625 -57L2723 -119L2724 -106Q2619 -36 2567.5 -17.0Q2516 2 2499 2Q2471 2 2471 -33Q2471 -80 2505.0 -127.0Q2539 -174 2584.5 -204.0Q2630 -234 2672.5 -253.0Q2715 -272 2737.0 -272.0Q2759 -272 2759 -257Q2759 -220 2671.5 -167.0Q2584 -114 2526 -97Q2492 -48 2492 -21ZM2712 -98 2709 -110 2742 -131Q2817 -181 2836.0 -201.5Q2855 -222 2859 -227Q2885 -260 2888 -264Q2900 -260 2900 -240Q2880 -211 2846.0 -170.5Q2812 -130 2790.0 -103.5Q2768 -77 2768.0 -73.0Q2768 -69 2769.5 -69.0Q2771 -69 2784.5 -79.5Q2798 -90 2858 -132Q2979 -216 3012.0 -238.5Q3045 -261 3054.5 -261.0Q3064 -261 3064.0 -241.5Q3064 -222 3034.0 -183.0Q3004 -144 2968 -111Q2872 -23 2872 -14Q2872 -13 2876 -13Q2888 -13 3011 -92L3052 -119L3053 -106Q2892 1 2857 1Q2851 1 2851 -5Q2851 -42 2897.5 -92.5Q2944 -143 2990.0 -183.5Q3036 -224 3036 -237Q3036 -239 3034 -239Q3005 -225 2899.5 -150.5Q2794 -76 2776 -63Q2729 -28 2726.5 -26.5Q2724 -25 2716 -16Q2698 3 2683 3Q2659 1 2658 0Q2657 -1 2657 -2Q2657 -3 2674 -21Q2690 -38 2706 -55Q2759 -114 2779 -139ZM3189 -118Q3206 -131 3255.0 -187.0Q3304 -243 3304 -252Q3304 -256 3296 -256Q3225 -256 3134.0 -172.5Q3043 -89 3043 -30Q3043 -24 3049.0 -24.0Q3055 -24 3068.5 -31.5Q3082 -39 3101.5 -52.5Q3121 -66 3134 -76Q3183 -112 3189 -118ZM2803 344Q2815 344 2977 150L3031 86Q3031 84 3029 84Q2961 133 2902.0 184.5Q2843 236 2821.5 271.0Q2800 306 2800 338Q2800 344 2803 344ZM3159 -13Q3176 -13 3300 -92L3342 -118L3343 -106Q3279 -62 3223 -32L3132 15Q3053 122 2934.5 244.5Q2816 367 2795.0 367.0Q2774 367 2774 353Q2774 280 2884 184Q2924 149 2986.0 103.5Q3048 58 3062 47Q3085 19 3110 -11Q3164 -74 3168 -80Q3168 -82 3164.5 -82.0Q3161 -82 3106 -42Q3052 -2 3035.5 -2.0Q3019 -2 3019 -32Q3019 -115 3113.5 -194.0Q3208 -273 3341 -273Q3352 -273 3352 -261Q3169 -31 3159 -13Z"}))),de.ready&&React.createElement(ValveInsetCard,{state:d,lang:a,t:Ce}),React.createElement("div",{className:`right-rail ${Me?"open":""}`},React.createElement("button",{className:"btn tiny ghost narrow-only rail-close",onClick:()=>pt(!1)},P("\u6536\u8D77\u9762\u677F","Hide panels")," \u25BE"),React.createElement("div",{className:"state-panel glass"},React.createElement("div",{className:"ctrl-label"},a==="en"?"Clinical State":"\u4E34\u5E8A\u72B6\u6001"),React.createElement("div",{className:"states-grid"},Object.values(STATES).map((e,t,r)=>{const i=e.group||"base",u=t?r[t-1].group||"base":null,l=t<9?String(t+1):t===9?"0":t===10?"-":t===11?"=":"";return React.createElement(React.Fragment,{key:e.id},i!==u&&React.createElement("div",{className:"states-group"},(STATE_GROUPS[i]||STATE_GROUPS.base)[a==="en"?1:0]),React.createElement("button",{className:`state-btn ${M===e.id?"active":""}`,onClick:()=>ot(e.id),title:`${l?l+" \u2014 ":""}${a==="en"?e.note:e.noteZh}`},React.createElement("div",{className:"nm"},a==="en"?e.en:e.zh)))})),React.createElement("div",{className:"state-readout"},React.createElement("span",{title:f!==d.HR?s(`\u672C\u72B6\u6001\u5178\u578B\u5FC3\u7387 ${d.HR}`,`Typical HR for this state: ${d.HR}`):""},s("\u5FC3\u7387","HR")," ",React.createElement("b",null,f)),React.createElement("span",null,s("\u5C04\u8840\u5206\u6570","EF")," ",React.createElement("b",null,d.EF,"%")),React.createElement("span",null,s("\u5FC3\u8F93\u51FA\u91CF","CO")," ",React.createElement("b",null,bt.toFixed(2))," L/min"),React.createElement("span",null,s("\u8212\u5F20\u672B\u5BB9\u79EF","EDV")," ",React.createElement("b",null,d.EDV)," / ",s("\u6536\u7F29\u672B\u5BB9\u79EF","ESV")," ",React.createElement("b",null,d.ESV)," mL"),React.createElement("span",null,s("\u6BCF\u640F\u91CF","SV")," ",React.createElement("b",null,d.SV)," mL"),d.regurgFrac>0&&React.createElement("span",{className:"warn"},s(`\u21A9 \u53CD\u6D41 ${d.regurgSV} \xB7 \u524D\u5411 ${d.forwardSV} mL\uFF08\u5FC3\u8F93\u51FA\u91CF\u6309\u524D\u5411\u7B97\uFF09`,`\u21A9 regurgitant ${d.regurgSV} \xB7 forward ${d.forwardSV} mL (CO uses forward SV)`)),d.myoDark&&React.createElement("span",{style:{color:"var(--ink-mute)"}},s("\u5DE6\u5BA4\u7740\u8272\u504F\u6697 = \u6536\u7F29\u529B\u4E0B\u964D\uFF08\u793A\u610F\uFF0C\u4E0D\u662F\u771F\u5B9E\u989C\u8272\uFF09","Darker LV = reduced contractility (illustrative, not a true colour)")))),React.createElement("div",{className:"wig-panel glass"},React.createElement("div",{className:"wig-head"},React.createElement("div",{className:"t"},a==="en"?"Wiggers Diagram":"\u5FC3\u52A8\u5468\u671F\u540C\u6B65\u56FE"),React.createElement("div",{className:"s"},Y?s("\u25B6 \u64AD\u653E\u4E2D","\u25B6 LIVE"):s("\u23F8 \u5DF2\u6682\u505C \xB7 \u62D6\u52A8\u770B\u65F6\u76F8","\u23F8 PAUSED \xB7 drag to scrub"))),React.createElement("canvas",{ref:Ae,className:`wig-canvas ${Qe?"dragging":""}`,onMouseDown:aa,onMouseMove:Ze,onMouseUp:na,onClick:sa,onMouseLeave:()=>ut(null)}),React.createElement("div",{className:"wig-legend"},React.createElement("div",{className:"lg"},React.createElement("span",{className:"sw",style:{background:"#A23B36"}}),s("\u4E3B\u52A8\u8109","Aorta")),React.createElement("div",{className:"lg"},React.createElement("span",{className:"sw",style:{background:"#1E3A5F"}}),s("\u5DE6\u5BA4","LV")),React.createElement("div",{className:"lg"},React.createElement("span",{className:"sw",style:{background:"#3E6B6E"}}),s("\u5DE6\u623F","LA")),React.createElement("div",{className:"lg"},React.createElement("span",{className:"sw",style:{background:"#8E8A83"}}),s("\u5BB9\u79EF","Vol")),React.createElement("div",{className:"lg"},React.createElement("span",{className:"sw",style:{background:"#4A7C59"}}),s("\u5FC3\u7535\u56FE","ECG")),React.createElement("div",{className:"lg",style:{color:"#B8860B"}},s("\u25CF \u65F6\u95F4\u5149\u6807 \xB7 \u70B9\u51FB\u65F6\u76F8","\u25CF t-cursor \xB7 click phase")))),React.createElement("div",{className:"ecg-panel glass"},React.createElement("div",{className:"wig-head"},React.createElement("div",{className:"t"},P("\u5FC3\u7535\u76D1\u62A4 ECG","ECG monitor")),React.createElement("div",{className:"s"},P("\u5BFC\u8054 II \xB7 \u4E0E\u52A8\u753B\u540C\u6B65\u8D70\u7EB8","lead II \xB7 in step with the animation"))),React.createElement("div",{className:"ecg-vitals"},React.createElement("span",{className:"hr-read"},React.createElement("b",null,f),React.createElement("small",null," bpm")),React.createElement("span",{className:"rr-read"},"R-R ",React.createElement("b",null,(60/f).toFixed(2))," s"),React.createElement("span",{className:"rr-read"},"PR ",React.createElement("b",null,J.pr.toFixed(2))),React.createElement("span",{className:"rr-read"},"QRS ",React.createElement("b",null,J.qrs.toFixed(2))),React.createElement("span",{className:"rr-read"},"QT ",React.createElement("b",null,J.qt.toFixed(2))),React.createElement("span",{className:"rr-read"},"QTc ",React.createElement("b",null,J.qtc.toFixed(2)))),React.createElement("canvas",{ref:gt,className:"ecg-screen"}),React.createElement("div",{className:"ecg-morph"},J.m.label[a==="en"?1:0]),React.createElement("div",{className:"ecg-chips"},[["P","P \u6CE2","P wave"],["QRS","QRS \u6CE2","QRS"],["T","T \u6CE2","T wave"],["PR","PR \u95F4\u671F","PR interval"],["QT","QT \u95F4\u671F","QT interval"]].map(([e,t,r])=>React.createElement("button",{key:e,className:"btn tiny "+(we===e?"primary":"ghost"),onClick:()=>Xt(i=>i===e?null:e)},P(t,r)))),React.createElement("div",{className:"ecg-explain"},we?ECG_INFO[we][a==="en"?1:0]:P("\u70B9\u4E0A\u9762\u4EFB\u4E00\u6CE2 / \u95F4\u671F\uFF1A\u770B\u673A\u5236\u4E0E\u5BF9\u5E94\u65F6\u76F8\uFF0C\u5E76\u5728\u6CE2\u5F62\u4E0A\u9AD8\u4EAE\u8BE5\u6BB5\uFF1B\u518D\u70B9\u4E00\u6B21\u53D6\u6D88\u3002\u5FC3\u7387\u8D8A\u5FEB\uFF0CR-R \u8D8A\u5BC6\u3001QT \u8D8A\u77ED\u3002","Tap a wave or interval to see what it is and which phase it belongs to; the segment lights up on the trace. Faster rate: closer R-R, shorter QT."))),React.createElement(AuscPanel,{stateId:M,site:ye,onPick:Jt,lang:a,canvasRef:Qt,audioOn:ce,onToggleAudio:()=>Te(e=>!e)}),React.createElement("div",{className:"pv-panel glass"},React.createElement("div",{className:"ttl"},React.createElement("span",null,a==="en"?"PV Loop":"\u538B\u529B\u2013\u5BB9\u79EF\u73AF"),React.createElement("span",{className:"sub"},a==="en"?d.id.toUpperCase():d.zh)),React.createElement("canvas",{ref:rt,className:"pv-canvas"})),React.createElement("div",{className:"ctrl-panel glass"},React.createElement("div",{className:"ctrl-section"},React.createElement("div",{className:"ctrl-label"},a==="en"?"Display Mode":"\u663E\u793A\u6A21\u5F0F"),React.createElement("div",{className:"row",style:{gap:4,marginBottom:8}},DISPLAY_MODES.map(e=>React.createElement("button",{key:e.id,className:`btn tiny ${T===e.id?"primary":"ghost"}`,style:{flex:1},onClick:()=>zt(e.id)},a==="en"?e.en:e.zh))),React.createElement("div",{className:"ctrl-label"},a==="en"?"Camera View":"\u89C6\u89D2"),React.createElement("div",{className:"view-row"},Object.keys(VIEW_PRESETS).map(e=>React.createElement("button",{key:e,className:"btn tiny ghost",onClick:()=>ra(e),title:`${VIEW_LABELS[e][0]} \xB7 ${VIEW_LABELS[e][1]}`},a==="en"?VIEW_LABELS[e][2]:VIEW_LABELS[e][0])))),T==="full"&&BLOOD_ON&&React.createElement("div",{className:"ctrl-section"},React.createElement("label",{className:"tg"},React.createElement("input",{type:"checkbox",checked:B,onChange:e=>Bt(e.target.checked)}),React.createElement("span",{className:"sw"}),P("\u5927\u8840\u7BA1\u5F00\u7A97\uFF08\u770B\u7BA1\u8154\u91CC\u7684\u8840\u6D41\uFF09","Vessel windows (see the blood inside)")),B&&je),T==="transp"&&React.createElement("div",{className:"ctrl-section"},React.createElement("div",{className:"row between"},React.createElement("div",{className:"ctrl-label"},a==="en"?"Tissue transparency":"\u7EC4\u7EC7\u900F\u660E\u5EA6\uFF08\u8840\u6DB2\u9664\u5916\uFF09"),React.createElement("span",{style:{fontFamily:"var(--mono)",fontSize:11,color:"var(--ink-dim)"}},Math.round(fe*100),"%")),React.createElement("input",{type:"range",min:0,max:1,step:.01,value:fe,onChange:e=>Ut(parseFloat(e.target.value)),style:{width:"100%"}}),React.createElement("div",{className:"row between",style:{fontSize:9.5,color:"var(--ink-mute)"}},React.createElement("span",null,a==="en"?"solid":"\u5B9E\u5FC3"),React.createElement("span",null,a==="en"?"blood only":"\u53EA\u770B\u8840")),BLOOD_ON&&React.createElement(React.Fragment,null,React.createElement("div",{className:"row between",style:{marginTop:8}},React.createElement("div",{className:"ctrl-label"},a==="en"?"Blood transparency":"\u8840\u6DB2\u900F\u89C6\u5EA6"),React.createElement("span",{style:{fontFamily:"var(--mono)",fontSize:11,color:"var(--ink-dim)"}},Math.round(ge*100),"%")),React.createElement("input",{type:"range",min:0,max:1,step:.01,value:ge,onChange:e=>$t(parseFloat(e.target.value)),style:{width:"100%"}}),React.createElement("div",{className:"row between",style:{fontSize:9.5,color:"var(--ink-mute)"}},React.createElement("span",null,a==="en"?"thick blood":"\u6D53\u8840"),React.createElement("span",null,a==="en"?"cells only":"\u53EA\u770B\u8840\u7EC6\u80DE"))),je),T==="cor"&&React.createElement("div",{className:"ctrl-section"},React.createElement("div",{className:"row between"},React.createElement("div",{className:"ctrl-label"},a==="en"?"Section depth":"\u5207\u9762\u6DF1\u5EA6"),React.createElement("span",{style:{fontFamily:"var(--mono)",fontSize:11,color:"var(--ink-dim)"}},le>0?"+":"",le.toFixed(1)," cm")),React.createElement("input",{type:"range",min:-4,max:4,step:.1,value:le,onChange:e=>Wt(parseFloat(e.target.value)),style:{width:"100%"}}),React.createElement("div",{className:"row between",style:{fontSize:9.5,color:"var(--ink-mute)"}},React.createElement("span",null,a==="en"?"posterior":"\u504F\u540E\uFF08\u5DE6\u623F\uFF09"),React.createElement("span",null,a==="en"?"anterior":"\u504F\u524D\uFF08\u53F3\u5BA4\uFF09")),je),React.createElement("div",{className:"ctrl-section"},React.createElement("div",{className:"row between"},React.createElement("label",{className:"tg"},React.createElement("input",{type:"checkbox",checked:Fe,onChange:e=>Gt(e.target.checked)}),React.createElement("span",{className:"sw"}),P("\u81EA\u65CB","Auto-rotate")),React.createElement("div",{className:"row",style:{gap:4}},["zh","en"].map(e=>React.createElement("button",{key:e,className:`btn tiny ${a===e?"primary":"ghost"}`,onClick:()=>ct(e),title:e==="zh"?"\u5168\u4E2D\u6587\u754C\u9762":"All-English interface"},e==="zh"?"\u4E2D\u6587":"English"))))),React.createElement("div",{className:"ctrl-section",style:{fontSize:9.5,color:"var(--ink-mute)",fontFamily:"var(--mono)",lineHeight:1.6}},a==="en"?React.createElement(React.Fragment,null,React.createElement("span",{style:{color:"var(--ink-dim)"}},"SHORTCUTS")," \xB7 Space \u25B6/\u23F8 \xB7 \u2190\u2192 phase (when paused) \xB7 1-9 / 0 / - state \xB7 L sound \xB7 F focus \xB7 R reset \xB7 Esc close"):React.createElement(React.Fragment,null,React.createElement("span",{style:{color:"var(--ink-dim)"}},"\u5FEB\u6377\u952E")," \xB7 \u7A7A\u683C \u25B6/\u23F8 \xB7 \u2190\u2192 \u65F6\u76F8\uFF08\u6682\u505C\u65F6\uFF09\xB7 1-9 / 0 / - \u72B6\u6001 \xB7 L \u542C\u8BCA \xB7 F \u805A\u7126 \xB7 R \u590D\u4F4D \xB7 Esc \u5173\u95ED")),React.createElement(ShareQR,{lang:a}),React.createElement("div",{className:"ctrl-section credit"},React.createElement("span",{className:"lbl"},a==="en"?"MODEL":"\u6A21\u578B\u6765\u6E90"),a==="en"?React.createElement(React.Fragment,null,"3D mesh derived from ",React.createElement("a",{href:"https://dbarchive.biosciencedbc.jp/en/bodyparts3d/",target:"_blank",rel:"noopener"},"BodyParts3D"),", \xA9 The Database Center for Life Science, ",React.createElement("a",{href:"https://creativecommons.org/licenses/by-sa/2.1/jp/",target:"_blank",rel:"noopener"},"CC BY-SA 2.1 JP"),". The 3D part of this work is shared under the same licence."):React.createElement(React.Fragment,null,"3D \u7F51\u683C\u6D3E\u751F\u81EA ",React.createElement("a",{href:"https://dbarchive.biosciencedbc.jp/en/bodyparts3d/",target:"_blank",rel:"noopener"},"BodyParts3D"),"\uFF0C\xA9 The Database Center for Life Science\uFF0C",React.createElement("a",{href:"https://creativecommons.org/licenses/by-sa/2.1/jp/",target:"_blank",rel:"noopener"},"CC BY-SA 2.1 JP"),"\u3002\u672C\u4F5C\u54C1\u7684 3D \u90E8\u5206\u4EE5\u76F8\u540C\u8BB8\u53EF\u5171\u4EAB\u3002"),React.createElement("br",null),React.createElement("span",{className:"lbl"},a==="en"?"AUDIO":"\u5FC3\u97F3\u6765\u6E90"),a==="en"?React.createElement(React.Fragment,null,"Recordings from the University of Michigan Heart Sound & Murmur Library (Judge & Mangrulkar), ",React.createElement("a",{href:"https://creativecommons.org/licenses/by-sa/3.0/",target:"_blank",rel:"noopener"},"CC BY-SA 3.0"),"; cut into beats for playback."):React.createElement(React.Fragment,null,"\u5F55\u97F3\u6765\u81EA University of Michigan Heart Sound & Murmur Library\uFF08Judge & Mangrulkar\uFF09\uFF0C",React.createElement("a",{href:"https://creativecommons.org/licenses/by-sa/3.0/",target:"_blank",rel:"noopener"},"CC BY-SA 3.0"),"\uFF0C\u6309\u62CD\u526A\u8F91\u64AD\u653E\u3002")))),React.createElement("div",{className:"transport glass"},React.createElement("div",{className:"grp"},React.createElement("button",{className:"btn primary",onClick:()=>ke(e=>!e),title:"Space"},Y?"\u23F8":"\u25B6",React.createElement("span",{className:"btn-txt"}," ",Y?P("\u6682\u505C","Pause"):P("\u64AD\u653E","Play"))),React.createElement("button",{className:"btn",onClick:()=>Te(e=>!e),title:"L"},ce?"\u{1F50A}":"\u{1F508}",React.createElement("span",{className:"btn-txt"}," ",P("\u542C\u8BCA","Listen"))),React.createElement("button",{className:"btn ghost",onClick:()=>We(e=>!e),title:"F"},"\u26F6",React.createElement("span",{className:"btn-txt"}," ",P("\u6C89\u6D78","Focus"))),React.createElement("button",{className:"btn ghost icon",title:s("R \u2014 \u56DE\u5230\u5468\u671F\u8D77\u70B9","R \u2014 back to the start of the cycle"),onClick:()=>{w.current=0,X(0),pe.current=0}},"\u21BB"),React.createElement("button",{className:`btn narrow-only ${Me?"primary":"ghost"}`,onClick:()=>pt(e=>!e)},"\u2630",React.createElement("span",{className:"btn-txt"}," ",P("\u9762\u677F","Panels")))),React.createElement("div",{className:"sep"}),React.createElement("div",{className:"hr-wrap"},React.createElement("span",{className:"lbl"},a==="en"?"HR":"\u5FC3\u7387"),React.createElement("input",{type:"range",min:"40",max:"180",value:f,className:"slider",style:{"--p":(f-40)/140*100+"%"},onChange:e=>it(parseInt(e.target.value))}),React.createElement("span",{className:"val"},React.createElement("span",{className:"v-ghost","aria-hidden":"true"},"000 ",s("\u6B21/\u5206","BPM")),React.createElement("span",{className:"v-now"},f," ",s("\u6B21/\u5206","BPM")))),React.createElement("div",{className:"sep"}),React.createElement("div",{className:"hr-wrap spd-wrap",title:s("\u6162\u52A8\u4F5C\uFF1A\u5FC3\u7387\u4E0E\u5404\u671F\u6BD4\u4F8B\u4E0D\u53D8\uFF1B\u6162\u653E\u65F6\u5FC3\u97F3\u9759\u97F3\uFF0C1\xD7 \u624D\u51FA\u58F0","Slow motion: heart rate and phase proportions unchanged; heart sounds only at 1\xD7")},React.createElement("span",{className:"lbl"},s("\u901F\u5EA6","Speed")),React.createElement("input",{type:"range",min:"0.1",max:"1",step:"0.05",value:j,className:"slider",style:{"--p":(j-.1)/(1-.1)*100+"%"},onChange:e=>It(parseFloat(e.target.value))}),React.createElement("svg",{className:"spd-mute",viewBox:"0 0 16 16",width:"13",height:"13",role:"img","aria-label":s("\u5FC3\u97F3\u9759\u97F3\uFF08\u6162\u653E\u65F6\uFF09","heart sounds muted (slow motion)"),style:{visibility:ce&&j<.999?"visible":"hidden"}},React.createElement("title",null,s("\u6162\u653E\u65F6\u5FC3\u97F3\u9759\u97F3\uFF0C1\xD7 \u624D\u51FA\u58F0","Heart sounds are muted in slow motion; they play at 1\xD7")),React.createElement("path",{d:"M2 6h3l4-3v10l-4-3H2z",fill:"currentColor"}),React.createElement("path",{d:"M11 6l4 4M15 6l-4 4",stroke:"currentColor",strokeWidth:"1.6",strokeLinecap:"round"})),React.createElement("span",{className:"val"},React.createElement("span",{className:"v-ghost","aria-hidden":"true"},"0.00\xD7",React.createElement("span",{className:"spd-sec"}," \xB7 00.0 ",s("\u79D2/\u5468\u671F","s/beat"))),React.createElement("span",{className:"v-now"},j.toFixed(2),"\xD7",React.createElement("span",{className:"spd-sec"}," \xB7 ",(60/f/j).toFixed(1)," ",s("\u79D2/\u5468\u671F","s/beat"))))),React.createElement("div",{className:"sep"}),React.createElement("div",{className:"grp"},React.createElement("span",{className:"lbl phase-lbl",style:{fontFamily:"var(--mono)",fontSize:10,color:"var(--ink-mute)",textTransform:"uppercase",letterSpacing:"0.08em"}},a==="en"?"Phase":"\u65F6\u76F8"),React.createElement("div",{className:"phase-jump",style:{gridTemplateColumns:"repeat(7, 26px)"}},PHASES.map(e=>React.createElement("button",{key:e.id,className:e.id===Re?"cur":"",disabled:Y,onClick:()=>{const t=PHASE_BOUNDS[e.id]+.001;w.current=t,X(t)},title:Y?s("\u5148\u6682\u505C","Pause first"):s(e.zh,e.en)},e.id+1))))),React.createElement("div",{className:`mini-hud glass ${ze?"show":""}`},React.createElement("div",{className:"mini-ring",style:{"--p":da}},React.createElement("div",{className:"num"},I.id+1)),React.createElement("div",{className:"mini-info"},React.createElement("div",{className:"ph"},a==="en"?I.en:I.zh),React.createElement("div",{className:"st"},a==="en"?d.en:d.zh," \xB7 ",f," ",s("\u6B21/\u5206","BPM")))),U&&React.createElement("div",{className:"tooltip",style:{left:U.x,top:U.y}},React.createElement("div",{className:"zh"},a==="en"?ANATOMY[U.anatomy].en:ANATOMY[U.anatomy].zh),React.createElement("div",{className:"desc"},s(ANATOMY[U.anatomy].fn,ANATOMY[U.anatomy].fnEn)),React.createElement("div",{style:{marginTop:6,fontSize:9.5,color:"var(--orange-2)",fontFamily:"var(--mono)"}},s("\u70B9\u51FB\u67E5\u770B\u8BE6\u60C5","CLICK FOR DETAILS"))),be&&(()=>{const e=PHASES[be.phase],t=PHASE_DETAIL[be.phase],r=(PHASE_BOUNDS[e.id]+PHASE_BOUNDS[e.id+1])/2,i=Math.min(y.LV.length-1,Math.floor(r*y.LV.length)),u={LV:y.LV[i],LA:y.LA[i],AO:y.AO[i]},l=340,o=220,F=Math.min(window.innerWidth-l-14,be.x-l/2),N=Math.max(14,be.y-o-16);return React.createElement("div",{className:"phase-pop",style:{left:Math.max(14,F),top:N}},React.createElement("button",{className:"x",onClick:()=>Ie(null)},"\xD7"),React.createElement("div",{className:"hd"},e.id+1,". ",a==="en"?e.en:e.zh," \xB7 ",e.pct,"%"),React.createElement("div",{className:"ev"},a==="en"?e.eventEn:e.event),React.createElement("div",{className:"row"},React.createElement("span",{className:"k"},s("\u74E3\u819C","Valves")),React.createElement("span",null,["TV","MV","PV","AV"].map(xe=>`${a==="en"?xe:VALVE_ZH[xe]} ${e.valves[xe]==="open"?"\u25CB":"\u25CF"}`).join(" \xB7 "))),React.createElement("div",{className:"row"},React.createElement("span",{className:"k"},s("\u538B\u529B","Pressure")),React.createElement("span",null,s("\u5DE6\u5BA4","LV")," ",u.LV.toFixed(0)," \xB7 ",s("\u5DE6\u623F","LA")," ",u.LA.toFixed(0)," \xB7 ",s("\u4E3B\u52A8\u8109","AO")," ",u.AO.toFixed(0)," mmHg ",React.createElement("span",{style:{opacity:.6}},"(",s(d.zh,d.en)," \xB7 ",s("\u672C\u671F\u4E2D\u70B9","mid-phase"),")"))),React.createElement("div",{className:"row"},React.createElement("span",{className:"k"},s("\u5FC3\u7535\u56FE","ECG")),React.createElement("span",null,s(e.ecg,e.ecgEn))),React.createElement("div",{className:"warn"},"\u26A0\uFE0F ",s(t.warn,t.warnEn)),React.createElement("div",{className:"ref"},"\u{1F4D6} ",s(t.ref,t.refEn||t.ref)))})(),React.createElement("div",{className:`drawer glass ${q?"open":""}`},q&&React.createElement(React.Fragment,null,React.createElement("button",{className:"drawer-close",onClick:()=>De(null)},"\xD7"),React.createElement("h2",null,a==="en"?q.en:q.zh),[["loc","\u89E3\u5256\u4F4D\u7F6E","Anatomy"],["fn","\u751F\u7406\u529F\u80FD","Function"],["clin","\u4E34\u5E8A\u8981\u70B9","Clinical"],["cycle","\u5FC3\u52A8\u5468\u671F\u89D2\u8272","In the Cycle"]].map(([e,t,r])=>React.createElement("div",{className:"drawer-section",key:e},React.createElement("div",{className:"lbl"},a==="en"?r:t),React.createElement("p",null,la(a==="en"?q[e+"En"]:q[e])))))))}ReactDOM.createRoot(document.getElementById("root")).render(React.createElement(App,null));
