BiNgoViewer 2.2.1__tar.gz → 2.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/PKG-INFO +1 -1
  2. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/SOURCES.txt +1 -1
  3. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/PKG-INFO +1 -1
  4. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/__init__.py +1 -1
  5. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/__main__.py +7 -0
  6. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/cli.py +20 -2
  7. bingoviewer-2.2.1/bingoviewer/frontend_dist/assets/index-DfWUZpOb.js → bingoviewer-2.2.3/bingoviewer/frontend_dist/assets/index-CpGWw-Cu.js +1 -1
  8. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/frontend_dist/index.html +1 -1
  9. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/main.py +1 -1
  10. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/pyproject.toml +1 -1
  11. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/dependency_links.txt +0 -0
  12. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/entry_points.txt +0 -0
  13. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/requires.txt +0 -0
  14. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/BiNgoViewer.egg-info/top_level.txt +0 -0
  15. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/README.md +0 -0
  16. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/icon.py +0 -0
  17. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/install_shortcut.py +0 -0
  18. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/__init__.py +0 -0
  19. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/api/__init__.py +0 -0
  20. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/api/data.py +0 -0
  21. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/api/genome.py +0 -0
  22. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/api/tracks.py +0 -0
  23. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/__init__.py +0 -0
  24. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/annotation_reader.py +0 -0
  25. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/bam_reader.py +0 -0
  26. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/bigwig_reader.py +0 -0
  27. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/genbank_reader.py +0 -0
  28. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/genome_reader.py +0 -0
  29. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/readers/vcf_reader.py +0 -0
  30. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/bingoviewer/server/state.py +0 -0
  31. {bingoviewer-2.2.1 → bingoviewer-2.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BiNgoViewer
3
- Version: 2.2.1
3
+ Version: 2.2.3
4
4
  Summary: BiNgo Genome Viewer — a lightweight browser-based genomics viewer
5
5
  Author-email: Billy M Ngo <billy.ngo0108@gmail.com>
6
6
  License: Proprietary
@@ -12,7 +12,7 @@ bingoviewer/cli.py
12
12
  bingoviewer/icon.py
13
13
  bingoviewer/install_shortcut.py
14
14
  bingoviewer/frontend_dist/index.html
15
- bingoviewer/frontend_dist/assets/index-DfWUZpOb.js
15
+ bingoviewer/frontend_dist/assets/index-CpGWw-Cu.js
16
16
  bingoviewer/server/__init__.py
17
17
  bingoviewer/server/main.py
18
18
  bingoviewer/server/state.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BiNgoViewer
3
- Version: 2.2.1
3
+ Version: 2.2.3
4
4
  Summary: BiNgo Genome Viewer — a lightweight browser-based genomics viewer
5
5
  Author-email: Billy M Ngo <billy.ngo0108@gmail.com>
6
6
  License: Proprietary
@@ -1,3 +1,3 @@
1
1
  """BiNgo Genome Viewer — a lightweight browser-based genomics viewer."""
2
2
 
3
- __version__ = "2.2.1"
3
+ __version__ = "2.2.3"
@@ -5,6 +5,13 @@ Starts the FastAPI server, serves the bundled frontend, and opens the browser.
5
5
  """
6
6
 
7
7
  import sys
8
+
9
+ # Set Windows event loop policy as early as possible to prevent
10
+ # ProactorEventLoop socket errors (WinError 64)
11
+ if sys.platform == "win32":
12
+ import asyncio
13
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
14
+
8
15
  from bingoviewer.cli import main
9
16
 
10
17
  if __name__ == "__main__":
@@ -239,8 +239,26 @@ def _check_update_with_prompt():
239
239
  _log(f" Updating BiNgo Genome Viewer: {installed} → {latest} ...")
240
240
  if _do_upgrade():
241
241
  _log(f" Updated to {latest}.")
242
- print(f"\n Please run 'bingo' again to launch the new version.\n")
243
- sys.exit(0)
242
+ if has_terminal:
243
+ print(f"\n Please run 'bingo' again to launch the new version.\n")
244
+ sys.exit(0)
245
+ else:
246
+ # Running from shortcut (pythonw) — show dialog and relaunch
247
+ try:
248
+ import tkinter as tk
249
+ from tkinter import messagebox
250
+ root = tk.Tk()
251
+ root.withdraw()
252
+ messagebox.showinfo(
253
+ "BiNgo Genome Viewer",
254
+ f"Updated to v{latest}.\n\nThe viewer will now relaunch."
255
+ )
256
+ root.destroy()
257
+ except Exception:
258
+ pass
259
+ # Relaunch via subprocess (new process gets new code)
260
+ subprocess.Popen([sys.executable, "-m", "bingoviewer", "--no-update"])
261
+ sys.exit(0)
244
262
  else:
245
263
  _log(f" Update failed. You can retry with: bingo --update")
246
264
 
@@ -94,4 +94,4 @@ ${A.join(`
94
94
  `)}
95
95
 
96
96
  Tip: If files were moved, re-add them using the 📂 Path button.`):(y("Session restored"),setTimeout(()=>{y(null),e()},1200))}catch(G){p(G.message)}finally{m(!1)}}const $=kc(),_=hy(c);return a.jsx("div",{style:_.overlay,onClick:H=>{H.target===H.currentTarget&&e()},children:a.jsxs("div",{style:_.panel,children:[a.jsxs("div",{style:_.header,children:[a.jsx("span",{style:_.title,children:"Session"}),a.jsx("button",{style:_.closeBtn,onClick:e,children:"✕"})]}),a.jsxs("div",{style:_.body,children:[a.jsxs("div",{style:_.section,children:[a.jsx("div",{style:_.sectionTitle,children:"Save"}),a.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:a.jsx("button",{style:_.btn,onClick:S,disabled:!r||f,children:"Save to file"})}),a.jsx("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:"Session is also auto-saved to browser storage."})]}),a.jsxs("div",{style:_.section,children:[a.jsx("div",{style:_.sectionTitle,children:"Restore"}),a.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[a.jsx("button",{style:_.btn,onClick:E,disabled:f,children:"Load from file"}),$&&a.jsx("button",{style:_.btn,onClick:P,disabled:f,children:"Restore last session"})]}),a.jsx("input",{ref:w,type:"file",accept:".json",style:{display:"none"},onChange:k}),$&&a.jsxs("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:["Last auto-save: ",new Date($.savedAt).toLocaleString(),$.genome&&` — ${$.genome.name}`,$.tracks&&` — ${$.tracks.length} tracks`]})]}),v&&a.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#81c784"},children:v}),x&&a.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#ef9a9a",whiteSpace:"pre-wrap"},children:x})]}),a.jsx("div",{style:_.footer,children:a.jsx("button",{style:_.btn,onClick:e,children:"Close"})})]})})}function hy(e){return{overlay:{position:"fixed",inset:0,background:e.overlayBg,display:"flex",alignItems:"center",justifyContent:"center",zIndex:1e3},panel:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:0,minWidth:380,maxWidth:480,maxHeight:"80vh",display:"flex",flexDirection:"column",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},header:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"10px 16px",borderBottom:`1px solid ${e.border}`},title:{fontSize:14,fontWeight:700,color:e.textPrimary},closeBtn:{background:"none",border:"none",color:e.textSecondary,cursor:"pointer",fontSize:18,lineHeight:1,padding:"0 4px"},body:{padding:"8px 0",overflowY:"auto",flex:1},section:{padding:"8px 16px"},sectionTitle:{fontSize:11,color:e.textSecondary,textTransform:"uppercase",letterSpacing:1,marginBottom:6},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600},footer:{display:"flex",justifyContent:"flex-end",padding:"10px 16px",borderTop:`1px solid ${e.border}`}}}const kn=[{target:"file-loader",title:"Load Files",description:"Select genome and track files using the file picker, drag and drop, or paste a local file path. Supported formats: FASTA, GenBank, BAM (+BAI), BigWig, WIG, BedGraph, VCF, BED, GTF, GFF.",position:"bottom"},{target:"nav-bar",title:"Navigation & Scrubber",description:"Switch chromosomes, type coordinates (chr1:1000-5000) to jump, zoom with -/+, and pan with ◀/▶. The blue scrubber bar shows your position — click or drag it to scroll across the entire chromosome.",position:"bottom"},{target:"track-area",title:"Track Interaction",description:"Left-click drag to pan, scroll to zoom. Right-click drag to select a region — hover the blue highlight for stats. Double-click a gene to zoom in with context. Hover features for detailed tooltips.",position:"inside"},{target:"skeleton-track-label",title:"Track Controls",description:"Drag ≡ to reorder tracks, click the color swatch to change colors, and click × to remove. Drag the bottom edge of a track to resize its height.",position:"right"},{target:"btn-settings",title:"Track Settings",description:"Select tracks and adjust: height, color, Y-axis scale (auto/manual/log), bar width, peak outline trace with color picker, show/hide bars, pointed arrows, and nucleotide display for BAM reads (shows A/C/G/T with mismatch highlighting when zoomed in).",position:"bottom",action:"open-settings"},{target:"header-btns",title:"Themes",description:"Choose from built-in themes (Dark, Light, Colorblind, Soft, High Contrast) or create a fully custom theme. Theme preferences persist across sessions.",position:"bottom",action:"open-theme"},{target:"btn-export",title:"Export Image",description:"Export your current view as SVG or PNG. The export respects all track settings including peak outlines, bar visibility, and scale labels.",position:"bottom"},{target:"header-btns",title:"Sessions",description:"Save Session exports your entire state (genome, tracks, region, zoom, colors, settings) as a JSON file. Restore it later or share with collaborators. Sessions also auto-save to your browser. An exit guard warns you before closing if you have unsaved work.",position:"bottom"},{target:"file-loader",title:"Large File Tips",description:"For large BAM files, use the 📂 Path button to paste a local file path — the server reads directly from disk without uploading. For large WIG files, convert to BigWig format for instant loading. The app checks for updates automatically in the background.",position:"bottom"}],bn=8,Cn=14,Tt=340,my=230,Br="rgba(0,0,0,0.55)";function gy({onClose:e,theme:t,onAction:n}){const[r,o]=C.useState(0),[l,i]=C.useState(null),[s,u]=C.useState(my),c=C.useRef(null),h=kn[r],d=r===0,g=r===kn.length-1;C.useEffect(()=>{var k;const E=(k=kn[r])==null?void 0:k.action;E&&n&&n(E)},[r,n]);const T=C.useCallback(E=>{var P;((P=kn[E])==null?void 0:P.action)&&n&&n(null)},[n]),v=C.useCallback(()=>{T(r),r<kn.length-1?o(E=>E+1):e()},[r,e,T]),y=C.useCallback(()=>{T(r),r>0&&o(E=>E-1)},[r,T]);C.useEffect(()=>{function E(k){k.key==="Escape"?e():k.key==="ArrowRight"||k.key==="Enter"?v():k.key==="ArrowLeft"&&y()}return window.addEventListener("keydown",E),()=>window.removeEventListener("keydown",E)},[e,v,y]),C.useEffect(()=>{function E(){const k=document.querySelector(`[data-tour="${h.target}"]`);if(k){const P=k.getBoundingClientRect();i({top:P.top,left:P.left,width:P.width,height:P.height})}else i(null)}return E(),window.addEventListener("resize",E),window.addEventListener("scroll",E,!0),()=>{window.removeEventListener("resize",E),window.removeEventListener("scroll",E,!0)}},[h.target]),C.useEffect(()=>{c.current&&u(c.current.getBoundingClientRect().height)});const x=l?{top:l.top-bn,left:l.left-bn,width:l.width+bn*2,height:l.height+bn*2}:null;let p,f,m=null,w=Tt/2;if(!l)p=(window.innerHeight-s)/2,f=(window.innerWidth-Tt)/2;else{const E=h.position||"bottom",k=l.top+l.height+bn,P=l.top-bn,N=l.left+l.width+bn,$=l.left+l.width/2;E==="inside"?(p=l.top+Math.max(20,(l.height-s)/2),f=l.left+Math.max(16,(l.width-Tt)/2)):E==="right"?(p=l.top+l.height/2-s/2,f=N+Cn,m="left",w=s/2,f+Tt>window.innerWidth-12&&(p=k+Cn,f=$-Tt/2,m="up",w=Math.max(20,Math.min(Tt-20,$-f)))):(k+Cn+s<=window.innerHeight?(p=k+Cn,m="up"):P-Cn-s>=0?(p=P-Cn-s,m="down"):(p=k+Cn,m="up"),l.width<200?(f=Math.max(12,l.left+l.width-Tt),f<12&&(f=12)):f=$-Tt/2,w=Math.max(20,Math.min(Tt-20,$-f))),f=Math.max(12,Math.min(window.innerWidth-Tt-12,f)),p=Math.max(12,Math.min(window.innerHeight-s-12,p))}const S={card:{position:"fixed",top:p,left:f,width:Tt,zIndex:10002,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:10,padding:"20px 24px 16px",color:t.textPrimary,boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},stepCounter:{fontSize:11,fontWeight:600,color:t.textTertiary,textTransform:"uppercase",letterSpacing:1.2,marginBottom:10},title:{fontSize:16,fontWeight:700,marginBottom:6,color:t.textPrimary},description:{fontSize:13,lineHeight:1.6,color:t.textSecondary,marginBottom:20},dots:{display:"flex",justifyContent:"center",gap:8,marginBottom:14},dot:E=>({width:7,height:7,borderRadius:"50%",background:E?"#42a5f5":t.borderStrong,cursor:"pointer"}),nav:{display:"flex",alignItems:"center",justifyContent:"space-between"},btnPrimary:{background:"#1976d2",border:"none",borderRadius:5,color:"#fff",padding:"6px 18px",cursor:"pointer",fontSize:12,fontWeight:600},btnSecondary:{background:t.btnBg,border:`1px solid ${t.borderStrong}`,borderRadius:5,color:t.btnText,padding:"6px 14px",cursor:"pointer",fontSize:12,fontWeight:600},btnDisabled:{background:t.btnBg,border:`1px solid ${t.border}`,borderRadius:5,color:t.textMuted,padding:"6px 14px",fontSize:12,fontWeight:600,cursor:"default",opacity:.5},skip:{background:"none",border:"none",color:t.textTertiary,fontSize:11,cursor:"pointer",textDecoration:"underline",padding:0},arrowUp:{position:"absolute",top:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderBottom:`7px solid ${t.panelBg}`},arrowDown:{position:"absolute",bottom:-7,left:w-7,width:0,height:0,borderLeft:"7px solid transparent",borderRight:"7px solid transparent",borderTop:`7px solid ${t.panelBg}`},arrowLeft:{position:"absolute",left:-7,top:w-7,width:0,height:0,borderTop:"7px solid transparent",borderBottom:"7px solid transparent",borderRight:`7px solid ${t.panelBg}`}};return a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4},onClick:e}),x?a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{position:"fixed",top:0,left:0,right:0,height:Math.max(0,x.top),background:Br,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:x.top+x.height,left:0,right:0,bottom:0,background:Br,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:x.top,left:0,width:Math.max(0,x.left),height:x.height,background:Br,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:x.top,left:x.left+x.width,right:0,height:x.height,background:Br,zIndex:10001,pointerEvents:"none"}}),a.jsx("div",{style:{position:"fixed",top:x.top,left:x.left,width:x.width,height:x.height,borderRadius:6,border:"2px solid rgba(255,255,255,0.22)",zIndex:10001,pointerEvents:"none",boxSizing:"border-box"}})]}):a.jsx("div",{style:{position:"fixed",inset:0,background:Br,zIndex:10001,pointerEvents:"none"}}),a.jsxs("div",{ref:c,style:S.card,onClick:E=>E.stopPropagation(),children:[m==="up"&&a.jsx("div",{style:S.arrowUp}),m==="down"&&a.jsx("div",{style:S.arrowDown}),m==="left"&&a.jsx("div",{style:S.arrowLeft}),a.jsxs("div",{style:S.stepCounter,children:["Step ",r+1," of ",kn.length]}),a.jsx("div",{style:S.title,children:h.title}),a.jsx("div",{style:S.description,children:h.description}),a.jsx("div",{style:S.dots,children:kn.map((E,k)=>a.jsx("div",{style:S.dot(k===r),onClick:()=>o(k)},k))}),a.jsxs("div",{style:S.nav,children:[a.jsx("button",{style:S.skip,onClick:e,children:"Skip Tour"}),a.jsxs("div",{style:{display:"flex",gap:8},children:[a.jsx("button",{style:d?S.btnDisabled:S.btnSecondary,onClick:y,disabled:d,children:"Previous"}),a.jsx("button",{style:S.btnPrimary,onClick:v,children:g?"Finish":"Next"})]})]})]})]})}function yy(){const{theme:e}=Ye(),{genome:t,region:n,navigateTo:r,zoom:o,pan:l}=it(),[i,s]=C.useState(""),u=C.useRef(null),c=C.useRef(!1),h=C.useMemo(()=>{if(!t)return{toShort:{},toLong:{}};const w={},S={};return t.chromosomes.forEach((E,k)=>{const P=`chr${k+1}`;w[E.name]=P,S[P.toLowerCase()]=E.name,S[E.name.toLowerCase()]=E.name}),{toShort:w,toLong:S}},[t]);C.useEffect(()=>{if(n){const w=h.toShort[n.chrom]||n.chrom;s(`${w}:${n.start.toLocaleString()}-${n.end.toLocaleString()}`)}},[n,h]);const d=C.useMemo(()=>{if(!t||!n)return 0;const w=t.chromosomes.find(S=>S.name===n.chrom);return w?w.length:0},[t,n==null?void 0:n.chrom]),g=C.useCallback(w=>{if(!u.current||!n||!d)return;const S=u.current.getBoundingClientRect(),E=Math.max(0,Math.min(1,(w-S.left)/S.width)),k=n.end-n.start,P=E*d;r(n.chrom,P-k/2,P+k/2)},[n,d,r]),T=C.useCallback(w=>{w.preventDefault(),c.current=!0,g(w.clientX);function S(k){c.current&&g(k.clientX)}function E(){c.current=!1,window.removeEventListener("mousemove",S),window.removeEventListener("mouseup",E),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="grabbing",document.body.style.userSelect="none",window.addEventListener("mousemove",S),window.addEventListener("mouseup",E)},[g]),v={bar:{background:e.headerBg,borderBottom:`1px solid ${e.border}`,padding:"6px 12px",display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},select:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 6px",fontSize:12},coordInput:{background:e.inputBg,border:`1px solid ${e.borderAccent}`,borderRadius:4,color:e.textPrimary,padding:"4px 8px",fontSize:12,width:220,fontFamily:"monospace"},btn:{background:e.btnBg,border:"none",borderRadius:4,color:e.btnText,padding:"4px 10px",cursor:"pointer",fontSize:13},info:{color:e.textSecondary,fontSize:11,marginLeft:8},scrubberWrap:{flex:1,minWidth:120,height:14,position:"relative",background:e.inputBg,borderRadius:7,border:`1px solid ${e.borderAccent}`,cursor:"pointer",overflow:"hidden"}};function y(w){if(!t)return;const S=t.chromosomes.find(E=>E.name===w.target.value);S&&r(S.name,0,Math.min(S.length,5e4))}function x(w){w.preventDefault();const E=i.replace(/,/g,"").trim().match(/^(\S+):(\d+)-(\d+)$/);if(E){const k=h.toLong[E[1].toLowerCase()]||E[1];r(k,parseInt(E[2]),parseInt(E[3]))}}if(!t)return a.jsx("div",{style:{...v.bar,opacity:.4},"data-tour":"nav-bar",children:a.jsx("span",{style:{fontSize:12,color:e.textMuted,fontStyle:"italic"},children:"Load a genome to enable navigation"})});const p=n?n.end-n.start:0;let f=0,m=100;return n&&d>0&&(f=n.start/d*100,m=Math.max(1,p/d*100)),a.jsxs("div",{style:v.bar,"data-tour":"nav-bar",children:[a.jsx("select",{style:v.select,value:(n==null?void 0:n.chrom)||"",onChange:y,children:t.chromosomes.map((w,S)=>a.jsxs("option",{value:w.name,children:["chr",S+1," ","—"," ",w.name," (",(w.length/1e3).toFixed(0)," kbp)"]},w.name))}),a.jsxs("form",{onSubmit:x,style:{display:"flex",gap:4},children:[a.jsx("input",{style:v.coordInput,value:i,onChange:w=>s(w.target.value),placeholder:"chr1:start-end"}),a.jsx("button",{style:v.btn,type:"submit",children:"Go"})]}),a.jsx("button",{style:v.btn,onClick:()=>o(2),title:"Zoom out",children:"-"}),a.jsx("button",{style:v.btn,onClick:()=>o(.5),title:"Zoom in",children:"+"}),a.jsx("button",{style:v.btn,onClick:()=>l(-p*.5),title:"Pan left",children:"◀"}),a.jsx("button",{style:v.btn,onClick:()=>l(p*.5),title:"Pan right",children:"▶"}),n&&d>0&&a.jsx("div",{ref:u,style:v.scrubberWrap,onMouseDown:T,title:"Drag to scroll across the chromosome",children:a.jsx("div",{style:{position:"absolute",left:`${f}%`,width:`${m}%`,top:1,bottom:1,background:"#42a5f5",borderRadius:6,minWidth:8,opacity:.7,transition:c.current?"none":"left 0.1s ease"}})}),n&&a.jsxs("span",{style:v.info,children:[p.toLocaleString()," bp"]})]})}function bp(e){const{region:t,zoom:n,navigateTo:r,setSelection:o,clearSelection:l}=it(),i=C.useRef(null),s=C.useRef(null),u=C.useRef(t);u.current=t,C.useEffect(()=>{const c=e.current;if(!c)return;function h(y){const x=u.current;if(x){if(y.button===2){y.preventDefault();const p=c.getBoundingClientRect(),f=(y.clientX-p.left)/p.width,m=x.start+f*(x.end-x.start);s.current={startX:y.clientX,startBp:m,region:{...x},containerWidth:p.width};return}y.button===0&&(l(),i.current={x:y.clientX,startRegion:{...x},containerWidth:c.offsetWidth||c.clientWidth||1})}}function d(y){if(s.current){const E=s.current,k=c.getBoundingClientRect(),P=Math.max(0,Math.min(1,(y.clientX-k.left)/k.width)),N=E.region.start+P*(E.region.end-E.region.start),$=Math.min(E.startBp,N),_=Math.max(E.startBp,N);Math.abs(_-$)>=1&&o({chrom:E.region.chrom,start:Math.floor($),end:Math.ceil(_)});return}if(!i.current)return;const x=y.clientX-i.current.x,{chrom:p,start:f,end:m}=i.current.startRegion,w=(m-f)/i.current.containerWidth,S=-x*w;r(p,f+S,m+S)}function g(y){if(s.current){s.current=null;return}i.current=null}function T(y){y.preventDefault()}function v(y){y.preventDefault();const x=c.getBoundingClientRect(),p=(y.clientX-x.left)/x.width,f=y.deltaY>0?1.4:.7;n(f,p)}return c.addEventListener("mousedown",h),c.addEventListener("contextmenu",T),window.addEventListener("mousemove",d),window.addEventListener("mouseup",g),c.addEventListener("wheel",v,{passive:!1}),()=>{c.removeEventListener("mousedown",h),c.removeEventListener("contextmenu",T),window.removeEventListener("mousemove",d),window.removeEventListener("mouseup",g),c.removeEventListener("wheel",v)}},[n,r,o,l,e])}const Tn=30;function xy({width:e}){const t=C.useRef(null),n=C.useRef(null),{region:r,selection:o}=it(),{theme:l}=Ye();return bp(t),C.useEffect(()=>{const i=n.current;if(!i||!r)return;const s=window.devicePixelRatio||1;i.width=e*s,i.height=Tn*s;const u=i.getContext("2d");u.scale(s,s);const{start:c,end:h}=r,d=h-c;if(u.clearRect(0,0,e,Tn),u.fillStyle=l.canvasBg,u.fillRect(0,0,e,Tn),o&&o.chrom===r.chrom){const f=(o.start-c)/d,m=(o.end-c)/d,w=Math.max(0,f*e),S=Math.min(e,m*e);S-w>=1&&(u.fillStyle="rgba(100, 181, 246, 0.25)",u.fillRect(w,0,S-w,Tn),u.strokeStyle="rgba(100, 181, 246, 0.6)",u.lineWidth=1,u.beginPath(),u.moveTo(w,0),u.lineTo(w,Tn),u.moveTo(S,0),u.lineTo(S,Tn),u.stroke())}const g=Math.min(10,Math.floor(e/80)),T=d/g,v=Math.pow(10,Math.floor(Math.log10(T))),y=[1,2,5,10].map(f=>f*v),x=y.find(f=>f>=T)||y[y.length-1],p=Math.ceil(c/x)*x;u.strokeStyle=l.rulerTick,u.fillStyle=l.rulerLabel,u.font="10px Arial, Helvetica, sans-serif",u.textAlign="center",u.beginPath(),u.moveTo(0,20),u.lineTo(e,20),u.lineWidth=1,u.stroke();for(let f=p;f<=h;f+=x){const m=(f-c)/d*e;u.beginPath(),u.moveTo(m,14),u.lineTo(m,20),u.stroke(),u.fillText(vy(f),m,11)}},[r,o,e,l]),a.jsx("div",{ref:t,style:{position:"relative"},children:a.jsx("canvas",{ref:n,style:{display:"block",width:"100%",height:Tn}})})}function vy(e){return e>=1e6?`${(e/1e6).toFixed(2)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function Mi(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function Yn(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function wy({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=it(),{theme:i}=Ye(),{data:s,loading:u,error:c}=Jl(e,l,t);return C.useEffect(()=>{var G,F;const h=o.current;if(!h)return;const d=window.devicePixelRatio||1;h.width=t*d,h.height=n*d;const g=h.getContext("2d");if(g.scale(d,d),g.clearRect(0,0,t,n),g.fillStyle=i.canvasBg,g.fillRect(0,0,t,n),u&&!((G=s==null?void 0:s.bins)!=null&&G.length)){g.fillStyle=i.textTertiary,g.font="11px Arial, Helvetica, sans-serif",g.fillText("Loading…",8,n/2+4),r&&r(null);return}if(c){g.fillStyle="#ef9a9a",g.font="11px Arial, Helvetica, sans-serif",g.fillText(typeof c=="string"?c:JSON.stringify(c),8,n/2+4),r&&r(null);return}if(!((F=s==null?void 0:s.bins)!=null&&F.length)){r&&r(null);return}const T=s.max_value||0,v=s.min_value||0,y=v<0,x=l.start,p=l.end-l.start,f=e.color||"#78909c",m=e.scaleMax!=null?e.scaleMax:null,w=e.scaleMin!=null?e.scaleMin:null,S=e.logScale===!0,E=e.barAutoWidth!==!1,k=e.barWidth||2,P=e.showOutline===!0,N=e.outlineColor||null,$=e.outlineSmooth||0,_=e.showBars!==!1,H=f,j=Sy(f,-40),U=t/p;function O(B){return E?U>=1?Math.max(1,Math.min(U,B)):Math.max(1,B):Math.min(k,B)}if(y){const M=Math.round(n/2),I=M-12/2,A=n-M-12/2,R=m??(T||1),b=w??(Math.abs(v)||1);if(g.strokeStyle=i.centerLine,g.lineWidth=1,g.beginPath(),g.moveTo(0,M),g.lineTo(t,M),g.stroke(),_)for(const Y of s.bins){const K=(Y.end-Y.start)/p*t,re=O(K),ue=(Y.start-x)/p*t,pe=Y.forward!=null?Y.forward:Math.max(0,Y.value),fe=Y.reverse!=null?Y.reverse:Math.min(0,Y.value);if(pe>0){const ae=S?Yn(pe,R):pe/R;g.fillStyle=H,g.fillRect(ue,M-ae*I,re,ae*I)}if(fe<0){const ae=S?Yn(Math.abs(fe),b):Math.abs(fe)/b;g.fillStyle=j,g.fillRect(ue,M,re,ae*A)}}if(P&&s.bins.length>0){const Y=N||i.textPrimary||"#fff",K=N||i.textPrimary||"#fff",re=s.bins.map(ie=>{const te=ie.forward!=null?ie.forward:Math.max(0,ie.value);return te>0?S?Yn(te,R):te/R:0}),ue=s.bins.map(ie=>{const te=ie.reverse!=null?ie.reverse:Math.min(0,ie.value);return te<0?S?Yn(Math.abs(te),b):Math.abs(te)/b:0}),pe=Mi(re,$),fe=Mi(ue,$),ae=s.bins.map(ie=>((ie.start+ie.end)/2-x)/p*t);Bi(g,ae,pe.map(ie=>M-ie*I),Y,$>0),Bi(g,ae,fe.map(ie=>M+ie*A),K,$>0)}const D=S?" log₂":"";Ar(g,`+${R.toFixed(1)}${D}`,2,2,i),Ar(g,`−${b.toFixed(1)}${D}`,2,n-12,i),Ar(g,"0",2,M-6,i,!0)}else{const B=m??(T||1);if(_){g.fillStyle=H;for(const I of s.bins){const A=(I.end-I.start)/p*t,R=O(A),b=(I.start-x)/p*t,Y=(S?Yn(I.value,B):I.value/B)*(n-14);g.fillRect(b,n-Y-2,R,Y)}}if(P&&s.bins.length>0){const I=s.bins.map(D=>S?Yn(D.value,B):D.value/B),A=Mi(I,$),R=s.bins.map(D=>((D.start+D.end)/2-x)/p*t),b=A.map(D=>n-D*(n-14)-2);Bi(g,R,b,N||i.textPrimary||"#fff",$>0)}const M=S?" log₂":"";Ar(g,`${B.toFixed(1)}${M}`,2,2,i),Ar(g,"0",2,n-12,i,!0)}if(r){const B=[];m!=null&&T>m&&B.push(`Bars clipped: max value ${T.toFixed(1)} exceeds scale ${m.toFixed(1)}`),y&&w!=null&&Math.abs(v)>w&&B.push(`Negative bars clipped: min value ${Math.abs(v).toFixed(1)} exceeds scale ${w.toFixed(1)}`),r(B.length>0?B.join(`
97
- `):null)}},[s,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Bi(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,s=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,s)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function Ar(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),s=2,u=i.width+s*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+s,r+1),e.textBaseline="alphabetic"}function Sy(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const Cc=6,Ai=8,zi=14,$i=2,ky="#9c27b0",Wo=10,by={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},Cy="#ffeb3b";function Tc(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ty({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=it(),{theme:i}=Ye(),{data:s,loading:u}=Jl(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),y=e.showNucleotides!==!1,x=e.useArrows!==!1,p=e.logScale===!0,f=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",S=e.arrowSize||4,E=C.useRef(null);C.useEffect(()=>{if(l&&E.current){const N=E.current;(N.chrom!==l.chrom||Math.abs(N.start-l.start)>N.end-N.start)&&T(0)}E.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!y){h(null);return}const N=l.end-l.start;if(t/N<Cc||N>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const _=Math.max(0,l.start-500),H=l.end+500,j=`${l.chrom}:${_}-${H}`;d.current!==j&&(d.current=j,mn.sequence(l.chrom,_,H).then(U=>h({chrom:l.chrom,start:_,end:H,sequence:U.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,y]);const k=C.useCallback(N=>{var U;if(!((U=s==null?void 0:s.reads)!=null&&U.length)||!N.shiftKey&&Math.abs(N.deltaX)>Math.abs(N.deltaY))return;const $=y&&c?zi:Ai,_=Math.max(0,...s.reads.map(O=>O.row)),H=Math.floor(n/($+$i)),j=Math.max(0,_-H+2);j<=0||(N.preventDefault(),N.stopPropagation(),T(O=>Math.max(0,Math.min(j,O+Math.sign(N.deltaY)*3))))},[s,n,y,c]);C.useEffect(()=>{var Y;const N=o.current;if(!N)return;const $=window.devicePixelRatio||1;N.width=t*$,N.height=n*$;const _=N.getContext("2d");if(_.scale($,$),_.clearRect(0,0,t,n),_.fillStyle=i.canvasBg,_.fillRect(0,0,t,n),u&&!s){_.fillStyle=i.textTertiary,_.font="11px Arial, Helvetica, sans-serif",_.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!s){r&&r(null);return}const H=l.start,j=l.end-l.start;if(s.bins){const K=s.max_value||1,re=e.scaleMax!=null?e.scaleMax:K,ue=e.color||"#78909c",pe=e.barAutoWidth!==!1,fe=e.barWidth||2,ae=t/j;if(e.showBars!==!1){_.fillStyle=ue;for(const te of s.bins){const ge=(te.end-te.start)/j*t,_e=pe?ae>=1?Math.max(1,Math.min(ae,ge)):Math.max(1,ge):Math.min(fe,ge),ye=(te.start-H)/j*t,Je=(p?Tc(te.value,re):Math.min(1,te.value/re))*(n-14);_.fillRect(ye,n-Je-2,_e,Je)}}if(e.showOutline&&s.bins.length>0){const te=e.outlineSmooth||0,ge=s.bins.map(he=>p?Tc(he.value,re):Math.min(1,he.value/re)),_e=Ry(ge,te),ye=s.bins.map(he=>((he.start+he.end)/2-H)/j*t),Ne=_e.map(he=>n-he*(n-14)-2),Je=e.outlineColor||i.textPrimary||"#fff";if(_.beginPath(),_.moveTo(ye[0],Ne[0]),te>0){for(let he=0;he<ye.length-1;he++)_.quadraticCurveTo(ye[he],Ne[he],(ye[he]+ye[he+1])/2,(Ne[he]+Ne[he+1])/2);_.lineTo(ye[ye.length-1],Ne[Ne.length-1])}else for(let he=0;he<ye.length;he++)_.lineTo(ye[he],Ne[he]);_.strokeStyle=Je,_.lineWidth=1.5,_.stroke()}const ie=p?" log₂":"";Ec(_,`${re.toFixed(1)}${ie}`,2,2,i),Ec(_,"0",2,n-12,i,!0),_.fillStyle="#ffb74d",_.font="10px Arial, Helvetica, sans-serif",_.textAlign="right",_.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&K>e.scaleMax?`Bars clipped: max value ${K.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((Y=s.reads)!=null&&Y.length)){_.fillStyle=i.textTertiary,_.font="11px Arial, Helvetica, sans-serif",_.fillText("No reads in region",8,n/2+4),r&&r(null);return}const U=K=>(K-H)/j*t,O=t/j,G=y&&O>=Cc&&c!=null,F=G?zi:Ai,B=$i,I=Math.max(0,...s.reads.map(K=>K.row))+1,A=Math.floor(n/(F+B)),R=I>A,b=Math.min(g,Math.max(0,I-A+1));let D=0;for(const K of s.reads){const re=(K.row-b)*(F+B)+2;if(re+F<0||re>n){D++;continue}const ue=K.strand==="+"?f:m,pe=K.segments;if(pe&&pe.length>0){const fe=U(K.start),ae=U(K.end);_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(fe,re+F/2),_.lineTo(ae,re+F/2),_.stroke();let ie=0;for(const te of pe)if(te.type==="M"){const ge=U(te.start),_e=Math.max(1,U(te.end)-ge);if(_.fillStyle=ue,_.fillRect(ge,re,_e,F),G&&K.sequence){const ye=te.end-te.start;for(let Ne=0;Ne<ye;Ne++){const Je=te.start+Ne,he=U(Je),ht=U(Je+1)-he,V=(K.sequence[ie+Ne]||"").toUpperCase();let J="";c&&Je>=c.start&&Je<c.end&&(J=(c.sequence[Je-c.start]||"").toUpperCase());const ee=J&&V&&V!==J&&V!=="N";ee&&(_.fillStyle=Cy,_.fillRect(he,re,ht,F)),ht>=6&&(_.fillStyle=ee?"#000":by[V]||"#999",_.font=`bold ${Math.min(11,ht-1)}px monospace`,_.textAlign="center",_.textBaseline="middle",_.fillText(V,he+ht/2,re+F/2))}ie+=ye}}else if(te.type==="D"){const ge=U(te.start),_e=U(te.end)-ge;_e>=1&&(_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(ge,re+F/2),_.lineTo(ge+_e,re+F/2),_.stroke())}else if(te.type==="N"){const ge=U(te.start),_e=U(te.end)-ge;_e>=2&&(_.setLineDash([2,2]),_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(ge,re+F/2),_.lineTo(ge+_e,re+F/2),_.stroke(),_.setLineDash([]))}else te.type==="I"?(_.fillStyle=ky,_.fillRect(U(te.pos)-1,re-1,2,F+2),G&&(ie+=te.length)):te.type==="S"&&G&&(ie+=te.length)}else{const fe=U(K.start),ae=Math.max(2,U(K.end)-fe);_.fillStyle=K.strand==="+"?f:m,_.fillRect(fe,re,ae,F)}if(x&&w!=="flat"){const fe=U(K.start),ae=Math.max(2,U(K.end)-fe),ie=Math.min(S,ae/2);ie>=2&&Ey(_,w,K.strand,fe,re,ae,F,ie,ue,i.canvasBg)}if(!G&&!y){const fe=U(K.start);Math.max(2,U(K.end)-fe)>60&&(_.fillStyle=i.canvasBg,_.font="8px Arial, Helvetica, sans-serif",_.textAlign="left",_.fillText(K.name.slice(0,20),fe+2,re+F-1))}}if(R){const K=t-Wo;_.fillStyle=i.inputBg||"#2a2a2a",_.fillRect(K,0,Wo,n);const re=A/I,ue=Math.max(20,re*n),fe=(I>A?b/(I-A):0)*(n-ue);_.fillStyle="#555",_.fillRect(K+1,fe,Wo-2,ue)}r&&(D>0&&!R?r(`${D} read${D>1?"s":""} hidden — increase track height to show all`):r(R?`${I} rows · Shift+scroll or drag scrollbar to navigate`:null))},[s,u,t,n,l,c,g,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,e.logScale,e.fwdColor,e.revColor,e.arrowStyle,e.arrowSize,i]);const P=C.useCallback(N=>{var I;if(!((I=s==null?void 0:s.reads)!=null&&I.length))return;const $=o.current;if(!$)return;const _=$.getBoundingClientRect();if((N.clientX-_.left)*(t/_.width)<t-Wo)return;const j=y&&c?zi:Ai,O=Math.max(0,...s.reads.map(A=>A.row))+1,G=Math.floor(n/(j+$i)),F=Math.max(0,O-G+1);if(F<=0)return;N.preventDefault(),v.current={maxScroll:F,startY:N.clientY,startRow:g};function B(A){if(!v.current)return;const R=A.clientY-v.current.startY,b=Math.round(R/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+b)))}function M(){v.current=null,window.removeEventListener("mousemove",B),window.removeEventListener("mouseup",M)}window.addEventListener("mousemove",B),window.addEventListener("mouseup",M)},[s,t,n,g,y,c]);return a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:k,onMouseDown:P})}function Ey(e,t,n,r,o,l,i,s,u,c){const h=n==="+";if(t==="pointed")e.fillStyle=c,h?(e.beginPath(),e.moveTo(r+l,o+i/2),e.lineTo(r+l-s,o),e.lineTo(r+l-s,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+s,o),e.lineTo(r+s,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-s,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-s,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+s,o),e.lineTo(r,o+i/2),e.lineTo(r+s,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-s*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-s*2,o,s*2,i)}else{const d=e.createLinearGradient(r,0,r+s*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,s*2,i)}}function Ry(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function Ec(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,s=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,s,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const jy=16,Py=22,_y=4,Cp=8,Rc=6,jc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Ly({track:e,width:t,height:n,onWarning:r}){var N,$,_,H;const o=C.useRef(null),{region:l,navigateTo:i}=it(),{tracks:s}=Kt(),{theme:u}=Ye(),{data:c,loading:h,error:d}=Jl(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[y,x]=C.useState(null),[p,f]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){f(null);return}const j=l.end-l.start;if(t/j<Rc||j>2e3){f(null);return}if(p&&p.chrom===l.chrom&&p.start<=l.start&&p.end>=l.end)return;const O=Math.max(0,l.start-500),G=l.end+500,F=`${l.chrom}:${O}-${G}`;m.current!==F&&(m.current=F,mn.sequence(l.chrom,O,G).then(B=>f({chrom:l.chrom,start:O,end:G,sequence:B.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,T]),C.useEffect(()=>{var b,D;const j=o.current;if(!j)return;const U=window.devicePixelRatio||1;j.width=t*U,j.height=n*U;const O=j.getContext("2d");if(O.scale(U,U),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((b=c==null?void 0:c.features)!=null&&b.length)){O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){O.fillStyle="#ef9a9a",O.font="11px Arial, Helvetica, sans-serif",O.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((D=c==null?void 0:c.features)!=null&&D.length)){c&&(O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("No features in region",8,n/2+4)),r&&r(null);return}const G=l.end-l.start,F=t/G,B=T&&F>=Rc&&p!=null,M=B?Py:jy,I=[],A=[];let R=0;if(B){const K=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,K,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,K),O.lineTo(t,K),O.stroke();const re=Math.min(10,F-1);if(re>=5){O.font=`bold ${re}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ue=Math.floor(l.start);ue<Math.ceil(l.end);ue++)if(p&&ue>=p.start&&ue<p.end){const pe=(p.sequence[ue-p.start]||"").toUpperCase(),fe=(ue-l.start)/G*t;O.fillStyle=jc[pe]||"#999",O.fillText(pe,fe+F/2,K+14/2)}}}for(const Y of c.features){let K=I.findIndex(ae=>Y.start>=ae);K===-1&&(K=I.length),I[K]=Y.end;const re=(Y.start-l.start)/G*t,ue=Math.max(2,(Y.end-Y.start)/G*t),pe=K*(M+_y)+2;if(pe+M>n){R++;continue}const fe=_c(Y.feature_type,e,u);if(Y.sub_features&&Y.sub_features.length>0){O.fillStyle=fe+"66",O.fillRect(re,pe+M/2-1,ue,2);for(const ae of Y.sub_features){const ie=(ae.start-l.start)/G*t,te=Math.max(1,(ae.end-ae.start)/G*t),ge=_c(ae.feature_type,e,u),_e=ae.feature_type==="CDS"?M:M-6,ye=ae.feature_type==="CDS"?pe:pe+3;g?Pc(O,ge,ie,ye,te,_e,ae.strand||Y.strand):(O.fillStyle=ge,O.fillRect(ie,ye,te,_e))}}else g?Pc(O,fe,re,pe,ue,M,Y.strand):(O.fillStyle=fe,O.fillRect(re,pe,ue,M));if(B){const ae=Math.max(Y.start,l.start),ie=Math.min(Y.end,l.end);for(let te=ae;te<ie;te++)if(p&&te>=p.start&&te<p.end){const ge=(p.sequence[te-p.start]||"").toUpperCase(),_e=(te-l.start)/G*t,ye=F;ye>=6&&(O.fillStyle=jc[ge]||"#999",O.font=`bold ${Math.min(10,ye-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(ge,_e+ye/2,pe+M/2))}}else if(ue>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=Y.name||Y.feature_type,ie=Math.floor((ue-(g?Cp:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),re+3,pe+M-4)}A.push({feat:Y,x:re,y:pe,w:ue,h:M})}v.current=A,r&&r(R>0?`${R} feature${R>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,p,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(j=>{const U=o.current;if(!U)return;const O=U.getBoundingClientRect(),G=(j.clientX-O.left)*(t/O.width),F=(j.clientY-O.top)*(n/O.height);for(const B of v.current)if(G>=B.x&&G<=B.x+B.w&&F>=B.y&&F<=B.y+B.h){const M=Math.min(j.clientX+14,window.innerWidth-300),I=Math.min(j.clientY+14,window.innerHeight-260);x({feat:B.feat,x:Math.max(4,M),y:Math.max(4,I)});return}x(null)},[t,n]),S=C.useCallback(()=>x(null),[]),E=C.useCallback(j=>{const U=o.current;if(!U||!l)return;const O=U.getBoundingClientRect(),G=(j.clientX-O.left)*(t/O.width),F=(j.clientY-O.top)*(n/O.height);for(const B of v.current)if(G>=B.x&&G<=B.x+B.w&&F>=B.y&&F<=B.y+B.h){const M=B.feat,A=(M.end-M.start)*.15/(1-.3),R=M.start-A,b=M.end+A;i(l.chrom,R,b),x(null);return}},[t,n,l,i]),k=y?My(y.feat,s,l==null?void 0:l.chrom):[],P=y?Dn.createPortal(a.jsxs("div",{style:{position:"fixed",left:y.x,top:y.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[a.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:y.feat.name||y.feat.feature_type}),a.jsx(Jt,{label:"Type",value:y.feat.feature_type}),a.jsx(Jt,{label:"Strand",value:y.feat.strand||"."}),a.jsx(Jt,{label:"Location",value:`${y.feat.start.toLocaleString()}–${y.feat.end.toLocaleString()}`}),a.jsx(Jt,{label:"Length",value:`${(y.feat.end-y.feat.start).toLocaleString()} bp`}),((N=y.feat.attributes)==null?void 0:N.gene)&&y.feat.attributes.gene!==y.feat.name&&a.jsx(Jt,{label:"Gene",value:y.feat.attributes.gene}),(($=y.feat.attributes)==null?void 0:$.locus_tag)&&a.jsx(Jt,{label:"Locus",value:y.feat.attributes.locus_tag}),((_=y.feat.attributes)==null?void 0:_.product)&&a.jsx(Jt,{label:"Product",value:y.feat.attributes.product}),((H=y.feat.attributes)==null?void 0:H.note)&&a.jsx(Jt,{label:"Note",value:String(y.feat.attributes.note).slice(0,120)}),k.length>0&&a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:a.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),k.map(j=>a.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[a.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:j.name}),a.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:j.total.toFixed(1)})]},j.trackId))]})]}),document.body):null;return a.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:S,onDoubleClick:E}),P]})}function Jt({label:e,value:t}){return t?a.jsxs("div",{style:{display:"flex",gap:6},children:[a.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),a.jsx("span",{children:t})]}):null}function My(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=K0(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let s=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),h=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));s+=c+h}s>0&&r.push({trackId:l.id,name:l.name,total:s})}return r}function Pc(e,t,n,r,o,l,i){e.fillStyle=t;const s=Math.min(Cp,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-s,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-s,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+s,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+s,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function _c(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function By({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=it(),{theme:i}=Ye(),{data:s,loading:u}=Jl(e,l,t);return C.useEffect(()=>{var p,f;const c=o.current;if(!c)return;const h=window.devicePixelRatio||1;c.width=t*h,c.height=n*h;const d=c.getContext("2d");if(d.scale(h,h),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((p=s==null?void 0:s.variants)!=null&&p.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((f=s==null?void 0:s.variants)!=null&&f.length)){s&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const g=l.end-l.start,T=e.barAutoWidth!==!1,v=e.barWidth||2,y=T?1:Math.max(.5,v),x=T?5:Math.max(2,v*2);for(const m of s.variants){const w=(m.pos-l.start)/g*t,S=Ay(m.ref,m.alt);d.strokeStyle=S,d.lineWidth=y,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=S,d.beginPath(),d.arc(w,10,x,0,Math.PI*2),d.fill(),g<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=s.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[s,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ay(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function zy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return a.jsxs(a.Fragment,{children:[a.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&Dn.createPortal(a.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function $y({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=it(),{theme:s}=Ye(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback($=>{d({x:$.clientX,y:$.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const y=o.end-o.start;if(y<=0)return null;const x=(l.start-o.start)/y,p=(l.end-o.start)/y,f=Math.max(0,x*e),w=Math.min(e,p*e)-f;if(w<1)return null;const S=Ny(l,n,r),E=l.end-l.start,k=260,P=Math.min(h.x+14,window.innerWidth-k-10),N=Math.min(h.y+14,window.innerHeight-200);return a.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[a.jsx("div",{style:{position:"absolute",left:f,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:T,onMouseLeave:v,onClick:$=>{$.stopPropagation(),i()}}),u&&Dn.createPortal(a.jsxs("div",{style:{position:"fixed",left:P,top:N,background:s.panelBg,border:`1px solid ${s.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:s.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:k},children:[a.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Length:"})," ",E.toLocaleString()," bp"]}),S.map(($,_)=>a.jsxs("div",{children:[a.jsxs("span",{style:{color:s.textSecondary},children:[$.label,":"]})," ",$.value]},_)),a.jsx("div",{style:{fontSize:9,color:s.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Ny(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const s=i.cigar.match(/(\d+)I/g);if(s)for(const u of s)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((s,u)=>s+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,h)=>c+h,0)/l.length,s=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:s.toFixed(1)}),u!==s&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Oy extends C.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?a.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function Fy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:s,onDrop:u,onDragEnd:c}){const{theme:h}=Ye(),{updateTrack:d,removeTrack:g}=Kt(),T=C.useRef(null),v=C.useRef(null),[y,x]=C.useState(!1),[p,f]=C.useState(!1),[m,w]=C.useState(null),S=C.useRef(null),E=C.useRef(null),k=e.track_type==="annotations"||e.track_type==="genome_annotations";bp(T);const P=["#78909c","#66bb6a","#42a5f5","#ffa726","#f06292","#ab47bc","#26c6da","#ef5350","#8d6e63","#fff176","#ff8a65","#80cbc4","#9575cd","#aed581","#4dd0e1","#e57373","#ffb74d","#81c784","#64b5f6","#ce93d8"],N=t-n,$={row:{display:"flex",borderBottom:`1px solid ${h.border}`,minHeight:40},label:{width:n,minWidth:n,background:h.panelBg,borderRight:`1px solid ${h.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:h.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:h.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},_=C.useCallback(j=>{j.preventDefault(),j.stopPropagation();const U=j.clientY,O=e.height;function G(B){const M=Math.max(30,Math.min(500,O+(B.clientY-U)));d(e.id,{height:M})}function F(){window.removeEventListener("mousemove",G),window.removeEventListener("mouseup",F),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",G),window.addEventListener("mouseup",F)},[e.id,e.height,d]);function H(){const j={track:e,width:N,height:e.height,onWarning:w};switch(e.track_type){case"reads":return a.jsx(Ty,{...j});case"coverage":return a.jsx(wy,{...j});case"variants":return a.jsx(By,{...j});case"annotations":case"genome_annotations":return a.jsx(Ly,{...j});default:return a.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return a.jsxs("div",{style:{...$.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:j=>{j.preventDefault(),j.dataTransfer.dropEffect="move",s==null||s()},onDrop:j=>{j.preventDefault(),u==null||u()},onDragEnd:c,children:[a.jsxs("div",{style:$.label,children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsx("div",{draggable:!0,onDragStart:j=>{j.dataTransfer.effectAllowed="move",j.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:h.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),a.jsx("div",{ref:S,children:k?a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:j=>{j.stopPropagation(),f(U=>!U)}}),p&&Dn.createPortal(a.jsx(Wy,{track:e,theme:h,anchorRef:S,onClose:()=>f(!1),onChange:(j,U)=>{const O={...e.annotationColors||{},[j]:U};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:j=>{j.stopPropagation(),x(!0)},onDoubleClick:j=>{var U;j.stopPropagation(),x(!1),(U=E.current)==null||U.click()}}),a.jsx("input",{ref:E,type:"color",value:e.color||"#78909c",onChange:j=>d(e.id,{color:j.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),y&&Dn.createPortal(a.jsx("div",{style:{position:"fixed",left:S.current?S.current.getBoundingClientRect().left:0,top:S.current?S.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:h.panelBg,border:`1px solid ${h.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>x(!1),children:P.map(j=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:j,cursor:"pointer",border:j===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:j}),x(!1)}},j))}),document.body)]})}),a.jsx("div",{style:{...$.trackName,flex:1},title:e.name,children:e.name}),a.jsx("span",{title:"Remove track",onClick:j=>{j.stopPropagation(),g(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:j=>j.currentTarget.style.opacity="1",onMouseLeave:j=>j.currentTarget.style.opacity="0.7",children:"×"})]}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsxs("div",{style:$.trackType,children:[e.file_format," · ",e.track_type]}),m&&a.jsx(zy,{message:m,theme:h})]}),r&&a.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:j=>j.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:j=>j.currentTarget.style.background="transparent"})]}),a.jsxs("div",{style:$.trackArea,ref:T,children:[a.jsx(Oy,{children:H()}),a.jsx($y,{width:N,height:e.height,trackData:wp(e.id),trackType:e.track_type})]}),a.jsx("div",{ref:v,onMouseDown:_,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:j=>j.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:j=>j.currentTarget.style.background="transparent"})]})}const Iy=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Dy=["#66bb6a","#42a5f5","#7e57c2","#ab47bc","#26c6da","#ffa726","#ef5350","#8d6e63","#80cbc4","#78909c","#4caf50","#2196f3","#9c27b0","#e91e63","#00bcd4","#ff9800","#f44336","#795548","#009688","#607d8b","#aed581","#64b5f6","#ce93d8","#f06292","#4dd0e1"],Uy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Wy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var d;const[i,s]=C.useState(null),u=e.annotationColors||{},c=(d=n.current)==null?void 0:d.getBoundingClientRect();function h(g){return u[g]||t[Uy[g]]||_0[g]}return a.jsxs("div",{style:{position:"fixed",left:c?Math.min(c.left,window.innerWidth-220):0,top:c?c.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[a.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),Iy.map(({key:g,label:T})=>{const v=h(g);return a.jsxs("div",{children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:y=>y.currentTarget.style.background=t.selectedRow,onMouseLeave:y=>y.currentTarget.style.background="transparent",onClick:()=>s(i===g?null:g),children:[a.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:v,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0}}),a.jsx("span",{style:{flex:1},children:T}),a.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===g?"▲":"▼"})]}),i===g&&a.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Dy.map(y=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:y,cursor:"pointer",border:y===v?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(g,y),s(null)}},y))})]},g)}),a.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:a.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:g=>{g.currentTarget.style.color=t.textPrimary},onMouseLeave:g=>{g.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})})]})}function Hy({labelWidth:e}){const{genome:t,region:n}=it(),{tracks:r}=Kt(),{theme:o,themeName:l,customTheme:i}=Ye(),[s,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function y(x){x.preventDefault(),x.returnValue=""}return window.addEventListener("beforeunload",y),()=>window.removeEventListener("beforeunload",y)},[d]),C.useEffect(()=>{if(!d)return;function y(x){(x.ctrlKey||x.metaKey)&&x.key==="w"&&(x.preventDefault(),u(!0))}return window.addEventListener("keydown",y),()=>window.removeEventListener("keydown",y)},[d]);const g=C.useCallback(()=>u(!1),[]),T=C.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=C.useCallback(()=>{h(!0);try{const y=Na(t,n,r,l,i,e);Oa(y),kp(y)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return s?a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:g,children:a.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:y=>y.stopPropagation(),children:[a.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),a.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",a.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[a.jsx("button",{onClick:g,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),a.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),a.jsx("button",{onClick:T,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const Lc="2.2.1";let Vy=0;function Mc({size:e=32}){const[t]=Is.useState(()=>`blogo${++Vy}`);return a.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[a.jsxs("defs",{children:[a.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[a.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),a.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),a.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),a.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[a.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),a.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),a.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),a.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function Gy({theme:e,labelWidth:t}){return a.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[a.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[a.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),a.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),a.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),a.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),a.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function Yy(){const{theme:e}=Ye(),{genome:t,region:n,setGenome:r,navigateTo:o}=it(),{tracks:l,reorderTracks:i,addTrack:s,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Kt(),T=C.useRef(null),[v,y]=C.useState(800),[x,p]=C.useState(!1),[f,m]=C.useState(!1),[w,S]=C.useState(!1),[E,k]=C.useState(!1),[P,N]=C.useState(!1),[$,_]=C.useState(!1),[H,j]=C.useState(140),[U,O]=C.useState(null),[G,F]=C.useState(null),[B,M]=C.useState(!1),[I,A]=C.useState(null),[R,b]=C.useState(null),[D,Y]=C.useState(null),K=C.useRef(0);fy(H),C.useEffect(()=>{const z=()=>fetch("/api/heartbeat").catch(()=>{});z();const q=setInterval(z,1e4);return()=>clearInterval(q)},[]);const re=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==re.current&&(re.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ue=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),pe=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),fe=new Set([".bai"]);function ae(z){if(!z)return"";if(z.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=z.lastIndexOf(".");return q>=0?z.slice(q).toLowerCase():""}const ie=C.useCallback(z=>{var q,Q;z.preventDefault(),z.stopPropagation(),(Q=(q=z.dataTransfer)==null?void 0:q.types)!=null&&Q.includes("Files")&&(K.current++,K.current===1&&M(!0))},[]),te=C.useCallback(z=>{var q,Q;z.preventDefault(),z.stopPropagation(),(Q=(q=z.dataTransfer)==null?void 0:q.types)!=null&&Q.includes("Files")&&(K.current--,K.current<=0&&(K.current=0,M(!1)))},[]),ge=C.useCallback(z=>{z.preventDefault(),z.stopPropagation()},[]);function _e(z){const q=z==null?void 0:z.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ye=C.useCallback(async z=>{var Oe,st,Fa,Ia,Da;if(z.preventDefault(),z.stopPropagation(),K.current=0,M(!1),!((st=(Oe=z.dataTransfer)==null?void 0:Oe.types)!=null&&st.includes("Files")))return;const q=Array.from(z.dataTransfer.files);if(!q.length)return;const Q=[],Z=[],le=[],oe=[];for(const Ee of q){const Le=ae(Ee.name),mt=Ee.name.toLowerCase();ue.has(Le)?Q.push(Ee):pe.has(Le)||Le===".vcf.gz"?Z.push(Ee):fe.has(Le)||mt.endsWith(".bam.bai")?le.push(Ee):oe.push(Ee)}const de=Z.filter(Ee=>Ee.name.toLowerCase().endsWith(".bam")&&Ee.size>50*1024*1024),xe=le.filter(Ee=>Ee.size>10*1024*1024);if(de.length||xe.length){const Ee=[...de,...xe].map(mt=>mt.name).join(", "),Le=[...de,...xe].reduce((mt,Co)=>mt+Co.size,0)/(1024*1024);A({error:`${Ee} (${Le.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>A(null),1e4);return}if(oe.length&&!Q.length&&!Z.length&&!le.length){A({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Ee=>Ee.name).join(", ")}`}),setTimeout(()=>A(null),4e3);return}try{if(Q.length>0&&!t){A({msg:`Loading genome: ${Q[0].name}...`});const Le=(await mn.load(Q[0])).data;if(Le.name&&(Le.name=Nt(Le.name)),r(Le),((Fa=Le.chromosomes)==null?void 0:Fa.length)>0){const mt=Le.chromosomes[0];o(mt.name,0,Math.min(mt.length,5e4))}Le.is_annotated&&d({id:"genome_annotations",name:`${Le.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Le.annotated_chromosomes||null})}else Q.length>0&&t&&b({files:Q});if(Z.length>0){if(!t&&Q.length===0){A({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>A(null),4e3);return}A({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Ee=[],Le=[],mt=[];for(const Co of Z)try{const Sn=await u(Co,void 0);_e(Sn)?Le.push(Sn):(c(Sn),Ee.push(Sn))}catch(Sn){mt.push(`${Co.name}: ${((Da=(Ia=Sn.response)==null?void 0:Ia.data)==null?void 0:Da.detail)||Sn.message}`)}if(mt.length){A({error:mt.join("; ")}),setTimeout(()=>A(null),5e3);return}Le.length>0&&Y({tracks:Le})}oe.length?(A({error:`Skipped unsupported: ${oe.map(Ee=>Ee.name).join(", ")}`}),setTimeout(()=>A(null),4e3)):(A({msg:"Files loaded"}),setTimeout(()=>A(null),2e3))}catch(Ee){A({error:Ee.message||"Drop failed"}),setTimeout(()=>A(null),5e3)}},[t,r,o,s,d]),Ne=C.useCallback(async()=>{var q,Q;if(!R)return;const z=R.files;b(null);try{const Z=[];for(const le of z){A({msg:`Adding chromosomes from ${le.name}...`});try{const de=(await mn.addChromosomes(le)).data;de.name&&(de.name=Nt(de.name)),r(de),de.is_annotated&&d({id:"genome_annotations",name:`${de.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:de.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((Q=(q=oe.response)==null?void 0:q.data)==null?void 0:Q.detail)||oe.message}`)}}Z.length?(A({error:Z.join("; ")}),setTimeout(()=>A(null),5e3)):(A({msg:`Added chromosomes from ${z.length} file${z.length>1?"s":""}`}),setTimeout(()=>A(null),3e3))}catch(Z){A({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>A(null),5e3)}},[R,r,d]),Je=C.useCallback(async()=>{var q,Q;if(!R)return;const z=R.files;b(null);try{A({msg:`Loading ${z.length} track${z.length>1?"s":""}...`});const Z=[];for(const le of z)try{await s(le,void 0)}catch(oe){Z.push(`${le.name}: ${((Q=(q=oe.response)==null?void 0:q.data)==null?void 0:Q.detail)||oe.message}`)}Z.length?(A({error:Z.join("; ")}),setTimeout(()=>A(null),5e3)):(A({msg:`Added ${z.length} track${z.length>1?"s":""}`}),setTimeout(()=>A(null),3e3))}catch(Z){A({error:Z.message||"Failed to load tracks"}),setTimeout(()=>A(null),5e3)}},[R,s]),he=C.useCallback(async()=>{if(D){for(const z of D.tracks)await h(z.id);Y(null)}},[D,h]),ht=C.useCallback(()=>{if(D){for(const z of D.tracks)c(z);Y(null),A({msg:`Added ${D.tracks.length} track${D.tracks.length>1?"s":""}`}),setTimeout(()=>A(null),3e3)}},[D,c]),V=C.useCallback(z=>{z.preventDefault();const q=z.clientX,Q=H;function Z(oe){j(Math.max(60,Math.min(400,Q+(oe.clientX-q))))}function le(){window.removeEventListener("mousemove",Z),window.removeEventListener("mouseup",le),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Z),window.addEventListener("mouseup",le)},[H]);C.useEffect(()=>{if(!T.current)return;const z=new ResizeObserver(q=>{for(const Q of q)y(Q.contentRect.width)});return z.observe(T.current),()=>z.disconnect()},[]);const J=C.useCallback(z=>z.visible?!z.targetChromosomes||!(n!=null&&n.chrom)?!0:z.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),ee={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return a.jsxs("div",{style:ee.app,onDragEnter:ie,onDragLeave:te,onDragOver:ge,onDrop:ye,children:[a.jsxs("div",{style:ee.header,children:[a.jsxs("div",{style:ee.headerLeft,children:[a.jsx(Mc,{size:34}),a.jsxs("div",{children:[a.jsx("div",{style:ee.title,children:"BiNgo Genome Viewer"}),t&&a.jsxs("div",{style:ee.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),a.jsx("button",{onClick:()=>N(!0),title:"About",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:"50%",width:20,height:20,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:e.textSecondary,fontSize:12,fontWeight:700,lineHeight:1,padding:0,flexShrink:0},onMouseEnter:z=>{z.currentTarget.style.color=e.textPrimary,z.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:z=>{z.currentTarget.style.color=e.textSecondary,z.currentTarget.style.borderColor=e.border},children:"?"}),a.jsxs("button",{onClick:()=>_(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:z=>{z.currentTarget.style.color=e.textPrimary,z.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:z=>{z.currentTarget.style.color=e.textSecondary,z.currentTarget.style.borderColor=e.border},children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[a.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),a.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),a.jsxs("div",{style:ee.headerBtns,"data-tour":"header-btns",children:[a.jsxs("button",{style:ee.btn,onClick:()=>k(!0),title:"Save or restore a session",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[a.jsx("path",{d:"M2 2h8v8H2z"}),a.jsx("path",{d:"M4 2v4h4V2"}),a.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),a.jsxs("button",{style:ee.btn,onClick:()=>m(!0),title:"Customize color theme",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[a.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),a.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),a.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),a.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),a.jsxs("button",{"data-tour":"btn-export",style:{...ee.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&S(!0)},title:"Export current view as SVG or PNG",children:[a.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:a.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),a.jsxs("button",{"data-tour":"btn-settings",style:{...ee.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&p(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),a.jsx(O0,{}),a.jsx(yy,{}),a.jsxs("div",{style:ee.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&a.jsx(Gy,{theme:e,labelWidth:H}),t?n?a.jsxs(a.Fragment,{children:[a.jsxs("div",{style:{display:"flex"},children:[a.jsx("div",{style:{width:H,minWidth:H,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:a.jsx("div",{onMouseDown:V,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:z=>z.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:z=>z.currentTarget.style.background="transparent"})}),a.jsx(xy,{width:v-H})]}),l.filter(J).map(z=>a.jsx(Fy,{track:z,containerWidth:v,labelWidth:H,onLabelResizeStart:V,isDragging:U===z.id,isDropTarget:G===z.id,onDragStart:()=>O(z.id),onDragOver:()=>F(z.id),onDrop:()=>{U&&U!==z.id&&i(U,z.id),O(null),F(null)},onDragEnd:()=>{O(null),F(null)}},z.id)),l.length===0&&a.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):a.jsx("div",{style:ee.emptyState,children:a.jsx("div",{style:ee.emptyHint,children:"Select a chromosome to begin"})}):a.jsxs("div",{style:ee.emptyState,children:[a.jsx("div",{style:ee.emptyTitle,children:"No genome loaded"}),a.jsx("div",{style:ee.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),x&&a.jsx(D0,{onClose:()=>p(!1)}),f&&a.jsx(H0,{onClose:()=>m(!1)}),w&&a.jsx(Z0,{onClose:()=>S(!1)}),E&&a.jsx(py,{onClose:()=>k(!1),labelWidth:H,setLabelWidth:j}),$&&a.jsx(gy,{onClose:()=>{_(!1),p(!1),m(!1)},theme:e,onAction:z=>{z==="open-settings"?(p(!0),m(!1)):z==="open-theme"?(m(!0),p(!1)):(p(!1),m(!1))}}),P&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>N(!1),children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:z=>z.stopPropagation(),children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[a.jsx(Mc,{size:44}),a.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",Lc]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",Lc,") [Software]."]}),a.jsxs("details",{style:{marginBottom:20},children:[a.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),a.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),a.jsxs("div",{children:[a.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",a.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),a.jsxs("div",{children:[a.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",a.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",a.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",a.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),a.jsxs("div",{children:[a.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",a.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),a.jsx("div",{children:"Early version testing and feedback:"}),a.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),a.jsx("div",{style:{textAlign:"right"},children:a.jsx("button",{onClick:()=>N(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),R&&(()=>{const z=R.files.length>1,q=R.files.map(Q=>Q.name).join(", ");return a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:Q=>Q.stopPropagation(),children:[a.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",z?"s":""," detected"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[a.jsx("strong",{style:{color:e.textPrimary},children:q}),z?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",a.jsx("br",{}),"How would you like to handle ",z?"them":"it","?"]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:()=>b(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsxs("button",{onClick:Je,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",z?"s":""]}),a.jsxs("button",{onClick:Ne,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",z?"s":""]})]})]})})})(),D&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:z=>z.stopPropagation(),children:[a.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[D.tracks.map(z=>{var q;return a.jsxs("div",{style:{marginBottom:6},children:[a.jsx("strong",{style:{color:e.textPrimary},children:z.name})," — ",((q=z.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},z.id)}),a.jsx("div",{style:{marginTop:8},children:D.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:he,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsx("button",{onClick:ht,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),B&&a.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:a.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[a.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),a.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),I&&a.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:I.error?"#c62828":e.panelBg,border:`1px solid ${I.error?"#e53935":e.borderAccent}`,color:I.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:I.error||I.msg}),t&&a.jsx(Hy,{labelWidth:H})]})}function Qy(){return a.jsx(A0,{children:a.jsx(qm,{children:a.jsx(L0,{children:a.jsx(Yy,{})})})})}Ni.createRoot(document.getElementById("root")).render(a.jsx(Is.StrictMode,{children:a.jsx(Qy,{})}));
97
+ `):null)}},[s,u,c,t,n,l,e.color,e.scaleMax,e.scaleMin,e.logScale,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Bi(e,t,n,r,o){if(!(t.length<2)){if(e.beginPath(),e.moveTo(t[0],n[0]),o){for(let l=0;l<t.length-1;l++){const i=(t[l]+t[l+1])/2,s=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,s)}e.lineTo(t[t.length-1],n[n.length-1])}else for(let l=0;l<t.length;l++)e.lineTo(t[l],n[l]);e.strokeStyle=r,e.lineWidth=1.5,e.stroke()}}function Ar(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=e.measureText(t),s=2,u=i.width+s*2,c=12;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,u,c),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+s,r+1),e.textBaseline="alphabetic"}function Sy(e,t){const n=e.match(/^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);if(!n)return e;const r=o=>Math.max(0,Math.min(255,o+t));return`rgb(${r(parseInt(n[1],16))},${r(parseInt(n[2],16))},${r(parseInt(n[3],16))})`}const Cc=6,Ai=8,zi=14,$i=2,ky="#9c27b0",Wo=10,by={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},Cy="#ffeb3b";function Tc(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ty({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=it(),{theme:i}=Ye(),{data:s,loading:u}=Jl(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),y=e.showNucleotides!==!1,x=e.useArrows!==!1,p=e.logScale===!0,f=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",S=e.arrowSize||4,E=C.useRef(null);C.useEffect(()=>{if(l&&E.current){const N=E.current;(N.chrom!==l.chrom||Math.abs(N.start-l.start)>N.end-N.start)&&T(0)}E.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!y){h(null);return}const N=l.end-l.start;if(t/N<Cc||N>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const _=Math.max(0,l.start-500),H=l.end+500,j=`${l.chrom}:${_}-${H}`;d.current!==j&&(d.current=j,mn.sequence(l.chrom,_,H).then(U=>h({chrom:l.chrom,start:_,end:H,sequence:U.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,y]);const k=C.useCallback(N=>{var U;if(!((U=s==null?void 0:s.reads)!=null&&U.length)||!N.shiftKey&&Math.abs(N.deltaX)>Math.abs(N.deltaY))return;const $=y&&c?zi:Ai,_=Math.max(0,...s.reads.map(O=>O.row)),H=Math.floor(n/($+$i)),j=Math.max(0,_-H+2);j<=0||(N.preventDefault(),N.stopPropagation(),T(O=>Math.max(0,Math.min(j,O+Math.sign(N.deltaY)*3))))},[s,n,y,c]);C.useEffect(()=>{var Y;const N=o.current;if(!N)return;const $=window.devicePixelRatio||1;N.width=t*$,N.height=n*$;const _=N.getContext("2d");if(_.scale($,$),_.clearRect(0,0,t,n),_.fillStyle=i.canvasBg,_.fillRect(0,0,t,n),u&&!s){_.fillStyle=i.textTertiary,_.font="11px Arial, Helvetica, sans-serif",_.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!s){r&&r(null);return}const H=l.start,j=l.end-l.start;if(s.bins){const K=s.max_value||1,re=e.scaleMax!=null?e.scaleMax:K,ue=e.color||"#78909c",pe=e.barAutoWidth!==!1,fe=e.barWidth||2,ae=t/j;if(e.showBars!==!1){_.fillStyle=ue;for(const te of s.bins){const ge=(te.end-te.start)/j*t,_e=pe?ae>=1?Math.max(1,Math.min(ae,ge)):Math.max(1,ge):Math.min(fe,ge),ye=(te.start-H)/j*t,Je=(p?Tc(te.value,re):Math.min(1,te.value/re))*(n-14);_.fillRect(ye,n-Je-2,_e,Je)}}if(e.showOutline&&s.bins.length>0){const te=e.outlineSmooth||0,ge=s.bins.map(he=>p?Tc(he.value,re):Math.min(1,he.value/re)),_e=Ry(ge,te),ye=s.bins.map(he=>((he.start+he.end)/2-H)/j*t),Ne=_e.map(he=>n-he*(n-14)-2),Je=e.outlineColor||i.textPrimary||"#fff";if(_.beginPath(),_.moveTo(ye[0],Ne[0]),te>0){for(let he=0;he<ye.length-1;he++)_.quadraticCurveTo(ye[he],Ne[he],(ye[he]+ye[he+1])/2,(Ne[he]+Ne[he+1])/2);_.lineTo(ye[ye.length-1],Ne[Ne.length-1])}else for(let he=0;he<ye.length;he++)_.lineTo(ye[he],Ne[he]);_.strokeStyle=Je,_.lineWidth=1.5,_.stroke()}const ie=p?" log₂":"";Ec(_,`${re.toFixed(1)}${ie}`,2,2,i),Ec(_,"0",2,n-12,i,!0),_.fillStyle="#ffb74d",_.font="10px Arial, Helvetica, sans-serif",_.textAlign="right",_.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&K>e.scaleMax?`Bars clipped: max value ${K.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((Y=s.reads)!=null&&Y.length)){_.fillStyle=i.textTertiary,_.font="11px Arial, Helvetica, sans-serif",_.fillText("No reads in region",8,n/2+4),r&&r(null);return}const U=K=>(K-H)/j*t,O=t/j,G=y&&O>=Cc&&c!=null,F=G?zi:Ai,B=$i,I=Math.max(0,...s.reads.map(K=>K.row))+1,A=Math.floor(n/(F+B)),R=I>A,b=Math.min(g,Math.max(0,I-A+1));let D=0;for(const K of s.reads){const re=(K.row-b)*(F+B)+2;if(re+F<0||re>n){D++;continue}const ue=K.strand==="+"?f:m,pe=K.segments;if(pe&&pe.length>0){const fe=U(K.start),ae=U(K.end);_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(fe,re+F/2),_.lineTo(ae,re+F/2),_.stroke();let ie=0;for(const te of pe)if(te.type==="M"){const ge=U(te.start),_e=Math.max(1,U(te.end)-ge);if(_.fillStyle=ue,_.fillRect(ge,re,_e,F),G&&K.sequence){const ye=te.end-te.start;for(let Ne=0;Ne<ye;Ne++){const Je=te.start+Ne,he=U(Je),ht=U(Je+1)-he,V=(K.sequence[ie+Ne]||"").toUpperCase();let J="";c&&Je>=c.start&&Je<c.end&&(J=(c.sequence[Je-c.start]||"").toUpperCase());const ee=J&&V&&V!==J&&V!=="N";ee&&(_.fillStyle=Cy,_.fillRect(he,re,ht,F)),ht>=6&&(_.fillStyle=ee?"#000":by[V]||"#999",_.font=`bold ${Math.min(11,ht-1)}px monospace`,_.textAlign="center",_.textBaseline="middle",_.fillText(V,he+ht/2,re+F/2))}ie+=ye}}else if(te.type==="D"){const ge=U(te.start),_e=U(te.end)-ge;_e>=1&&(_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(ge,re+F/2),_.lineTo(ge+_e,re+F/2),_.stroke())}else if(te.type==="N"){const ge=U(te.start),_e=U(te.end)-ge;_e>=2&&(_.setLineDash([2,2]),_.strokeStyle=ue,_.lineWidth=1,_.beginPath(),_.moveTo(ge,re+F/2),_.lineTo(ge+_e,re+F/2),_.stroke(),_.setLineDash([]))}else te.type==="I"?(_.fillStyle=ky,_.fillRect(U(te.pos)-1,re-1,2,F+2),G&&(ie+=te.length)):te.type==="S"&&G&&(ie+=te.length)}else{const fe=U(K.start),ae=Math.max(2,U(K.end)-fe);_.fillStyle=K.strand==="+"?f:m,_.fillRect(fe,re,ae,F)}if(x&&w!=="flat"){const fe=U(K.start),ae=Math.max(2,U(K.end)-fe),ie=Math.min(S,ae/2);ie>=2&&Ey(_,w,K.strand,fe,re,ae,F,ie,ue,i.canvasBg)}if(!G&&!y){const fe=U(K.start);Math.max(2,U(K.end)-fe)>60&&(_.fillStyle=i.canvasBg,_.font="8px Arial, Helvetica, sans-serif",_.textAlign="left",_.fillText(K.name.slice(0,20),fe+2,re+F-1))}}if(R){const K=t-Wo;_.fillStyle=i.inputBg||"#2a2a2a",_.fillRect(K,0,Wo,n);const re=A/I,ue=Math.max(20,re*n),fe=(I>A?b/(I-A):0)*(n-ue);_.fillStyle="#555",_.fillRect(K+1,fe,Wo-2,ue)}r&&(D>0&&!R?r(`${D} read${D>1?"s":""} hidden — increase track height to show all`):r(R?`${I} rows · Shift+scroll or drag scrollbar to navigate`:null))},[s,u,t,n,l,c,g,e.color,e.scaleMax,e.scaleMin,e.barAutoWidth,e.barWidth,e.showOutline,e.outlineColor,e.outlineSmooth,e.showBars,e.showNucleotides,e.useArrows,e.logScale,e.fwdColor,e.revColor,e.arrowStyle,e.arrowSize,i]);const P=C.useCallback(N=>{var I;if(!((I=s==null?void 0:s.reads)!=null&&I.length))return;const $=o.current;if(!$)return;const _=$.getBoundingClientRect();if((N.clientX-_.left)*(t/_.width)<t-Wo)return;const j=y&&c?zi:Ai,O=Math.max(0,...s.reads.map(A=>A.row))+1,G=Math.floor(n/(j+$i)),F=Math.max(0,O-G+1);if(F<=0)return;N.preventDefault(),v.current={maxScroll:F,startY:N.clientY,startRow:g};function B(A){if(!v.current)return;const R=A.clientY-v.current.startY,b=Math.round(R/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+b)))}function M(){v.current=null,window.removeEventListener("mousemove",B),window.removeEventListener("mouseup",M)}window.addEventListener("mousemove",B),window.addEventListener("mouseup",M)},[s,t,n,g,y,c]);return a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:k,onMouseDown:P})}function Ey(e,t,n,r,o,l,i,s,u,c){const h=n==="+";if(t==="pointed")e.fillStyle=c,h?(e.beginPath(),e.moveTo(r+l,o+i/2),e.lineTo(r+l-s,o),e.lineTo(r+l-s,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+s,o),e.lineTo(r+s,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-s,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-s,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+s,o),e.lineTo(r,o+i/2),e.lineTo(r+s,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-s*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-s*2,o,s*2,i)}else{const d=e.createLinearGradient(r,0,r+s*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,s*2,i)}}function Ry(e,t){if(t<=0||e.length===0)return e;const n=new Array(e.length);for(let r=0;r<e.length;r++){let o=0,l=0;const i=Math.max(0,r-t),s=Math.min(e.length-1,r+t);for(let u=i;u<=s;u++)o+=e[u],l++;n[r]=o/l}return n}function Ec(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,s=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,s,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const jy=16,Py=22,_y=4,Cp=8,Rc=6,jc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Ly({track:e,width:t,height:n,onWarning:r}){var N,$,_,H;const o=C.useRef(null),{region:l,navigateTo:i}=it(),{tracks:s}=Kt(),{theme:u}=Ye(),{data:c,loading:h,error:d}=Jl(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[y,x]=C.useState(null),[p,f]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){f(null);return}const j=l.end-l.start;if(t/j<Rc||j>2e3){f(null);return}if(p&&p.chrom===l.chrom&&p.start<=l.start&&p.end>=l.end)return;const O=Math.max(0,l.start-500),G=l.end+500,F=`${l.chrom}:${O}-${G}`;m.current!==F&&(m.current=F,mn.sequence(l.chrom,O,G).then(B=>f({chrom:l.chrom,start:O,end:G,sequence:B.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,T]),C.useEffect(()=>{var b,D;const j=o.current;if(!j)return;const U=window.devicePixelRatio||1;j.width=t*U,j.height=n*U;const O=j.getContext("2d");if(O.scale(U,U),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((b=c==null?void 0:c.features)!=null&&b.length)){O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("Loading…",8,n/2+4),r&&r(null);return}if(d){O.fillStyle="#ef9a9a",O.font="11px Arial, Helvetica, sans-serif",O.fillText(typeof d=="string"?d:JSON.stringify(d),8,n/2+4),r&&r(null);return}if(!((D=c==null?void 0:c.features)!=null&&D.length)){c&&(O.fillStyle=u.textTertiary,O.font="11px Arial, Helvetica, sans-serif",O.fillText("No features in region",8,n/2+4)),r&&r(null);return}const G=l.end-l.start,F=t/G,B=T&&F>=Rc&&p!=null,M=B?Py:jy,I=[],A=[];let R=0;if(B){const K=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,K,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,K),O.lineTo(t,K),O.stroke();const re=Math.min(10,F-1);if(re>=5){O.font=`bold ${re}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ue=Math.floor(l.start);ue<Math.ceil(l.end);ue++)if(p&&ue>=p.start&&ue<p.end){const pe=(p.sequence[ue-p.start]||"").toUpperCase(),fe=(ue-l.start)/G*t;O.fillStyle=jc[pe]||"#999",O.fillText(pe,fe+F/2,K+14/2)}}}for(const Y of c.features){let K=I.findIndex(ae=>Y.start>=ae);K===-1&&(K=I.length),I[K]=Y.end;const re=(Y.start-l.start)/G*t,ue=Math.max(2,(Y.end-Y.start)/G*t),pe=K*(M+_y)+2;if(pe+M>n){R++;continue}const fe=_c(Y.feature_type,e,u);if(Y.sub_features&&Y.sub_features.length>0){O.fillStyle=fe+"66",O.fillRect(re,pe+M/2-1,ue,2);for(const ae of Y.sub_features){const ie=(ae.start-l.start)/G*t,te=Math.max(1,(ae.end-ae.start)/G*t),ge=_c(ae.feature_type,e,u),_e=ae.feature_type==="CDS"?M:M-6,ye=ae.feature_type==="CDS"?pe:pe+3;g?Pc(O,ge,ie,ye,te,_e,ae.strand||Y.strand):(O.fillStyle=ge,O.fillRect(ie,ye,te,_e))}}else g?Pc(O,fe,re,pe,ue,M,Y.strand):(O.fillStyle=fe,O.fillRect(re,pe,ue,M));if(B){const ae=Math.max(Y.start,l.start),ie=Math.min(Y.end,l.end);for(let te=ae;te<ie;te++)if(p&&te>=p.start&&te<p.end){const ge=(p.sequence[te-p.start]||"").toUpperCase(),_e=(te-l.start)/G*t,ye=F;ye>=6&&(O.fillStyle=jc[ge]||"#999",O.font=`bold ${Math.min(10,ye-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(ge,_e+ye/2,pe+M/2))}}else if(ue>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=Y.name||Y.feature_type,ie=Math.floor((ue-(g?Cp:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),re+3,pe+M-4)}A.push({feat:Y,x:re,y:pe,w:ue,h:M})}v.current=A,r&&r(R>0?`${R} feature${R>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,p,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(j=>{const U=o.current;if(!U)return;const O=U.getBoundingClientRect(),G=(j.clientX-O.left)*(t/O.width),F=(j.clientY-O.top)*(n/O.height);for(const B of v.current)if(G>=B.x&&G<=B.x+B.w&&F>=B.y&&F<=B.y+B.h){const M=Math.min(j.clientX+14,window.innerWidth-300),I=Math.min(j.clientY+14,window.innerHeight-260);x({feat:B.feat,x:Math.max(4,M),y:Math.max(4,I)});return}x(null)},[t,n]),S=C.useCallback(()=>x(null),[]),E=C.useCallback(j=>{const U=o.current;if(!U||!l)return;const O=U.getBoundingClientRect(),G=(j.clientX-O.left)*(t/O.width),F=(j.clientY-O.top)*(n/O.height);for(const B of v.current)if(G>=B.x&&G<=B.x+B.w&&F>=B.y&&F<=B.y+B.h){const M=B.feat,A=(M.end-M.start)*.15/(1-.3),R=M.start-A,b=M.end+A;i(l.chrom,R,b),x(null);return}},[t,n,l,i]),k=y?My(y.feat,s,l==null?void 0:l.chrom):[],P=y?Dn.createPortal(a.jsxs("div",{style:{position:"fixed",left:y.x,top:y.y,background:u.tooltipBg,border:`1px solid ${u.tooltipBorder}`,borderRadius:4,padding:"6px 10px",color:u.textPrimary,fontSize:11,lineHeight:1.5,maxWidth:280,zIndex:1e4,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:[a.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:y.feat.name||y.feat.feature_type}),a.jsx(Jt,{label:"Type",value:y.feat.feature_type}),a.jsx(Jt,{label:"Strand",value:y.feat.strand||"."}),a.jsx(Jt,{label:"Location",value:`${y.feat.start.toLocaleString()}–${y.feat.end.toLocaleString()}`}),a.jsx(Jt,{label:"Length",value:`${(y.feat.end-y.feat.start).toLocaleString()} bp`}),((N=y.feat.attributes)==null?void 0:N.gene)&&y.feat.attributes.gene!==y.feat.name&&a.jsx(Jt,{label:"Gene",value:y.feat.attributes.gene}),(($=y.feat.attributes)==null?void 0:$.locus_tag)&&a.jsx(Jt,{label:"Locus",value:y.feat.attributes.locus_tag}),((_=y.feat.attributes)==null?void 0:_.product)&&a.jsx(Jt,{label:"Product",value:y.feat.attributes.product}),((H=y.feat.attributes)==null?void 0:H.note)&&a.jsx(Jt,{label:"Note",value:String(y.feat.attributes.note).slice(0,120)}),k.length>0&&a.jsxs(a.Fragment,{children:[a.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:a.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),k.map(j=>a.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[a.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:j.name}),a.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:j.total.toFixed(1)})]},j.trackId))]})]}),document.body):null;return a.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:S,onDoubleClick:E}),P]})}function Jt({label:e,value:t}){return t?a.jsxs("div",{style:{display:"flex",gap:6},children:[a.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),a.jsx("span",{children:t})]}):null}function My(e,t,n){var o;if(!e||!n)return[];const r=[];for(const l of t){if(l.track_type!=="coverage"&&l.track_type!=="reads")continue;const i=K0(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let s=0;for(const u of i.bins){if(u.end<=e.start||u.start>=e.end)continue;const c=u.forward!=null?u.forward:Math.max(0,u.value||0),h=u.reverse!=null?Math.abs(u.reverse):Math.abs(Math.min(0,u.value||0));s+=c+h}s>0&&r.push({trackId:l.id,name:l.name,total:s})}return r}function Pc(e,t,n,r,o,l,i){e.fillStyle=t;const s=Math.min(Cp,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-s,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-s,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+s,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+s,r+l),e.lineTo(n,r+l/2),e.closePath()):e.rect(n,r,o,l),e.fill(),e.strokeStyle="rgba(0,0,0,0.25)",e.lineWidth=.5,e.stroke()}function _c(e,t,n){const r=t.annotationColors;switch(e==null?void 0:e.toLowerCase()){case"cds":return(r==null?void 0:r.cds)||(n==null?void 0:n.geneCds)||"#66bb6a";case"exon":return(r==null?void 0:r.exon)||(n==null?void 0:n.geneExon)||"#42a5f5";case"gene":return(r==null?void 0:r.gene)||(n==null?void 0:n.geneGene)||"#7e57c2";case"mrna":case"transcript":return(r==null?void 0:r.transcript)||(n==null?void 0:n.geneTranscript)||"#ab47bc";case"utr":case"3utr":case"5utr":return(r==null?void 0:r.utr)||(n==null?void 0:n.geneUtr)||"#26c6da";case"rrna":return(r==null?void 0:r.rrna)||(n==null?void 0:n.geneRrna)||"#ffa726";case"trna":return(r==null?void 0:r.trna)||(n==null?void 0:n.geneTrna)||"#ef5350";case"repeat_region":return(r==null?void 0:r.repeat)||(n==null?void 0:n.geneRepeat)||"#8d6e63";default:return(r==null?void 0:r.default)||t.color||(n==null?void 0:n.geneDefault)||"#80cbc4"}}function By({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=it(),{theme:i}=Ye(),{data:s,loading:u}=Jl(e,l,t);return C.useEffect(()=>{var p,f;const c=o.current;if(!c)return;const h=window.devicePixelRatio||1;c.width=t*h,c.height=n*h;const d=c.getContext("2d");if(d.scale(h,h),d.clearRect(0,0,t,n),d.fillStyle=i.canvasBg,d.fillRect(0,0,t,n),u&&!((p=s==null?void 0:s.variants)!=null&&p.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((f=s==null?void 0:s.variants)!=null&&f.length)){s&&(d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("No variants in region",8,n/2+4)),r&&r(null);return}const g=l.end-l.start,T=e.barAutoWidth!==!1,v=e.barWidth||2,y=T?1:Math.max(.5,v),x=T?5:Math.max(2,v*2);for(const m of s.variants){const w=(m.pos-l.start)/g*t,S=Ay(m.ref,m.alt);d.strokeStyle=S,d.lineWidth=y,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=S,d.beginPath(),d.arc(w,10,x,0,Math.PI*2),d.fill(),g<5e3&&(d.fillStyle=i.textPrimary,d.font="9px Arial, Helvetica, sans-serif",d.textAlign="center",d.fillText(`${m.ref}>${m.alt[0]||"?"}`,w,n-6))}if(r){const m=s.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[s,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),a.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ay(e,t){const n=t[0]||"";return e.length===1&&n.length===1?"#ffb74d":n.length>e.length?"#81c784":n.length<e.length?"#e57373":"#b0bec5"}function zy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return a.jsxs(a.Fragment,{children:[a.jsx("span",{ref:o,onMouseEnter:()=>r(!0),onMouseLeave:()=>r(!1),style:{display:"inline-flex",alignItems:"center",justifyContent:"center",width:12,height:12,borderRadius:"50%",background:"rgba(229, 57, 53, 0.85)",color:"#fff",fontSize:9,fontWeight:800,lineHeight:1,cursor:"default",flexShrink:0,fontFamily:"Arial, Helvetica, sans-serif"},children:"!"}),n&&l&&Dn.createPortal(a.jsx("div",{style:{position:"fixed",left:Math.min(l.right+6,window.innerWidth-220),top:l.top-4,background:t.tooltipBg||"#333",border:`1px solid ${t.tooltipBorder||"#555"}`,borderRadius:4,padding:"4px 8px",color:t.textPrimary||"#e0e0e0",fontSize:11,lineHeight:1.4,maxWidth:200,zIndex:10001,pointerEvents:"none",boxShadow:"0 3px 10px rgba(0,0,0,0.5)",whiteSpace:"pre-wrap",fontFamily:"Arial, Helvetica, sans-serif"},children:e}),document.body)]})}function $y({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=it(),{theme:s}=Ye(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback($=>{d({x:$.clientX,y:$.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const y=o.end-o.start;if(y<=0)return null;const x=(l.start-o.start)/y,p=(l.end-o.start)/y,f=Math.max(0,x*e),w=Math.min(e,p*e)-f;if(w<1)return null;const S=Ny(l,n,r),E=l.end-l.start,k=260,P=Math.min(h.x+14,window.innerWidth-k-10),N=Math.min(h.y+14,window.innerHeight-200);return a.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[a.jsx("div",{style:{position:"absolute",left:f,top:0,width:w,height:"100%",background:"rgba(100, 181, 246, 0.2)",borderLeft:"1px solid rgba(100, 181, 246, 0.6)",borderRight:"1px solid rgba(100, 181, 246, 0.6)",pointerEvents:"auto",cursor:"crosshair"},onMouseMove:T,onMouseLeave:v,onClick:$=>{$.stopPropagation(),i()}}),u&&Dn.createPortal(a.jsxs("div",{style:{position:"fixed",left:P,top:N,background:s.panelBg,border:`1px solid ${s.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:s.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:k},children:[a.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),a.jsxs("div",{children:[a.jsx("span",{style:{color:s.textSecondary},children:"Length:"})," ",E.toLocaleString()," bp"]}),S.map(($,_)=>a.jsxs("div",{children:[a.jsxs("span",{style:{color:s.textSecondary},children:[$.label,":"]})," ",$.value]},_)),a.jsx("div",{style:{fontSize:9,color:s.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Ny(e,t,n){const r=[];if(!t)return r;if(n==="reads"&&t.reads){const o=t.reads.filter(i=>i.end>e.start&&i.start<e.end);r.push({label:"Reads in region",value:o.length.toLocaleString()});let l=0;for(const i of o)if(i.cigar){const s=i.cigar.match(/(\d+)I/g);if(s)for(const u of s)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((s,u)=>s+(u.mapq||0),0)/o.length;r.push({label:"Avg MAPQ",value:i.toFixed(1)})}}if((n==="coverage"||n==="reads")&&t.bins){const o=t.bins.filter(l=>l.end>e.start&&l.start<e.end);if(o.length>0){const l=o.map(c=>c.value),i=l.reduce((c,h)=>c+h,0)/l.length,s=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:s.toFixed(1)}),u!==s&&r.push({label:"Min coverage",value:u.toFixed(1)})}}if(n==="variants"&&t.variants){const o=t.variants.filter(l=>l.pos>=e.start&&l.pos<e.end);r.push({label:"Variants in region",value:o.length.toLocaleString()})}if((n==="annotations"||n==="genome_annotations")&&t.features){const o=t.features.filter(l=>l.end>e.start&&l.start<e.end);r.push({label:"Features in region",value:o.length.toLocaleString()})}return r}class Oy extends C.Component{constructor(t){super(t),this.state={hasError:!1,error:null}}static getDerivedStateFromError(t){return{hasError:!0,error:t}}render(){var t;return this.state.hasError?a.jsxs("div",{style:{padding:8,color:"#ef9a9a",fontSize:11},children:["Track error: ",((t=this.state.error)==null?void 0:t.message)||"Unknown error"]}):this.props.children}}function Fy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:s,onDrop:u,onDragEnd:c}){const{theme:h}=Ye(),{updateTrack:d,removeTrack:g}=Kt(),T=C.useRef(null),v=C.useRef(null),[y,x]=C.useState(!1),[p,f]=C.useState(!1),[m,w]=C.useState(null),S=C.useRef(null),E=C.useRef(null),k=e.track_type==="annotations"||e.track_type==="genome_annotations";bp(T);const P=["#78909c","#66bb6a","#42a5f5","#ffa726","#f06292","#ab47bc","#26c6da","#ef5350","#8d6e63","#fff176","#ff8a65","#80cbc4","#9575cd","#aed581","#4dd0e1","#e57373","#ffb74d","#81c784","#64b5f6","#ce93d8"],N=t-n,$={row:{display:"flex",borderBottom:`1px solid ${h.border}`,minHeight:40},label:{width:n,minWidth:n,background:h.panelBg,borderRight:`1px solid ${h.border}`,display:"flex",flexDirection:"column",justifyContent:"center",padding:"4px 8px",overflow:"hidden",position:"relative"},trackName:{fontSize:11,color:h.trackName,fontWeight:600,whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},trackType:{fontSize:10,color:h.textTertiary,marginTop:2},trackArea:{flex:1,overflow:"hidden",position:"relative"}},_=C.useCallback(j=>{j.preventDefault(),j.stopPropagation();const U=j.clientY,O=e.height;function G(B){const M=Math.max(30,Math.min(500,O+(B.clientY-U)));d(e.id,{height:M})}function F(){window.removeEventListener("mousemove",G),window.removeEventListener("mouseup",F),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",G),window.addEventListener("mouseup",F)},[e.id,e.height,d]);function H(){const j={track:e,width:N,height:e.height,onWarning:w};switch(e.track_type){case"reads":return a.jsx(Ty,{...j});case"coverage":return a.jsx(wy,{...j});case"variants":return a.jsx(By,{...j});case"annotations":case"genome_annotations":return a.jsx(Ly,{...j});default:return a.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return a.jsxs("div",{style:{...$.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:j=>{j.preventDefault(),j.dataTransfer.dropEffect="move",s==null||s()},onDrop:j=>{j.preventDefault(),u==null||u()},onDragEnd:c,children:[a.jsxs("div",{style:$.label,children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsx("div",{draggable:!0,onDragStart:j=>{j.dataTransfer.effectAllowed="move",j.dataTransfer.setData("text/plain",e.id),i==null||i()},style:{cursor:"grab",color:h.textMuted,fontSize:14,lineHeight:1,userSelect:"none",flexShrink:0,padding:"0 2px"},title:"Drag to reorder tracks",children:"≡"}),a.jsx("div",{ref:S,children:k?a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:"#888",cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)",backgroundImage:"linear-gradient(135deg, #ef5350 25%, #66bb6a 25%, #66bb6a 50%, #42a5f5 50%, #42a5f5 75%, #ffa726 75%)"},title:"Click to customize annotation colors",onMouseDown:j=>{j.stopPropagation(),f(U=>!U)}}),p&&Dn.createPortal(a.jsx(Wy,{track:e,theme:h,anchorRef:S,onClose:()=>f(!1),onChange:(j,U)=>{const O={...e.annotationColors||{},[j]:U};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):a.jsxs(a.Fragment,{children:[a.jsx("span",{style:{display:"inline-block",width:10,height:10,borderRadius:2,background:e.color,cursor:"pointer",verticalAlign:"middle",border:"1px solid rgba(255,255,255,0.2)"},title:"Click to pick color, double-click for full palette",onMouseDown:j=>{j.stopPropagation(),x(!0)},onDoubleClick:j=>{var U;j.stopPropagation(),x(!1),(U=E.current)==null||U.click()}}),a.jsx("input",{ref:E,type:"color",value:e.color||"#78909c",onChange:j=>d(e.id,{color:j.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),y&&Dn.createPortal(a.jsx("div",{style:{position:"fixed",left:S.current?S.current.getBoundingClientRect().left:0,top:S.current?S.current.getBoundingClientRect().bottom+4:0,zIndex:10001,background:h.panelBg,border:`1px solid ${h.borderAccent}`,borderRadius:4,padding:6,boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},onMouseLeave:()=>x(!1),children:P.map(j=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:j,cursor:"pointer",border:j===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:j}),x(!1)}},j))}),document.body)]})}),a.jsx("div",{style:{...$.trackName,flex:1},title:e.name,children:e.name}),a.jsx("span",{title:"Remove track",onClick:j=>{j.stopPropagation(),g(e.id)},style:{color:"#e53935",fontSize:13,fontWeight:700,cursor:"pointer",lineHeight:1,flexShrink:0,padding:"0 2px",opacity:.7,transition:"opacity 0.15s"},onMouseEnter:j=>j.currentTarget.style.opacity="1",onMouseLeave:j=>j.currentTarget.style.opacity="0.7",children:"×"})]}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[a.jsxs("div",{style:$.trackType,children:[e.file_format," · ",e.track_type]}),m&&a.jsx(zy,{message:m,theme:h})]}),r&&a.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:j=>j.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:j=>j.currentTarget.style.background="transparent"})]}),a.jsxs("div",{style:$.trackArea,ref:T,children:[a.jsx(Oy,{children:H()}),a.jsx($y,{width:N,height:e.height,trackData:wp(e.id),trackType:e.track_type})]}),a.jsx("div",{ref:v,onMouseDown:_,title:"Drag to resize track height",style:{position:"absolute",left:0,right:0,bottom:-2,height:5,cursor:"ns-resize",zIndex:10,background:"transparent"},onMouseEnter:j=>j.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:j=>j.currentTarget.style.background="transparent"})]})}const Iy=[{key:"cds",label:"CDS"},{key:"exon",label:"Exon"},{key:"gene",label:"Gene"},{key:"transcript",label:"Transcript"},{key:"utr",label:"UTR"},{key:"rrna",label:"rRNA"},{key:"trna",label:"tRNA"},{key:"repeat",label:"Repeat"},{key:"default",label:"Other"}],Dy=["#66bb6a","#42a5f5","#7e57c2","#ab47bc","#26c6da","#ffa726","#ef5350","#8d6e63","#80cbc4","#78909c","#4caf50","#2196f3","#9c27b0","#e91e63","#00bcd4","#ff9800","#f44336","#795548","#009688","#607d8b","#aed581","#64b5f6","#ce93d8","#f06292","#4dd0e1"],Uy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Wy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var d;const[i,s]=C.useState(null),u=e.annotationColors||{},c=(d=n.current)==null?void 0:d.getBoundingClientRect();function h(g){return u[g]||t[Uy[g]]||_0[g]}return a.jsxs("div",{style:{position:"fixed",left:c?Math.min(c.left,window.innerWidth-220):0,top:c?c.bottom+4:0,zIndex:10001,background:t.panelBg,border:`1px solid ${t.borderAccent}`,borderRadius:6,padding:"8px 0",boxShadow:"0 6px 20px rgba(0,0,0,0.5)",width:210,maxHeight:340,overflowY:"auto"},onMouseLeave:r,children:[a.jsx("div",{style:{fontSize:10,fontWeight:700,color:t.textSecondary,textTransform:"uppercase",letterSpacing:1,padding:"0 10px 6px",borderBottom:`1px solid ${t.border}`,marginBottom:4},children:"Annotation Colors"}),Iy.map(({key:g,label:T})=>{const v=h(g);return a.jsxs("div",{children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:y=>y.currentTarget.style.background=t.selectedRow,onMouseLeave:y=>y.currentTarget.style.background="transparent",onClick:()=>s(i===g?null:g),children:[a.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:v,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0}}),a.jsx("span",{style:{flex:1},children:T}),a.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===g?"▲":"▼"})]}),i===g&&a.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Dy.map(y=>a.jsx("span",{style:{width:18,height:18,borderRadius:3,background:y,cursor:"pointer",border:y===v?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(g,y),s(null)}},y))})]},g)}),a.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:a.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:g=>{g.currentTarget.style.color=t.textPrimary},onMouseLeave:g=>{g.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})})]})}function Hy({labelWidth:e}){const{genome:t,region:n}=it(),{tracks:r}=Kt(),{theme:o,themeName:l,customTheme:i}=Ye(),[s,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function y(x){x.preventDefault(),x.returnValue=""}return window.addEventListener("beforeunload",y),()=>window.removeEventListener("beforeunload",y)},[d]),C.useEffect(()=>{if(!d)return;function y(x){(x.ctrlKey||x.metaKey)&&x.key==="w"&&(x.preventDefault(),u(!0))}return window.addEventListener("keydown",y),()=>window.removeEventListener("keydown",y)},[d]);const g=C.useCallback(()=>u(!1),[]),T=C.useCallback(()=>{window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[]),v=C.useCallback(()=>{h(!0);try{const y=Na(t,n,r,l,i,e);Oa(y),kp(y)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return s?a.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4,background:"rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center"},onClick:g,children:a.jsxs("div",{style:{background:o.panelBg,border:`1px solid ${o.borderAccent}`,borderRadius:8,padding:"24px 28px",maxWidth:400,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.6)"},onClick:y=>y.stopPropagation(),children:[a.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),a.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",a.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[a.jsx("button",{onClick:g,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Return to App"}),a.jsx("button",{onClick:v,disabled:c,style:{background:o.btnBg,border:`1px solid ${o.borderStrong}`,borderRadius:4,color:o.btnText,padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:c?"Saving...":"Save Session & Exit"}),a.jsx("button",{onClick:T,style:{background:"transparent",border:`1px solid ${o.border}`,borderRadius:4,color:"#e57373",padding:"8px 16px",cursor:"pointer",fontSize:13,fontWeight:600,width:"100%"},children:"Exit Without Saving"})]})]})}):null}const Lc="2.2.3";let Vy=0;function Mc({size:e=32}){const[t]=Is.useState(()=>`blogo${++Vy}`);return a.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[a.jsxs("defs",{children:[a.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[a.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),a.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),a.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),a.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[a.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),a.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),a.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),a.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),a.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),a.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function Gy({theme:e,labelWidth:t}){return a.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[a.jsx("div",{"data-tour":"skeleton-track-label",style:{width:t,minWidth:t,background:e.panelBg,borderRight:`1px solid ${e.border}`,padding:"6px 8px",display:"flex",flexDirection:"column",justifyContent:"center",gap:4},children:a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[a.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),a.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),a.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),a.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),a.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function Yy(){const{theme:e}=Ye(),{genome:t,region:n,setGenome:r,navigateTo:o}=it(),{tracks:l,reorderTracks:i,addTrack:s,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Kt(),T=C.useRef(null),[v,y]=C.useState(800),[x,p]=C.useState(!1),[f,m]=C.useState(!1),[w,S]=C.useState(!1),[E,k]=C.useState(!1),[P,N]=C.useState(!1),[$,_]=C.useState(!1),[H,j]=C.useState(140),[U,O]=C.useState(null),[G,F]=C.useState(null),[B,M]=C.useState(!1),[I,A]=C.useState(null),[R,b]=C.useState(null),[D,Y]=C.useState(null),K=C.useRef(0);fy(H),C.useEffect(()=>{const z=()=>fetch("/api/heartbeat").catch(()=>{});z();const q=setInterval(z,1e4);return()=>clearInterval(q)},[]);const re=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==re.current&&(re.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ue=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),pe=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),fe=new Set([".bai"]);function ae(z){if(!z)return"";if(z.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=z.lastIndexOf(".");return q>=0?z.slice(q).toLowerCase():""}const ie=C.useCallback(z=>{var q,Q;z.preventDefault(),z.stopPropagation(),(Q=(q=z.dataTransfer)==null?void 0:q.types)!=null&&Q.includes("Files")&&(K.current++,K.current===1&&M(!0))},[]),te=C.useCallback(z=>{var q,Q;z.preventDefault(),z.stopPropagation(),(Q=(q=z.dataTransfer)==null?void 0:q.types)!=null&&Q.includes("Files")&&(K.current--,K.current<=0&&(K.current=0,M(!1)))},[]),ge=C.useCallback(z=>{z.preventDefault(),z.stopPropagation()},[]);function _e(z){const q=z==null?void 0:z.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ye=C.useCallback(async z=>{var Oe,st,Fa,Ia,Da;if(z.preventDefault(),z.stopPropagation(),K.current=0,M(!1),!((st=(Oe=z.dataTransfer)==null?void 0:Oe.types)!=null&&st.includes("Files")))return;const q=Array.from(z.dataTransfer.files);if(!q.length)return;const Q=[],Z=[],le=[],oe=[];for(const Ee of q){const Le=ae(Ee.name),mt=Ee.name.toLowerCase();ue.has(Le)?Q.push(Ee):pe.has(Le)||Le===".vcf.gz"?Z.push(Ee):fe.has(Le)||mt.endsWith(".bam.bai")?le.push(Ee):oe.push(Ee)}const de=Z.filter(Ee=>Ee.name.toLowerCase().endsWith(".bam")&&Ee.size>50*1024*1024),xe=le.filter(Ee=>Ee.size>10*1024*1024);if(de.length||xe.length){const Ee=[...de,...xe].map(mt=>mt.name).join(", "),Le=[...de,...xe].reduce((mt,Co)=>mt+Co.size,0)/(1024*1024);A({error:`${Ee} (${Le.toFixed(0)} MB) — large files load faster via the Path button. Click 📂 Path in the toolbar and paste the file path instead of uploading.`}),setTimeout(()=>A(null),1e4);return}if(oe.length&&!Q.length&&!Z.length&&!le.length){A({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Ee=>Ee.name).join(", ")}`}),setTimeout(()=>A(null),4e3);return}try{if(Q.length>0&&!t){A({msg:`Loading genome: ${Q[0].name}...`});const Le=(await mn.load(Q[0])).data;if(Le.name&&(Le.name=Nt(Le.name)),r(Le),((Fa=Le.chromosomes)==null?void 0:Fa.length)>0){const mt=Le.chromosomes[0];o(mt.name,0,Math.min(mt.length,5e4))}Le.is_annotated&&d({id:"genome_annotations",name:`${Le.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Le.annotated_chromosomes||null})}else Q.length>0&&t&&b({files:Q});if(Z.length>0){if(!t&&Q.length===0){A({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>A(null),4e3);return}A({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Ee=[],Le=[],mt=[];for(const Co of Z)try{const Sn=await u(Co,void 0);_e(Sn)?Le.push(Sn):(c(Sn),Ee.push(Sn))}catch(Sn){mt.push(`${Co.name}: ${((Da=(Ia=Sn.response)==null?void 0:Ia.data)==null?void 0:Da.detail)||Sn.message}`)}if(mt.length){A({error:mt.join("; ")}),setTimeout(()=>A(null),5e3);return}Le.length>0&&Y({tracks:Le})}oe.length?(A({error:`Skipped unsupported: ${oe.map(Ee=>Ee.name).join(", ")}`}),setTimeout(()=>A(null),4e3)):(A({msg:"Files loaded"}),setTimeout(()=>A(null),2e3))}catch(Ee){A({error:Ee.message||"Drop failed"}),setTimeout(()=>A(null),5e3)}},[t,r,o,s,d]),Ne=C.useCallback(async()=>{var q,Q;if(!R)return;const z=R.files;b(null);try{const Z=[];for(const le of z){A({msg:`Adding chromosomes from ${le.name}...`});try{const de=(await mn.addChromosomes(le)).data;de.name&&(de.name=Nt(de.name)),r(de),de.is_annotated&&d({id:"genome_annotations",name:`${de.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:de.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((Q=(q=oe.response)==null?void 0:q.data)==null?void 0:Q.detail)||oe.message}`)}}Z.length?(A({error:Z.join("; ")}),setTimeout(()=>A(null),5e3)):(A({msg:`Added chromosomes from ${z.length} file${z.length>1?"s":""}`}),setTimeout(()=>A(null),3e3))}catch(Z){A({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>A(null),5e3)}},[R,r,d]),Je=C.useCallback(async()=>{var q,Q;if(!R)return;const z=R.files;b(null);try{A({msg:`Loading ${z.length} track${z.length>1?"s":""}...`});const Z=[];for(const le of z)try{await s(le,void 0)}catch(oe){Z.push(`${le.name}: ${((Q=(q=oe.response)==null?void 0:q.data)==null?void 0:Q.detail)||oe.message}`)}Z.length?(A({error:Z.join("; ")}),setTimeout(()=>A(null),5e3)):(A({msg:`Added ${z.length} track${z.length>1?"s":""}`}),setTimeout(()=>A(null),3e3))}catch(Z){A({error:Z.message||"Failed to load tracks"}),setTimeout(()=>A(null),5e3)}},[R,s]),he=C.useCallback(async()=>{if(D){for(const z of D.tracks)await h(z.id);Y(null)}},[D,h]),ht=C.useCallback(()=>{if(D){for(const z of D.tracks)c(z);Y(null),A({msg:`Added ${D.tracks.length} track${D.tracks.length>1?"s":""}`}),setTimeout(()=>A(null),3e3)}},[D,c]),V=C.useCallback(z=>{z.preventDefault();const q=z.clientX,Q=H;function Z(oe){j(Math.max(60,Math.min(400,Q+(oe.clientX-q))))}function le(){window.removeEventListener("mousemove",Z),window.removeEventListener("mouseup",le),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ew-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Z),window.addEventListener("mouseup",le)},[H]);C.useEffect(()=>{if(!T.current)return;const z=new ResizeObserver(q=>{for(const Q of q)y(Q.contentRect.width)});return z.observe(T.current),()=>z.disconnect()},[]);const J=C.useCallback(z=>z.visible?!z.targetChromosomes||!(n!=null&&n.chrom)?!0:z.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),ee={app:{display:"flex",flexDirection:"column",height:"100vh",background:e.appBg,color:e.textPrimary},header:{background:e.headerBg,borderBottom:`2px solid ${e.borderAccent}`,padding:"8px 16px",display:"flex",alignItems:"center",justifyContent:"space-between"},headerLeft:{display:"flex",alignItems:"center",gap:12},title:{fontSize:18,fontWeight:700,color:e.textPrimary,letterSpacing:1},subtitle:{fontSize:11,color:e.textTertiary},headerBtns:{display:"flex",gap:8},btn:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 14px",cursor:"pointer",fontSize:12,fontWeight:600,display:"flex",alignItems:"center",gap:6},trackArea:{flex:1,overflowY:"auto",overflowX:"hidden",display:"flex",flexDirection:"column"},emptyState:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",flex:1,color:e.textMuted,gap:12},emptyTitle:{fontSize:22,fontWeight:300},emptyHint:{fontSize:13}};return a.jsxs("div",{style:ee.app,onDragEnter:ie,onDragLeave:te,onDragOver:ge,onDrop:ye,children:[a.jsxs("div",{style:ee.header,children:[a.jsxs("div",{style:ee.headerLeft,children:[a.jsx(Mc,{size:34}),a.jsxs("div",{children:[a.jsx("div",{style:ee.title,children:"BiNgo Genome Viewer"}),t&&a.jsxs("div",{style:ee.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),a.jsx("button",{onClick:()=>N(!0),title:"About",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:"50%",width:20,height:20,display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",color:e.textSecondary,fontSize:12,fontWeight:700,lineHeight:1,padding:0,flexShrink:0},onMouseEnter:z=>{z.currentTarget.style.color=e.textPrimary,z.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:z=>{z.currentTarget.style.color=e.textSecondary,z.currentTarget.style.borderColor=e.border},children:"?"}),a.jsxs("button",{onClick:()=>_(!0),title:"Guided Tour",style:{background:"none",border:`1px solid ${e.border}`,borderRadius:10,padding:"2px 8px",display:"flex",alignItems:"center",gap:4,cursor:"pointer",color:e.textSecondary,fontSize:11,fontWeight:600,lineHeight:1,flexShrink:0},onMouseEnter:z=>{z.currentTarget.style.color=e.textPrimary,z.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:z=>{z.currentTarget.style.color=e.textSecondary,z.currentTarget.style.borderColor=e.border},children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[a.jsx("path",{d:"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"}),a.jsx("path",{d:"M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zM8 13.5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"})]}),"Help"]})]}),a.jsxs("div",{style:ee.headerBtns,"data-tour":"header-btns",children:[a.jsxs("button",{style:ee.btn,onClick:()=>k(!0),title:"Save or restore a session",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.3",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:[a.jsx("path",{d:"M2 2h8v8H2z"}),a.jsx("path",{d:"M4 2v4h4V2"}),a.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),a.jsxs("button",{style:ee.btn,onClick:()=>m(!0),title:"Customize color theme",children:[a.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[a.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),a.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),a.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),a.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),a.jsxs("button",{"data-tour":"btn-export",style:{...ee.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&S(!0)},title:"Export current view as SVG or PNG",children:[a.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",style:{flexShrink:0},children:a.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),a.jsxs("button",{"data-tour":"btn-settings",style:{...ee.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&p(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),a.jsx(O0,{}),a.jsx(yy,{}),a.jsxs("div",{style:ee.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&a.jsx(Gy,{theme:e,labelWidth:H}),t?n?a.jsxs(a.Fragment,{children:[a.jsxs("div",{style:{display:"flex"},children:[a.jsx("div",{style:{width:H,minWidth:H,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:a.jsx("div",{onMouseDown:V,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:z=>z.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:z=>z.currentTarget.style.background="transparent"})}),a.jsx(xy,{width:v-H})]}),l.filter(J).map(z=>a.jsx(Fy,{track:z,containerWidth:v,labelWidth:H,onLabelResizeStart:V,isDragging:U===z.id,isDropTarget:G===z.id,onDragStart:()=>O(z.id),onDragOver:()=>F(z.id),onDrop:()=>{U&&U!==z.id&&i(U,z.id),O(null),F(null)},onDragEnd:()=>{O(null),F(null)}},z.id)),l.length===0&&a.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):a.jsx("div",{style:ee.emptyState,children:a.jsx("div",{style:ee.emptyHint,children:"Select a chromosome to begin"})}):a.jsxs("div",{style:ee.emptyState,children:[a.jsx("div",{style:ee.emptyTitle,children:"No genome loaded"}),a.jsx("div",{style:ee.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),x&&a.jsx(D0,{onClose:()=>p(!1)}),f&&a.jsx(H0,{onClose:()=>m(!1)}),w&&a.jsx(Z0,{onClose:()=>S(!1)}),E&&a.jsx(py,{onClose:()=>k(!1),labelWidth:H,setLabelWidth:j}),$&&a.jsx(gy,{onClose:()=>{_(!1),p(!1),m(!1)},theme:e,onAction:z=>{z==="open-settings"?(p(!0),m(!1)):z==="open-theme"?(m(!0),p(!1)):(p(!1),m(!1))}}),P&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>N(!1),children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.border}`,borderRadius:8,padding:"28px 36px",maxWidth:520,maxHeight:"85vh",overflowY:"auto",color:e.textPrimary,lineHeight:1.7},onClick:z=>z.stopPropagation(),children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[a.jsx(Mc,{size:44}),a.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",Lc]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),a.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[a.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,background:e.canvasBg,border:`1px solid ${e.border}`,borderRadius:4,padding:"10px 14px",fontFamily:"monospace",lineHeight:1.6,marginBottom:20,userSelect:"all"},children:["Ngo, B.M. (2026). BiNgo Genome Viewer (v",Lc,") [Software]."]}),a.jsxs("details",{style:{marginBottom:20},children:[a.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),a.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),a.jsxs("div",{children:[a.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",a.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),a.jsxs("div",{children:[a.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",a.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",a.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",a.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),a.jsxs("div",{children:[a.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",a.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),a.jsxs("div",{children:[a.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",a.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),a.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),a.jsx("div",{children:"Early version testing and feedback:"}),a.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),a.jsx("div",{style:{textAlign:"right"},children:a.jsx("button",{onClick:()=>N(!1),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 18px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Close"})})]})}),R&&(()=>{const z=R.files.length>1,q=R.files.map(Q=>Q.name).join(", ");return a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:440,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:Q=>Q.stopPropagation(),children:[a.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",z?"s":""," detected"]}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[a.jsx("strong",{style:{color:e.textPrimary},children:q}),z?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",a.jsx("br",{}),"How would you like to handle ",z?"them":"it","?"]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:()=>b(null),style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsxs("button",{onClick:Je,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Track",z?"s":""]}),a.jsxs("button",{onClick:Ne,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",z?"s":""]})]})]})})})(),D&&a.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:a.jsxs("div",{style:{background:e.panelBg,border:`1px solid ${e.borderAccent}`,borderRadius:8,padding:"20px 24px",maxWidth:480,width:"90%",boxShadow:"0 8px 32px rgba(0,0,0,0.5)"},onClick:z=>z.stopPropagation(),children:[a.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),a.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[D.tracks.map(z=>{var q;return a.jsxs("div",{style:{marginBottom:6},children:[a.jsx("strong",{style:{color:e.textPrimary},children:z.name})," — ",((q=z.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},z.id)}),a.jsx("div",{style:{marginTop:8},children:D.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),a.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[a.jsx("button",{onClick:he,style:{background:e.btnBg,border:`1px solid ${e.borderStrong}`,borderRadius:4,color:e.btnText,padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Skip"}),a.jsx("button",{onClick:ht,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),B&&a.jsx("div",{style:{position:"fixed",inset:0,zIndex:9998,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",pointerEvents:"none"},children:a.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[a.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),a.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),I&&a.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:I.error?"#c62828":e.panelBg,border:`1px solid ${I.error?"#e53935":e.borderAccent}`,color:I.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:I.error||I.msg}),t&&a.jsx(Hy,{labelWidth:H})]})}function Qy(){return a.jsx(A0,{children:a.jsx(qm,{children:a.jsx(L0,{children:a.jsx(Yy,{})})})})}Ni.createRoot(document.getElementById("root")).render(a.jsx(Is.StrictMode,{children:a.jsx(Qy,{})}));
@@ -10,7 +10,7 @@
10
10
  body { font-family: Arial, Helvetica, sans-serif; background: #1a1a1a; color: #e0e0e0; height: 100vh; overflow: hidden; }
11
11
  #root { height: 100vh; display: flex; flex-direction: column; }
12
12
  </style>
13
- <script type="module" crossorigin src="/assets/index-DfWUZpOb.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-CpGWw-Cu.js"></script>
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
@@ -24,7 +24,7 @@ from api.genome import router as genome_router
24
24
  from api.tracks import router as tracks_router
25
25
  from api.data import router as data_router
26
26
 
27
- app = FastAPI(title="BiNgo Genome Viewer API", version="2.2.1")
27
+ app = FastAPI(title="BiNgo Genome Viewer API", version="2.2.3")
28
28
 
29
29
  app.add_middleware(
30
30
  CORSMiddleware,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "BiNgoViewer"
7
- version = "2.2.1"
7
+ version = "2.2.3"
8
8
  description = "BiNgo Genome Viewer — a lightweight browser-based genomics viewer"
9
9
  readme = "README.md"
10
10
  license = {text = "Proprietary"}
File without changes
File without changes