BiNgoViewer 2.3.4__tar.gz → 2.4.0__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.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/PKG-INFO +4 -2
  2. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/SOURCES.txt +1 -1
  3. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/PKG-INFO +4 -2
  4. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/README.md +1 -0
  5. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/__init__.py +1 -1
  6. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/cli.py +18 -4
  7. bingoviewer-2.3.4/bingoviewer/frontend_dist/assets/index-Dbtbm6Rs.js → bingoviewer-2.4.0/bingoviewer/frontend_dist/assets/index-v6csp4Bc.js +1 -1
  8. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/frontend_dist/index.html +1 -1
  9. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/genome.py +4 -1
  10. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/tracks.py +6 -2
  11. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/main.py +1 -1
  12. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/bam_reader.py +43 -27
  13. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/pyproject.toml +3 -2
  14. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/dependency_links.txt +0 -0
  15. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/entry_points.txt +0 -0
  16. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/requires.txt +0 -0
  17. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/BiNgoViewer.egg-info/top_level.txt +0 -0
  18. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/__main__.py +0 -0
  19. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/icon.py +0 -0
  20. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/install_shortcut.py +0 -0
  21. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/__init__.py +0 -0
  22. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/__init__.py +0 -0
  23. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/api/data.py +0 -0
  24. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/__init__.py +0 -0
  25. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/annotation_reader.py +0 -0
  26. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/bigwig_reader.py +0 -0
  27. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/genbank_reader.py +0 -0
  28. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/genome_reader.py +0 -0
  29. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/readers/vcf_reader.py +0 -0
  30. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/bingoviewer/server/state.py +0 -0
  31. {bingoviewer-2.3.4 → bingoviewer-2.4.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BiNgoViewer
3
- Version: 2.3.4
3
+ Version: 2.4.0
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
@@ -11,13 +11,14 @@ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
13
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
14
15
  Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Programming Language :: Python :: 3.11
16
17
  Classifier: Programming Language :: Python :: 3.12
17
18
  Classifier: Programming Language :: Python :: 3.13
18
19
  Classifier: Programming Language :: Python :: 3.14
19
20
  Classifier: Operating System :: OS Independent
20
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.9
21
22
  Description-Content-Type: text/markdown
22
23
  Requires-Dist: fastapi<1.0,>=0.111.0
23
24
  Requires-Dist: uvicorn<1.0,>=0.29.0
@@ -101,6 +102,7 @@ Then open [http://localhost:8000](http://localhost:8000).
101
102
  | Problem | Solution |
102
103
  |---------|----------|
103
104
  | `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
105
+ | "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
104
106
  | pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
105
107
  | Port 8000 in use | Run `bingo --port 9000` (or any free port) |
106
108
  | Browser doesn't open | Visit `http://localhost:8000` manually |
@@ -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-Dbtbm6Rs.js
15
+ bingoviewer/frontend_dist/assets/index-v6csp4Bc.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.3.4
3
+ Version: 2.4.0
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
@@ -11,13 +11,14 @@ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
13
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
14
15
  Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Programming Language :: Python :: 3.11
16
17
  Classifier: Programming Language :: Python :: 3.12
17
18
  Classifier: Programming Language :: Python :: 3.13
18
19
  Classifier: Programming Language :: Python :: 3.14
19
20
  Classifier: Operating System :: OS Independent
20
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.9
21
22
  Description-Content-Type: text/markdown
22
23
  Requires-Dist: fastapi<1.0,>=0.111.0
23
24
  Requires-Dist: uvicorn<1.0,>=0.29.0
@@ -101,6 +102,7 @@ Then open [http://localhost:8000](http://localhost:8000).
101
102
  | Problem | Solution |
102
103
  |---------|----------|
103
104
  | `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
105
+ | "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
104
106
  | pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
105
107
  | Port 8000 in use | Run `bingo --port 9000` (or any free port) |
106
108
  | Browser doesn't open | Visit `http://localhost:8000` manually |
@@ -73,6 +73,7 @@ Then open [http://localhost:8000](http://localhost:8000).
73
73
  | Problem | Solution |
74
74
  |---------|----------|
75
75
  | `python` not found | Install Python 3.10+ and check **Add to PATH** during setup |
76
+ | "No matching distribution" | Your Python is too old — BiNgo requires **Python 3.10+**. Check with `python --version` |
76
77
  | pip install fails | Try `pip install --user BiNgoViewer` or use a virtual environment |
77
78
  | Port 8000 in use | Run `bingo --port 9000` (or any free port) |
78
79
  | Browser doesn't open | Visit `http://localhost:8000` manually |
@@ -1,3 +1,3 @@
1
1
  """BiNgo Genome Viewer — a lightweight browser-based genomics viewer."""
2
2
 
3
- __version__ = "2.3.4"
3
+ __version__ = "2.4.0"
@@ -376,8 +376,16 @@ def _offer_shortcut_install():
376
376
  try:
377
377
  answer = input(" Create a desktop shortcut? [Y/n]: ").strip()
378
378
  if answer.lower() != 'n':
379
- from bingoviewer.install_shortcut import main as install_main
380
- install_main()
379
+ try:
380
+ from bingoviewer.install_shortcut import main as install_main
381
+ install_main()
382
+ except ImportError:
383
+ print(" Shortcut creation requires tkinter.")
384
+ print(" Install it with: conda install tk (or) sudo apt install python3-tk")
385
+ print(" You can create a shortcut later with: bingo --install")
386
+ except Exception as e:
387
+ print(f" Shortcut creation failed: {e}")
388
+ print(" You can try again later with: bingo --install")
381
389
  return
382
390
  except (EOFError, OSError):
383
391
  pass
@@ -437,8 +445,14 @@ def main():
437
445
  return 0
438
446
 
439
447
  if args.install:
440
- from bingoviewer.install_shortcut import main as install_main
441
- install_main()
448
+ try:
449
+ from bingoviewer.install_shortcut import main as install_main
450
+ install_main()
451
+ except ImportError:
452
+ print(" Shortcut creation requires tkinter.")
453
+ print(" Install it with: conda install tk (or) sudo apt install python3-tk")
454
+ except Exception as e:
455
+ print(f" Shortcut creation failed: {e}")
442
456
  return 0
443
457
 
444
458
  # ── Manual update command ────────────────────────────────────
@@ -94,4 +94,4 @@ ${z.join(`
94
94
  `)}
95
95
 
96
96
  Tip: If files were moved, re-add them using the 📂 Path button.`):(x("Session restored"),setTimeout(()=>{x(null),e()},1200))}catch(Y){f(Y.message)}finally{m(!1)}}const A=jc(),R=ky(c);return s.jsx("div",{style:R.overlay,onClick:U=>{U.target===U.currentTarget&&e()},children:s.jsxs("div",{style:R.panel,children:[s.jsxs("div",{style:R.header,children:[s.jsx("span",{style:R.title,children:"Session"}),s.jsx("button",{style:R.closeBtn,onClick:e,children:"✕"})]}),s.jsxs("div",{style:R.body,children:[s.jsxs("div",{style:R.section,children:[s.jsx("div",{style:R.sectionTitle,children:"Save"}),s.jsx("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:s.jsx("button",{style:R.btn,onClick:b,disabled:!r||p,children:"Save to file"})}),s.jsx("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:"Session is also auto-saved to browser storage."})]}),s.jsxs("div",{style:R.section,children:[s.jsx("div",{style:R.sectionTitle,children:"Restore"}),s.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap"},children:[s.jsx("button",{style:R.btn,onClick:j,disabled:p,children:"Load from file"}),A&&s.jsx("button",{style:R.btn,onClick:E,disabled:p,children:"Restore last session"})]}),s.jsx("input",{ref:w,type:"file",accept:".json",style:{display:"none"},onChange:S}),A&&s.jsxs("div",{style:{fontSize:10,color:c.textTertiary,marginTop:4},children:["Last auto-save: ",new Date(A.savedAt).toLocaleString(),A.genome&&` — ${A.genome.name}`,A.tracks&&` — ${A.tracks.length} tracks`]})]}),v&&s.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#81c784"},children:v}),y&&s.jsx("div",{style:{padding:"4px 16px",fontSize:11,color:"#ef9a9a",whiteSpace:"pre-wrap"},children:y})]}),s.jsx("div",{style:R.footer,children:s.jsx("button",{style:R.btn,onClick:e,children:"Close"})})]})})}function ky(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 ye=e=>s.jsx("strong",{children:e}),ue=({children:e})=>s.jsxs("div",{style:{display:"flex",gap:6,marginTop:4},children:[s.jsx("span",{style:{opacity:.5},children:"•"}),s.jsx("span",{children:e})]}),Rc=({children:e})=>s.jsx("span",{style:{background:"rgba(255,255,255,0.1)",borderRadius:3,padding:"0 4px",fontSize:11,fontFamily:"monospace"},children:e}),Cn=[{target:"file-loader",title:"Load Files",description:s.jsxs(s.Fragment,{children:["Upload genome and track files via:",s.jsxs(ue,{children:[ye("File picker"),' — click "Choose Files"']}),s.jsxs(ue,{children:[ye("Drag & drop")," — drop files anywhere on the app"]}),s.jsxs(ue,{children:[ye("Local path")," — paste a file path (best for large files)"]}),s.jsx("div",{style:{marginTop:8,opacity:.7},children:"Supported: FASTA, GenBank, BAM, BigWig, WIG, BedGraph, VCF, BED, GTF, GFF"})]}),position:"bottom"},{target:"nav-bar",title:"Navigation",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Chromosome selector")," — switch between chromosomes"]}),s.jsxs(ue,{children:[ye("Coordinate input")," — type ",s.jsx(Rc,{children:"chr1:1000-5000"})," and press Go"]}),s.jsxs(ue,{children:[ye("- +")," — zoom out / zoom in"]}),s.jsxs(ue,{children:[ye("◀ ▶")," — pan left / pan right"]}),s.jsxs(ue,{children:[ye("Blue scrubber bar")," — click or drag to jump across the chromosome"]})]}),position:"bottom"},{target:"track-area",title:"Track Interaction",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Left-click drag")," — pan the viewport"]}),s.jsxs(ue,{children:[ye("Scroll wheel")," — zoom in/out at cursor position"]}),s.jsxs(ue,{children:[ye("Right-click drag")," — select a region (hover for stats)"]}),s.jsxs(ue,{children:[ye("Double-click gene")," — zoom to fit that gene with context"]}),s.jsxs(ue,{children:[ye("Hover features")," — view detailed tooltips"]})]}),position:"inside"},{target:"skeleton-track-label",title:"Track Labels",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("≡ Drag handle")," — reorder tracks by dragging"]}),s.jsxs(ue,{children:[ye("Color swatch")," — click to pick a color"]}),s.jsxs(ue,{children:[ye("× Button")," — remove the track"]}),s.jsxs(ue,{children:[ye("Bottom edge")," — drag to resize track height"]})]}),position:"right"},{target:"btn-settings",title:"Track Settings",description:s.jsxs(s.Fragment,{children:["Select one or more tracks to adjust:",s.jsx(ue,{children:"Height, visibility, and fill color"}),s.jsx(ue,{children:"Bar width, peak outline trace + smoothness"}),s.jsxs(ue,{children:["Y-axis scale (auto / manual / log","₂",")"]}),s.jsx(ue,{children:"Annotation colors per feature type"}),s.jsx(ue,{children:"Read appearance — strand colors, arrow style & size"}),s.jsx(ue,{children:"Nucleotide display with mismatch highlighting"}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"The panel is draggable — adjust settings while viewing your data."})]}),position:"bottom",action:"open-settings"},{target:"header-btns",title:"Themes",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("5 built-in themes")," — Dark, Light, Colorblind, Soft, High Contrast"]}),s.jsxs(ue,{children:[ye("Custom themes")," — clone any preset and edit every color"]}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"Theme preferences persist across sessions."})]}),position:"bottom",action:"open-theme"},{target:"btn-export",title:"Export Image",description:s.jsxs(s.Fragment,{children:["Export the current view as ",ye("SVG")," or ",ye("PNG"),".",s.jsx(ue,{children:"Background, bars, outlines, and labels are separate SVG groups"}),s.jsx(ue,{children:"All track settings (colors, outlines, visibility) are respected"}),s.jsx(ue,{children:"Edit exported SVGs in Illustrator, Inkscape, or Figma"})]}),position:"bottom"},{target:"header-btns",title:"Sessions",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Save to file")," — exports genome, tracks, region, zoom, colors, and all settings as JSON"]}),s.jsxs(ue,{children:[ye("Restore")," — reload a saved session or the last auto-save"]}),s.jsxs(ue,{children:[ye("Auto-save")," — your session saves to the browser automatically"]}),s.jsx("div",{style:{marginTop:6,opacity:.7},children:"An exit guard warns you before closing with unsaved work."})]}),position:"bottom"},{target:"file-loader",title:"Tips",description:s.jsxs(s.Fragment,{children:[s.jsxs(ue,{children:[ye("Large BAM files")," — use the ",s.jsxs(Rc,{children:["📂"," Path"]})," button to load by file path (no upload needed)"]}),s.jsxs(ue,{children:[ye("Large WIG files")," — convert to BigWig for instant loading"]}),s.jsxs(ue,{children:[ye("BAM + BAI")," — select both together, or load by path (index auto-discovered)"]}),s.jsxs(ue,{children:[ye("Updates")," — the app checks for updates automatically on launch"]})]}),position:"bottom"}],Tn=8,jn=14,Et=340,Cy=230,zr="rgba(0,0,0,0.55)";function Ty({onClose:e,theme:t,onAction:n}){const[r,o]=C.useState(0),[l,i]=C.useState(null),[a,u]=C.useState(Cy),c=C.useRef(null),h=Cn[r],d=r===0,g=r===Cn.length-1;C.useEffect(()=>{var S;const j=(S=Cn[r])==null?void 0:S.action;j&&n&&n(j)},[r,n]);const T=C.useCallback(j=>{var E;((E=Cn[j])==null?void 0:E.action)&&n&&n(null)},[n]),v=C.useCallback(()=>{T(r),r<Cn.length-1?o(j=>j+1):e()},[r,e,T]),x=C.useCallback(()=>{T(r),r>0&&o(j=>j-1)},[r,T]);C.useEffect(()=>{function j(S){S.key==="Escape"?e():S.key==="ArrowRight"||S.key==="Enter"?v():S.key==="ArrowLeft"&&x()}return window.addEventListener("keydown",j),()=>window.removeEventListener("keydown",j)},[e,v,x]),C.useEffect(()=>{function j(){const S=document.querySelector(`[data-tour="${h.target}"]`);if(S){const E=S.getBoundingClientRect();i({top:E.top,left:E.left,width:E.width,height:E.height})}else i(null)}return j(),window.addEventListener("resize",j),window.addEventListener("scroll",j,!0),()=>{window.removeEventListener("resize",j),window.removeEventListener("scroll",j,!0)}},[h.target]),C.useEffect(()=>{c.current&&u(c.current.getBoundingClientRect().height)});const y=l?{top:l.top-Tn,left:l.left-Tn,width:l.width+Tn*2,height:l.height+Tn*2}:null;let f,p,m=null,w=Et/2;if(!l)f=(window.innerHeight-a)/2,p=(window.innerWidth-Et)/2;else{const j=h.position||"bottom",S=l.top+l.height+Tn,E=l.top-Tn,$=l.left+l.width+Tn,A=l.left+l.width/2;j==="inside"?(f=l.top+Math.max(20,(l.height-a)/2),p=l.left+Math.max(16,(l.width-Et)/2)):j==="right"?(f=l.top+l.height/2-a/2,p=$+jn,m="left",w=a/2,p+Et>window.innerWidth-12&&(f=S+jn,p=A-Et/2,m="up",w=Math.max(20,Math.min(Et-20,A-p)))):(S+jn+a<=window.innerHeight?(f=S+jn,m="up"):E-jn-a>=0?(f=E-jn-a,m="down"):(f=S+jn,m="up"),l.width<200?(p=Math.max(12,l.left+l.width-Et),p<12&&(p=12)):p=A-Et/2,w=Math.max(20,Math.min(Et-20,A-p))),p=Math.max(12,Math.min(window.innerWidth-Et-12,p)),f=Math.max(12,Math.min(window.innerHeight-a-12,f))}const b={card:{position:"fixed",top:f,left:p,width:Et,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:j=>({width:7,height:7,borderRadius:"50%",background:j?"#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 s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{position:"fixed",inset:0,zIndex:1e4},onClick:e}),y?s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{position:"fixed",top:0,left:0,right:0,height:Math.max(0,y.top),background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top+y.height,left:0,right:0,bottom:0,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:0,width:Math.max(0,y.left),height:y.height,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:y.left+y.width,right:0,height:y.height,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsx("div",{style:{position:"fixed",top:y.top,left:y.left,width:y.width,height:y.height,borderRadius:6,border:"2px solid rgba(255,255,255,0.22)",zIndex:10001,pointerEvents:"none",boxSizing:"border-box"}})]}):s.jsx("div",{style:{position:"fixed",inset:0,background:zr,zIndex:10001,pointerEvents:"none"}}),s.jsxs("div",{ref:c,style:b.card,onClick:j=>j.stopPropagation(),children:[m==="up"&&s.jsx("div",{style:b.arrowUp}),m==="down"&&s.jsx("div",{style:b.arrowDown}),m==="left"&&s.jsx("div",{style:b.arrowLeft}),s.jsxs("div",{style:b.stepCounter,children:["Step ",r+1," of ",Cn.length]}),s.jsx("div",{style:b.title,children:h.title}),s.jsx("div",{style:b.description,children:h.description}),s.jsx("div",{style:b.dots,children:Cn.map((j,S)=>s.jsx("div",{style:b.dot(S===r),onClick:()=>o(S)},S))}),s.jsxs("div",{style:b.nav,children:[s.jsx("button",{style:b.skip,onClick:e,children:"Skip Tour"}),s.jsxs("div",{style:{display:"flex",gap:8},children:[s.jsx("button",{style:d?b.btnDisabled:b.btnSecondary,onClick:x,disabled:d,children:"Previous"}),s.jsx("button",{style:b.btnPrimary,onClick:v,children:g?"Finish":"Next"})]})]})]})]})}function jy(){const{theme:e}=Xe(),{genome:t,region:n,navigateTo:r,zoom:o,pan:l}=at(),[i,a]=C.useState(""),u=C.useRef(null),c=C.useRef(!1),h=C.useMemo(()=>{if(!t)return{toShort:{},toLong:{}};const w={},b={};return t.chromosomes.forEach((j,S)=>{const E=`chr${S+1}`;w[j.name]=E,b[E.toLowerCase()]=j.name,b[j.name.toLowerCase()]=j.name}),{toShort:w,toLong:b}},[t]);C.useEffect(()=>{if(n){const w=h.toShort[n.chrom]||n.chrom;a(`${w}:${n.start.toLocaleString()}-${n.end.toLocaleString()}`)}},[n,h]);const d=C.useMemo(()=>{if(!t||!n)return 0;const w=t.chromosomes.find(b=>b.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 b=u.current.getBoundingClientRect(),j=Math.max(0,Math.min(1,(w-b.left)/b.width)),S=n.end-n.start,E=j*d;r(n.chrom,E-S/2,E+S/2)},[n,d,r]),T=C.useCallback(w=>{w.preventDefault(),c.current=!0,g(w.clientX);function b(S){c.current&&g(S.clientX)}function j(){c.current=!1,window.removeEventListener("mousemove",b),window.removeEventListener("mouseup",j),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="grabbing",document.body.style.userSelect="none",window.addEventListener("mousemove",b),window.addEventListener("mouseup",j)},[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 x(w){if(!t)return;const b=t.chromosomes.find(j=>j.name===w.target.value);b&&r(b.name,0,Math.min(b.length,5e4))}function y(w){w.preventDefault();const j=i.replace(/,/g,"").trim().match(/^(\S+):(\d+)-(\d+)$/);if(j){const S=h.toLong[j[1].toLowerCase()]||j[1];r(S,parseInt(j[2]),parseInt(j[3]))}}if(!t)return s.jsx("div",{style:{...v.bar,opacity:.4},"data-tour":"nav-bar",children:s.jsx("span",{style:{fontSize:12,color:e.textMuted,fontStyle:"italic"},children:"Load a genome to enable navigation"})});const f=n?n.end-n.start:0;let p=0,m=100;return n&&d>0&&(p=n.start/d*100,m=Math.max(1,f/d*100)),s.jsxs("div",{style:v.bar,"data-tour":"nav-bar",children:[s.jsx("select",{style:v.select,value:(n==null?void 0:n.chrom)||"",onChange:x,children:t.chromosomes.map((w,b)=>s.jsxs("option",{value:w.name,children:["chr",b+1," ","—"," ",w.name," (",(w.length/1e3).toFixed(0)," kbp)"]},w.name))}),s.jsxs("form",{onSubmit:y,style:{display:"flex",gap:4},children:[s.jsx("input",{style:v.coordInput,value:i,onChange:w=>a(w.target.value),placeholder:"chr1:start-end"}),s.jsx("button",{style:v.btn,type:"submit",children:"Go"})]}),s.jsx("button",{style:v.btn,onClick:()=>o(2),title:"Zoom out",children:"-"}),s.jsx("button",{style:v.btn,onClick:()=>o(.5),title:"Zoom in",children:"+"}),s.jsx("button",{style:v.btn,onClick:()=>l(-f*.5),title:"Pan left",children:"◀"}),s.jsx("button",{style:v.btn,onClick:()=>l(f*.5),title:"Pan right",children:"▶"}),n&&d>0&&s.jsx("div",{ref:u,style:v.scrubberWrap,onMouseDown:T,title:"Drag to scroll across the chromosome",children:s.jsx("div",{style:{position:"absolute",left:`${p}%`,width:`${m}%`,top:1,bottom:1,background:"#42a5f5",borderRadius:6,minWidth:8,opacity:.7,transition:c.current?"none":"left 0.1s ease"}})}),n&&s.jsxs("span",{style:v.info,children:[f.toLocaleString()," bp"]})]})}function Pp(e){const{region:t,zoom:n,navigateTo:r,setSelection:o,clearSelection:l}=at(),i=C.useRef(null),a=C.useRef(null),u=C.useRef(t);u.current=t,C.useEffect(()=>{const c=e.current;if(!c)return;function h(x){const y=u.current;if(y){if(x.button===2){x.preventDefault();const f=c.getBoundingClientRect(),p=(x.clientX-f.left)/f.width,m=y.start+p*(y.end-y.start);a.current={startX:x.clientX,startBp:m,region:{...y},containerWidth:f.width};return}x.button===0&&(l(),i.current={x:x.clientX,startRegion:{...y},containerWidth:c.offsetWidth||c.clientWidth||1})}}function d(x){if(a.current){const j=a.current,S=c.getBoundingClientRect(),E=Math.max(0,Math.min(1,(x.clientX-S.left)/S.width)),$=j.region.start+E*(j.region.end-j.region.start),A=Math.min(j.startBp,$),R=Math.max(j.startBp,$);Math.abs(R-A)>=1&&o({chrom:j.region.chrom,start:Math.floor(A),end:Math.ceil(R)});return}if(!i.current)return;const y=x.clientX-i.current.x,{chrom:f,start:p,end:m}=i.current.startRegion,w=(m-p)/i.current.containerWidth,b=-y*w;r(f,p+b,m+b)}function g(x){if(a.current){a.current=null;return}i.current=null}function T(x){x.preventDefault()}function v(x){x.preventDefault();const y=c.getBoundingClientRect(),f=(x.clientX-y.left)/y.width,p=x.deltaY>0?1.4:.7;n(p,f)}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 En=30;function Ey({width:e}){const t=C.useRef(null),n=C.useRef(null),{region:r,selection:o}=at(),{theme:l}=Xe();return Pp(t),C.useEffect(()=>{const i=n.current;if(!i||!r)return;const a=window.devicePixelRatio||1;i.width=e*a,i.height=En*a;const u=i.getContext("2d");u.scale(a,a);const{start:c,end:h}=r,d=h-c;if(u.clearRect(0,0,e,En),u.fillStyle=l.canvasBg,u.fillRect(0,0,e,En),o&&o.chrom===r.chrom){const p=(o.start-c)/d,m=(o.end-c)/d,w=Math.max(0,p*e),b=Math.min(e,m*e);b-w>=1&&(u.fillStyle="rgba(100, 181, 246, 0.25)",u.fillRect(w,0,b-w,En),u.strokeStyle="rgba(100, 181, 246, 0.6)",u.lineWidth=1,u.beginPath(),u.moveTo(w,0),u.lineTo(w,En),u.moveTo(b,0),u.lineTo(b,En),u.stroke())}const g=Math.min(10,Math.floor(e/80)),T=d/g,v=Math.pow(10,Math.floor(Math.log10(T))),x=[1,2,5,10].map(p=>p*v),y=x.find(p=>p>=T)||x[x.length-1],f=Math.ceil(c/y)*y;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 p=f;p<=h;p+=y){const m=(p-c)/d*e;u.beginPath(),u.moveTo(m,14),u.lineTo(m,20),u.stroke(),u.fillText(Ry(p),m,11)}},[r,o,e,l]),s.jsx("div",{ref:t,style:{position:"relative"},children:s.jsx("canvas",{ref:n,style:{display:"block",width:"100%",height:En}})})}function Ry(e){return e>=1e6?`${(e/1e6).toFixed(2)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function $i(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),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Xn(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Py({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u,error:c}=ei(e,l,t);return C.useEffect(()=>{var Y,I;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&&!((Y=a==null?void 0:a.bins)!=null&&Y.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(!((I=a==null?void 0:a.bins)!=null&&I.length)){r&&r(null);return}const T=a.max_value||0,v=a.min_value||0,x=v<0,y=l.start,f=l.end-l.start,p=e.color||"#78909c",m=e.scaleMax!=null?e.scaleMax:null,w=e.scaleMin!=null?e.scaleMin:null,b=e.logScale===!0,j=e.barAutoWidth!==!1,S=e.barWidth||2,E=e.showOutline===!0,$=e.outlineColor||null,A=e.outlineSmooth||0,R=e.showBars!==!1,U=p,P=_y(p,-40),W=t/f;function O(L){return j?W>=1?Math.max(1,Math.min(W,L)):Math.max(1,L):Math.min(S,L)}if(x){const N=Math.round(n/2),D=N-12/2,z=n-N-12/2,F=m??(T||1),V=w??(Math.abs(v)||1);if(g.strokeStyle=i.centerLine,g.lineWidth=1,g.beginPath(),g.moveTo(0,N),g.lineTo(t,N),g.stroke(),R)for(const k of a.bins){const Q=(k.end-k.start)/f*t,ee=O(Q),ce=(k.start-y)/f*t,he=k.forward!=null?k.forward:Math.max(0,k.value),pe=k.reverse!=null?k.reverse:Math.min(0,k.value);if(he>0){const ae=b?Xn(he,F):he/F;g.fillStyle=U,g.fillRect(ce,N-ae*D,ee,ae*D)}if(pe<0){const ae=b?Xn(Math.abs(pe),V):Math.abs(pe)/V;g.fillStyle=P,g.fillRect(ce,N,ee,ae*z)}}if(E&&a.bins.length>0){const k=$||i.textPrimary||"#fff",Q=$||i.textPrimary||"#fff",ee=a.bins.map(ie=>{const ne=ie.forward!=null?ie.forward:Math.max(0,ie.value);return ne>0?b?Xn(ne,F):ne/F:0}),ce=a.bins.map(ie=>{const ne=ie.reverse!=null?ie.reverse:Math.min(0,ie.value);return ne<0?b?Xn(Math.abs(ne),V):Math.abs(ne)/V:0}),he=$i(ee,A),pe=$i(ce,A),ae=a.bins.map(ie=>((ie.start+ie.end)/2-y)/f*t);Ni(g,ae,he.map(ie=>N-ie*D),k,A>0),Ni(g,ae,pe.map(ie=>N+ie*z),Q,A>0)}const M=b?" log₂":"";$r(g,`+${F.toFixed(1)}${M}`,2,2,i),$r(g,`−${V.toFixed(1)}${M}`,2,n-12,i),$r(g,"0",2,N-6,i,!0)}else{const L=m??(T||1);if(R){g.fillStyle=U;for(const D of a.bins){const z=(D.end-D.start)/f*t,F=O(z),V=(D.start-y)/f*t,k=(b?Xn(D.value,L):D.value/L)*(n-14);g.fillRect(V,n-k-2,F,k)}}if(E&&a.bins.length>0){const D=a.bins.map(M=>b?Xn(M.value,L):M.value/L),z=$i(D,A),F=a.bins.map(M=>((M.start+M.end)/2-y)/f*t),V=z.map(M=>n-M*(n-14)-2);Ni(g,F,V,$||i.textPrimary||"#fff",A>0)}const N=b?" log₂":"";$r(g,`${L.toFixed(1)}${N}`,2,2,i),$r(g,"0",2,n-12,i,!0)}if(r){const L=[];m!=null&&T>m&&L.push(`Bars clipped: max value ${T.toFixed(1)} exceeds scale ${m.toFixed(1)}`),x&&w!=null&&Math.abs(v)>w&&L.push(`Negative bars clipped: min value ${Math.abs(v).toFixed(1)} exceeds scale ${w.toFixed(1)}`),r(L.length>0?L.join(`
97
- `):null)}},[a,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]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ni(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,a=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,a)}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 $r(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),a=2,u=i.width+a*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+a,r+1),e.textBaseline="alphabetic"}function _y(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 Pc=6,Oi=8,Fi=14,Ii=2,Ly="#9c27b0",Vo=10,My={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},By="#ffeb3b";function _c(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ay({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),x=e.showNucleotides!==!1,y=e.useArrows!==!1,f=e.logScale===!0,p=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",b=e.arrowSize||4,j=C.useRef(null);C.useEffect(()=>{if(l&&j.current){const $=j.current;($.chrom!==l.chrom||Math.abs($.start-l.start)>$.end-$.start)&&T(0)}j.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!x){h(null);return}const $=l.end-l.start;if(t/$<Pc||$>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const R=Math.max(0,l.start-500),U=l.end+500,P=`${l.chrom}:${R}-${U}`;d.current!==P&&(d.current=P,yn.sequence(l.chrom,R,U).then(W=>h({chrom:l.chrom,start:R,end:U,sequence:W.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,x]);const S=C.useCallback($=>{var W;if(!((W=a==null?void 0:a.reads)!=null&&W.length)||!$.shiftKey&&Math.abs($.deltaX)>Math.abs($.deltaY))return;const A=x&&c?Fi:Oi,R=Math.max(0,...a.reads.map(O=>O.row)),U=Math.floor(n/(A+Ii)),P=Math.max(0,R-U+2);P<=0||($.preventDefault(),$.stopPropagation(),T(O=>Math.max(0,Math.min(P,O+Math.sign($.deltaY)*3))))},[a,n,x,c]);C.useEffect(()=>{var k;const $=o.current;if(!$)return;const A=window.devicePixelRatio||1;$.width=t*A,$.height=n*A;const R=$.getContext("2d");if(R.scale(A,A),R.clearRect(0,0,t,n),R.fillStyle=i.canvasBg,R.fillRect(0,0,t,n),u&&!a){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!a){r&&r(null);return}const U=l.start,P=l.end-l.start;if(a.bins){const Q=a.max_value||1,ee=e.scaleMax!=null?e.scaleMax:Q,ce=e.color||"#78909c",he=e.barAutoWidth!==!1,pe=e.barWidth||2,ae=t/P;if(e.showBars!==!1){R.fillStyle=ce;for(const ne of a.bins){const xe=(ne.end-ne.start)/P*t,Me=he?ae>=1?Math.max(1,Math.min(ae,xe)):Math.max(1,xe):Math.min(pe,xe),ve=(ne.start-U)/P*t,et=(f?_c(ne.value,ee):Math.min(1,ne.value/ee))*(n-14);R.fillRect(ve,n-et-2,Me,et)}}if(e.showOutline&&a.bins.length>0){const ne=e.outlineSmooth||0,xe=a.bins.map(me=>f?_c(me.value,ee):Math.min(1,me.value/ee)),Me=$y(xe,ne),ve=a.bins.map(me=>((me.start+me.end)/2-U)/P*t),Fe=Me.map(me=>n-me*(n-14)-2),et=e.outlineColor||i.textPrimary||"#fff";if(R.beginPath(),R.moveTo(ve[0],Fe[0]),ne>0){for(let me=0;me<ve.length-1;me++)R.quadraticCurveTo(ve[me],Fe[me],(ve[me]+ve[me+1])/2,(Fe[me]+Fe[me+1])/2);R.lineTo(ve[ve.length-1],Fe[Fe.length-1])}else for(let me=0;me<ve.length;me++)R.lineTo(ve[me],Fe[me]);R.strokeStyle=et,R.lineWidth=1.5,R.stroke()}const ie=f?" log₂":"";Lc(R,`${ee.toFixed(1)}${ie}`,2,2,i),Lc(R,"0",2,n-12,i,!0),R.fillStyle="#ffb74d",R.font="10px Arial, Helvetica, sans-serif",R.textAlign="right",R.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&Q>e.scaleMax?`Bars clipped: max value ${Q.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((k=a.reads)!=null&&k.length)){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("No reads in region",8,n/2+4),r&&r(null);return}const W=Q=>(Q-U)/P*t,O=t/P,Y=x&&O>=Pc&&c!=null,I=Y?Fi:Oi,L=Ii,D=Math.max(0,...a.reads.map(Q=>Q.row))+1,z=Math.floor(n/(I+L)),F=D>z,V=Math.min(g,Math.max(0,D-z+1));let M=0;for(const Q of a.reads){const ee=(Q.row-V)*(I+L)+2;if(ee+I<0||ee>n){M++;continue}const ce=Q.strand==="+"?p:m,he=Q.segments;if(he&&he.length>0){const pe=W(Q.start),ae=W(Q.end);R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(pe,ee+I/2),R.lineTo(ae,ee+I/2),R.stroke();let ie=0;for(const ne of he)if(ne.type==="M"){const xe=W(ne.start),Me=Math.max(1,W(ne.end)-xe);if(R.fillStyle=ce,R.fillRect(xe,ee,Me,I),Y&&Q.sequence){const ve=ne.end-ne.start;for(let Fe=0;Fe<ve;Fe++){const et=ne.start+Fe,me=W(et),gt=W(et+1)-me,G=(Q.sequence[ie+Fe]||"").toUpperCase();let J="";c&&et>=c.start&&et<c.end&&(J=(c.sequence[et-c.start]||"").toUpperCase());const te=J&&G&&G!==J&&G!=="N";te&&(R.fillStyle=By,R.fillRect(me,ee,gt,I)),gt>=6&&(R.fillStyle=te?"#000":My[G]||"#999",R.font=`bold ${Math.min(11,gt-1)}px monospace`,R.textAlign="center",R.textBaseline="middle",R.fillText(G,me+gt/2,ee+I/2))}ie+=ve}}else if(ne.type==="D"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=1&&(R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke())}else if(ne.type==="N"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=2&&(R.setLineDash([2,2]),R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke(),R.setLineDash([]))}else ne.type==="I"?(R.fillStyle=Ly,R.fillRect(W(ne.pos)-1,ee-1,2,I+2),Y&&(ie+=ne.length)):ne.type==="S"&&Y&&(ie+=ne.length)}else{const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe);R.fillStyle=Q.strand==="+"?p:m,R.fillRect(pe,ee,ae,I)}if(y&&w!=="flat"){const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe),ie=Math.min(b,ae/2);ie>=2&&zy(R,w,Q.strand,pe,ee,ae,I,ie,ce,i.canvasBg)}if(!Y&&!x){const pe=W(Q.start);Math.max(2,W(Q.end)-pe)>60&&(R.fillStyle=i.canvasBg,R.font="8px Arial, Helvetica, sans-serif",R.textAlign="left",R.fillText(Q.name.slice(0,20),pe+2,ee+I-1))}}if(F){const Q=t-Vo;R.fillStyle=i.inputBg||"#2a2a2a",R.fillRect(Q,0,Vo,n);const ee=z/D,ce=Math.max(20,ee*n),pe=(D>z?V/(D-z):0)*(n-ce);R.fillStyle="#555",R.fillRect(Q+1,pe,Vo-2,ce)}r&&(M>0&&!F?r(`${M} read${M>1?"s":""} hidden — increase track height to show all`):r(F?`${D} rows · Shift+scroll or drag scrollbar to navigate`:null))},[a,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 E=C.useCallback($=>{var D;if(!((D=a==null?void 0:a.reads)!=null&&D.length))return;const A=o.current;if(!A)return;const R=A.getBoundingClientRect();if(($.clientX-R.left)*(t/R.width)<t-Vo)return;const P=x&&c?Fi:Oi,O=Math.max(0,...a.reads.map(z=>z.row))+1,Y=Math.floor(n/(P+Ii)),I=Math.max(0,O-Y+1);if(I<=0)return;$.preventDefault(),v.current={maxScroll:I,startY:$.clientY,startRow:g};function L(z){if(!v.current)return;const F=z.clientY-v.current.startY,V=Math.round(F/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+V)))}function N(){v.current=null,window.removeEventListener("mousemove",L),window.removeEventListener("mouseup",N)}window.addEventListener("mousemove",L),window.addEventListener("mouseup",N)},[a,t,n,g,x,c]);return s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:S,onMouseDown:E})}function zy(e,t,n,r,o,l,i,a,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-a,o),e.lineTo(r+l-a,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+a,o),e.lineTo(r+a,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-a,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-a,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+a,o),e.lineTo(r,o+i/2),e.lineTo(r+a,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-a*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-a*2,o,a*2,i)}else{const d=e.createLinearGradient(r,0,r+a*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,a*2,i)}}function $y(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),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Lc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,a=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,a,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const Ny=16,Oy=22,Fy=4,_p=8,Mc=6,Bc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Iy({track:e,width:t,height:n,onWarning:r}){var $,A,R,U;const o=C.useRef(null),{region:l,navigateTo:i}=at(),{tracks:a}=Jt(),{theme:u}=Xe(),{data:c,loading:h,error:d}=ei(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[x,y]=C.useState(null),[f,p]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){p(null);return}const P=l.end-l.start;if(t/P<Mc||P>2e3){p(null);return}if(f&&f.chrom===l.chrom&&f.start<=l.start&&f.end>=l.end)return;const O=Math.max(0,l.start-500),Y=l.end+500,I=`${l.chrom}:${O}-${Y}`;m.current!==I&&(m.current=I,yn.sequence(l.chrom,O,Y).then(L=>p({chrom:l.chrom,start:O,end:Y,sequence:L.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 V,M;const P=o.current;if(!P)return;const W=window.devicePixelRatio||1;P.width=t*W,P.height=n*W;const O=P.getContext("2d");if(O.scale(W,W),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((V=c==null?void 0:c.features)!=null&&V.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(!((M=c==null?void 0:c.features)!=null&&M.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 Y=l.end-l.start,I=t/Y,L=T&&I>=Mc&&f!=null,N=L?Oy:Ny,D=[],z=[];let F=0;if(L){const Q=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,Q,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,Q),O.lineTo(t,Q),O.stroke();const ee=Math.min(10,I-1);if(ee>=5){O.font=`bold ${ee}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ce=Math.floor(l.start);ce<Math.ceil(l.end);ce++)if(f&&ce>=f.start&&ce<f.end){const he=(f.sequence[ce-f.start]||"").toUpperCase(),pe=(ce-l.start)/Y*t;O.fillStyle=Bc[he]||"#999",O.fillText(he,pe+I/2,Q+14/2)}}}for(const k of c.features){let Q=D.findIndex(ae=>k.start>=ae);Q===-1&&(Q=D.length),D[Q]=k.end;const ee=(k.start-l.start)/Y*t,ce=Math.max(2,(k.end-k.start)/Y*t),he=Q*(N+Fy)+2;if(he+N>n){F++;continue}const pe=zc(k.feature_type,e,u);if(k.sub_features&&k.sub_features.length>0){O.fillStyle=pe+"66",O.fillRect(ee,he+N/2-1,ce,2);for(const ae of k.sub_features){const ie=(ae.start-l.start)/Y*t,ne=Math.max(1,(ae.end-ae.start)/Y*t),xe=zc(ae.feature_type,e,u),Me=ae.feature_type==="CDS"?N:N-6,ve=ae.feature_type==="CDS"?he:he+3;g?Ac(O,xe,ie,ve,ne,Me,ae.strand||k.strand):(O.fillStyle=xe,O.fillRect(ie,ve,ne,Me))}}else g?Ac(O,pe,ee,he,ce,N,k.strand):(O.fillStyle=pe,O.fillRect(ee,he,ce,N));if(L){const ae=Math.max(k.start,l.start),ie=Math.min(k.end,l.end);for(let ne=ae;ne<ie;ne++)if(f&&ne>=f.start&&ne<f.end){const xe=(f.sequence[ne-f.start]||"").toUpperCase(),Me=(ne-l.start)/Y*t,ve=I;ve>=6&&(O.fillStyle=Bc[xe]||"#999",O.font=`bold ${Math.min(10,ve-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(xe,Me+ve/2,he+N/2))}}else if(ce>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=k.name||k.feature_type,ie=Math.floor((ce-(g?_p:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),ee+3,he+N-4)}z.push({feat:k,x:ee,y:he,w:ce,h:N})}v.current=z,r&&r(F>0?`${F} feature${F>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,f,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(P=>{const W=o.current;if(!W)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=Math.min(P.clientX+14,window.innerWidth-300),D=Math.min(P.clientY+14,window.innerHeight-260);y({feat:L.feat,x:Math.max(4,N),y:Math.max(4,D)});return}y(null)},[t,n]),b=C.useCallback(()=>y(null),[]),j=C.useCallback(P=>{const W=o.current;if(!W||!l)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=L.feat,z=(N.end-N.start)*.15/(1-.3),F=N.start-z,V=N.end+z;i(l.chrom,F,V),y(null);return}},[t,n,l,i]),S=x?Dy(x.feat,a,l==null?void 0:l.chrom):[],E=x?Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:x.x,top:x.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:[s.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),s.jsx(en,{label:"Type",value:x.feat.feature_type}),s.jsx(en,{label:"Strand",value:x.feat.strand||"."}),s.jsx(en,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),s.jsx(en,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),(($=x.feat.attributes)==null?void 0:$.gene)&&x.feat.attributes.gene!==x.feat.name&&s.jsx(en,{label:"Gene",value:x.feat.attributes.gene}),((A=x.feat.attributes)==null?void 0:A.locus_tag)&&s.jsx(en,{label:"Locus",value:x.feat.attributes.locus_tag}),((R=x.feat.attributes)==null?void 0:R.product)&&s.jsx(en,{label:"Product",value:x.feat.attributes.product}),((U=x.feat.attributes)==null?void 0:U.note)&&s.jsx(en,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),S.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:s.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),S.map(P=>s.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[s.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),s.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return s.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:b,onDoubleClick:j}),E]})}function en({label:e,value:t}){return t?s.jsxs("div",{style:{display:"flex",gap:6},children:[s.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),s.jsx("span",{children:t})]}):null}function Dy(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=ly(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let a=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));a+=c+h}a>0&&r.push({trackId:l.id,name:l.name,total:a})}return r}function Ac(e,t,n,r,o,l,i){e.fillStyle=t;const a=Math.min(_p,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-a,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-a,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+a,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+a,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 zc(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 Uy({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t);return C.useEffect(()=>{var f,p;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&&!((f=a==null?void 0:a.variants)!=null&&f.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=a==null?void 0:a.variants)!=null&&p.length)){a&&(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,x=T?1:Math.max(.5,v),y=T?5:Math.max(2,v*2);for(const m of a.variants){const w=(m.pos-l.start)/g*t,b=Wy(m.ref,m.alt);d.strokeStyle=b,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=b,d.beginPath(),d.arc(w,10,y,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=a.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[a,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Wy(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 Hy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return s.jsxs(s.Fragment,{children:[s.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&&Wn.createPortal(s.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 Vy({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=at(),{theme:a}=Xe(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback(A=>{d({x:A.clientX,y:A.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const y=(l.start-o.start)/x,f=(l.end-o.start)/x,p=Math.max(0,y*e),w=Math.min(e,f*e)-p;if(w<1)return null;const b=Gy(l,n,r),j=l.end-l.start,S=260,E=Math.min(h.x+14,window.innerWidth-S-10),$=Math.min(h.y+14,window.innerHeight-200);return s.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[s.jsx("div",{style:{position:"absolute",left:p,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:A=>{A.stopPropagation(),i()}}),u&&Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:E,top:$,background:a.panelBg,border:`1px solid ${a.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:a.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:S},children:[s.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Length:"})," ",j.toLocaleString()," bp"]}),b.map((A,R)=>s.jsxs("div",{children:[s.jsxs("span",{style:{color:a.textSecondary},children:[A.label,":"]})," ",A.value]},R)),s.jsx("div",{style:{fontSize:9,color:a.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Gy(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 a=i.cigar.match(/(\d+)I/g);if(a)for(const u of a)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((a,u)=>a+(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,a=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:a.toFixed(1)}),u!==a&&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 Yy 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?s.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 Qy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:a,onDrop:u,onDragEnd:c}){const{theme:h}=Xe(),{updateTrack:d,removeTrack:g}=Jt(),T=C.useRef(null),v=C.useRef(null),[x,y]=C.useState(!1),[f,p]=C.useState(!1),[m,w]=C.useState(null),b=C.useRef(null),j=C.useRef(null),S=e.track_type==="annotations"||e.track_type==="genome_annotations";Pp(T);const E=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],$=t-n,A={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"}},R=C.useCallback(P=>{P.preventDefault(),P.stopPropagation();const W=P.clientY,O=e.height;function Y(L){const N=Math.max(30,Math.min(500,O+(L.clientY-W)));d(e.id,{height:N})}function I(){window.removeEventListener("mousemove",Y),window.removeEventListener("mouseup",I),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Y),window.addEventListener("mouseup",I)},[e.id,e.height,d]);function U(){const P={track:e,width:$,height:e.height,onWarning:w};switch(e.track_type){case"reads":return s.jsx(Ay,{...P});case"coverage":return s.jsx(Py,{...P});case"variants":return s.jsx(Uy,{...P});case"annotations":case"genome_annotations":return s.jsx(Iy,{...P});default:return s.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return s.jsxs("div",{style:{...A.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",a==null||a()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[s.jsxs("div",{style:A.label,children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.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:"≡"}),s.jsx("div",{ref:b,children:S?s.jsxs(s.Fragment,{children:[s.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:P=>{P.stopPropagation(),p(W=>!W)}}),f&&Wn.createPortal(s.jsx(Jy,{track:e,theme:h,anchorRef:b,onClose:()=>p(!1),onChange:(P,W)=>{const O={...e.annotationColors||{},[P]:W};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):s.jsxs(s.Fragment,{children:[s.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:P=>{P.stopPropagation(),y(!0)},onDoubleClick:P=>{var W;P.stopPropagation(),y(!1),(W=j.current)==null||W.click()}}),s.jsx("input",{ref:j,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:b.current?b.current.getBoundingClientRect().left:0,top:b.current?b.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:()=>y(!1),children:E.map(P=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),y(!1)}},P))}),document.body)]})}),s.jsx("div",{style:{...A.trackName,flex:1},title:e.name,children:e.name}),s.jsx("span",{title:"Remove track",onClick:P=>{P.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:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsxs("div",{style:A.trackType,children:[e.file_format," · ",e.track_type]}),m&&s.jsx(Hy,{message:m,theme:h})]}),r&&s.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),s.jsxs("div",{style:A.trackArea,ref:T,children:[s.jsx(Yy,{children:U()}),s.jsx(Vy,{width:$,height:e.height,trackData:jp(e.id),trackType:e.track_type})]}),s.jsx("div",{ref:v,onMouseDown:R,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:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const Xy=[{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"}],Ky=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],qy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Jy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var x;const[i,a]=C.useState(null),u=C.useRef(null),[c,h]=C.useState(null),d=e.annotationColors||{},g=(x=n.current)==null?void 0:x.getBoundingClientRect();function T(y){return d[y]||t[qy[y]]||Sp[y]}function v(y){h(y),u.current&&(u.current.value=T(y),u.current.click())}return s.jsxs("div",{style:{position:"fixed",left:g?Math.min(g.left,window.innerWidth-220):0,top:g?g.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:[s.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"}),Xy.map(({key:y,label:f})=>{const p=T(y);return s.jsxs("div",{children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:m=>m.currentTarget.style.background=t.selectedRow,onMouseLeave:m=>m.currentTarget.style.background="transparent",onClick:()=>a(i===y?null:y),children:[s.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:p,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0,cursor:"pointer"},onDoubleClick:m=>{m.stopPropagation(),v(y)},title:"Click to expand, double-click for full picker"}),s.jsx("span",{style:{flex:1},children:f}),s.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&s.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ky.map(m=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:m,cursor:"pointer",border:m===p?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,m),a(null)}},m))})]},y)}),s.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:s.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})}),s.jsx("input",{ref:u,type:"color",style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0},onChange:y=>{c&&o(c,y.target.value)}})]})}function Zy({labelWidth:e}){const{genome:t,region:n}=at(),{tracks:r}=Jt(),{theme:o,themeName:l,customTheme:i}=Xe(),[a,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function x(y){y.preventDefault(),y.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),C.useEffect(()=>{if(!d)return;function x(y){(y.ctrlKey||y.metaKey)&&y.key==="w"&&(y.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[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 x=Da(t,n,r,l,i,e);Ua(x),Rp(x)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return a?s.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:s.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:x=>x.stopPropagation(),children:[s.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),s.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",s.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),s.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[s.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"}),s.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"}),s.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 $c="2.3.4";let ex=0;function Nc({size:e=32}){const[t]=Hs.useState(()=>`blogo${++ex}`);return s.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[s.jsxs("defs",{children:[s.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[s.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),s.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),s.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),s.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[s.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),s.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),s.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),s.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function tx({theme:e,labelWidth:t}){return s.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[s.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:s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[s.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),s.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),s.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),s.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),s.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function nx(){const{theme:e}=Xe(),{genome:t,region:n,setGenome:r,navigateTo:o}=at(),{tracks:l,reorderTracks:i,addTrack:a,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Jt(),T=C.useRef(null),[v,x]=C.useState(800),[y,f]=C.useState(!1),[p,m]=C.useState(!1),[w,b]=C.useState(!1),[j,S]=C.useState(!1),[E,$]=C.useState(!1),[A,R]=C.useState(!1),[U,P]=C.useState(140),[W,O]=C.useState(null),[Y,I]=C.useState(null),[L,N]=C.useState(!1),[D,z]=C.useState(null),[F,V]=C.useState(null),[M,k]=C.useState(null),Q=C.useRef(0);Sy(U),C.useEffect(()=>{const B=()=>fetch("/api/heartbeat").catch(()=>{});B();const q=setInterval(B,1e4);return()=>clearInterval(q)},[]);const ee=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==ee.current&&(ee.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ce=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),he=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),pe=new Set([".bai"]);function ae(B){if(!B)return"";if(B.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=B.lastIndexOf(".");return q>=0?B.slice(q).toLowerCase():""}const ie=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current++,Q.current===1&&N(!0))},[]),ne=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current--,Q.current<=0&&(Q.current=0,N(!1)))},[]),xe=C.useCallback(B=>{B.preventDefault(),B.stopPropagation()},[]);function Me(B){const q=B==null?void 0:B.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ve=C.useCallback(async B=>{var Ie,ut,Wa,Ha,Va;if(B.preventDefault(),B.stopPropagation(),Q.current=0,N(!1),!((ut=(Ie=B.dataTransfer)==null?void 0:Ie.types)!=null&&ut.includes("Files")))return;const q=Array.from(B.dataTransfer.files);if(!q.length)return;const X=[],Z=[],le=[],oe=[];for(const Re of q){const Be=ae(Re.name),yt=Re.name.toLowerCase();ce.has(Be)?X.push(Re):he.has(Be)||Be===".vcf.gz"?Z.push(Re):pe.has(Be)||yt.endsWith(".bam.bai")?le.push(Re):oe.push(Re)}const fe=Z.filter(Re=>Re.name.toLowerCase().endsWith(".bam")&&Re.size>50*1024*1024),we=le.filter(Re=>Re.size>10*1024*1024);if(fe.length||we.length){const Re=[...fe,...we].map(yt=>yt.name).join(", "),Be=[...fe,...we].reduce((yt,jo)=>yt+jo.size,0)/(1024*1024);z({error:`${Re} (${Be.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(()=>z(null),1e4);return}if(oe.length&&!X.length&&!Z.length&&!le.length){z({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(X.length>0&&!t){z({msg:`Loading genome: ${X[0].name}...`});const Be=(await yn.load(X[0])).data;if(Be.name&&(Be.name=Ft(Be.name)),r(Be),((Wa=Be.chromosomes)==null?void 0:Wa.length)>0){const yt=Be.chromosomes[0];o(yt.name,0,Math.min(yt.length,5e4))}Be.is_annotated&&d({id:"genome_annotations",name:`${Be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Be.annotated_chromosomes||null})}else X.length>0&&t&&V({files:X});if(Z.length>0){if(!t&&X.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Re=[],Be=[],yt=[];for(const jo of Z)try{const kn=await u(jo,void 0);Me(kn)?Be.push(kn):(c(kn),Re.push(kn))}catch(kn){yt.push(`${jo.name}: ${((Va=(Ha=kn.response)==null?void 0:Ha.data)==null?void 0:Va.detail)||kn.message}`)}if(yt.length){z({error:yt.join("; ")}),setTimeout(()=>z(null),5e3);return}Be.length>0&&k({tracks:Be})}oe.length?(z({error:`Skipped unsupported: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(Re){z({error:Re.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,a,d]),Fe=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{const Z=[];for(const le of B){z({msg:`Adding chromosomes from ${le.name}...`});try{const fe=(await yn.addChromosomes(le)).data;fe.name&&(fe.name=Ft(fe.name)),r(fe),fe.is_annotated&&d({id:"genome_annotations",name:`${fe.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:fe.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${B.length} file${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[F,r,d]),et=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{z({msg:`Loading ${B.length} track${B.length>1?"s":""}...`});const Z=[];for(const le of B)try{await a(le,void 0)}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${B.length} track${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[F,a]),me=C.useCallback(async()=>{if(M){for(const B of M.tracks)await h(B.id);k(null)}},[M,h]),gt=C.useCallback(()=>{if(M){for(const B of M.tracks)c(B);k(null),z({msg:`Added ${M.tracks.length} track${M.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[M,c]),G=C.useCallback(B=>{B.preventDefault();const q=B.clientX,X=U;function Z(oe){P(Math.max(60,Math.min(400,X+(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)},[U]);C.useEffect(()=>{if(!T.current)return;const B=new ResizeObserver(q=>{for(const X of q)x(X.contentRect.width)});return B.observe(T.current),()=>B.disconnect()},[]);const J=C.useCallback(B=>B.visible?!B.targetChromosomes||!(n!=null&&n.chrom)?!0:B.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),te={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 s.jsxs("div",{style:te.app,onDragEnter:ie,onDragLeave:ne,onDragOver:xe,onDrop:ve,children:[s.jsxs("div",{style:te.header,children:[s.jsxs("div",{style:te.headerLeft,children:[s.jsx(Nc,{size:34}),s.jsxs("div",{children:[s.jsx("div",{style:te.title,children:"BiNgo Genome Viewer"}),t&&s.jsxs("div",{style:te.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),s.jsxs("button",{onClick:()=>$(!0),title:"About / References",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:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.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"}),s.jsx("circle",{cx:"8",cy:"4.5",r:"1.2"}),s.jsx("rect",{x:"7",y:"6.5",width:"2",height:"5.5",rx:"0.8"})]}),"Info"]}),s.jsxs("button",{onClick:()=>R(!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:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.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"}),s.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"]})]}),s.jsxs("div",{style:te.headerBtns,"data-tour":"header-btns",children:[s.jsxs("button",{style:te.btn,onClick:()=>S(!0),title:"Save or restore a session",children:[s.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:[s.jsx("path",{d:"M2 2h8v8H2z"}),s.jsx("path",{d:"M4 2v4h4V2"}),s.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),s.jsxs("button",{style:te.btn,onClick:()=>m(!0),title:"Customize color theme",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[s.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),s.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),s.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),s.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),s.jsxs("button",{"data-tour":"btn-export",style:{...te.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&b(!0)},title:"Export current view as SVG or PNG",children:[s.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:s.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),s.jsxs("button",{"data-tour":"btn-settings",style:{...te.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&f(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),s.jsx(W0,{}),s.jsx(jy,{}),s.jsxs("div",{style:te.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&s.jsx(tx,{theme:e,labelWidth:U}),t?n?s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{display:"flex"},children:[s.jsx("div",{style:{width:U,minWidth:U,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:s.jsx("div",{onMouseDown:G,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:B=>B.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:B=>B.currentTarget.style.background="transparent"})}),s.jsx(Ey,{width:v-U})]}),l.filter(J).map(B=>s.jsx(Qy,{track:B,containerWidth:v,labelWidth:U,onLabelResizeStart:G,isDragging:W===B.id,isDropTarget:Y===B.id,onDragStart:()=>O(B.id),onDragOver:()=>I(B.id),onDrop:()=>{W&&W!==B.id&&i(W,B.id),O(null),I(null)},onDragEnd:()=>{O(null),I(null)}},B.id)),l.length===0&&s.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):s.jsx("div",{style:te.emptyState,children:s.jsx("div",{style:te.emptyHint,children:"Select a chromosome to begin"})}):s.jsxs("div",{style:te.emptyState,children:[s.jsx("div",{style:te.emptyTitle,children:"No genome loaded"}),s.jsx("div",{style:te.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),y&&s.jsx(Q0,{onClose:()=>f(!1)}),p&&s.jsx(Z0,{onClose:()=>m(!1)}),w&&s.jsx(ay,{onClose:()=>b(!1)}),j&&s.jsx(by,{onClose:()=>S(!1),labelWidth:U,setLabelWidth:P}),A&&s.jsx(Ty,{onClose:()=>{R(!1),f(!1),m(!1)},theme:e,onAction:B=>{B==="open-settings"?(f(!0),m(!1)):B==="open-theme"?(m(!0),f(!1)):(f(!1),m(!1))}}),E&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>$(!1),children:s.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:B=>B.stopPropagation(),children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[s.jsx(Nc,{size:44}),s.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",$c]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),s.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",$c,") [Software]."]}),s.jsxs("details",{style:{marginBottom:20},children:[s.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),s.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),s.jsxs("div",{children:[s.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",s.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),s.jsxs("div",{children:[s.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",s.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",s.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",s.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),s.jsxs("div",{children:[s.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",s.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),s.jsx("div",{children:"Early version testing and feedback:"}),s.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),s.jsx("div",{style:{textAlign:"right"},children:s.jsx("button",{onClick:()=>$(!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"})})]})}),F&&(()=>{const B=F.files.length>1,q=F.files.map(X=>X.name).join(", ");return s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.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:X=>X.stopPropagation(),children:[s.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",B?"s":""," detected"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[s.jsx("strong",{style:{color:e.textPrimary},children:q}),B?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",s.jsx("br",{}),"How would you like to handle ",B?"them":"it","?"]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:()=>V(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"}),s.jsxs("button",{onClick:et,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",B?"s":""]}),s.jsxs("button",{onClick:Fe,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",B?"s":""]})]})]})})})(),M&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.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:B=>B.stopPropagation(),children:[s.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[M.tracks.map(B=>{var q;return s.jsxs("div",{style:{marginBottom:6},children:[s.jsx("strong",{style:{color:e.textPrimary},children:B.name})," — ",((q=B.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},B.id)}),s.jsx("div",{style:{marginTop:8},children:M.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:me,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"}),s.jsx("button",{onClick:gt,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),L&&s.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:s.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[s.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),s.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),D&&s.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:D.error?"#c62828":e.panelBg,border:`1px solid ${D.error?"#e53935":e.borderAccent}`,color:D.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:D.error||D.msg}),t&&s.jsx(Zy,{labelWidth:U})]})}function rx(){return s.jsx(F0,{children:s.jsx(rg,{children:s.jsx($0,{children:s.jsx(nx,{})})})})}Di.createRoot(document.getElementById("root")).render(s.jsx(Hs.StrictMode,{children:s.jsx(rx,{})}));
97
+ `):null)}},[a,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]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Ni(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,a=(n[l]+n[l+1])/2;e.quadraticCurveTo(t[l],n[l],i,a)}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 $r(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),a=2,u=i.width+a*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+a,r+1),e.textBaseline="alphabetic"}function _y(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 Pc=6,Oi=8,Fi=14,Ii=2,Ly="#9c27b0",Vo=10,My={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"},By="#ffeb3b";function _c(e,t){return e<=0||t<=0?0:Math.log2(e+1)/Math.log2(t+1)}function Ay({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t),[c,h]=C.useState(null),d=C.useRef(null),[g,T]=C.useState(0),v=C.useRef(null),x=e.showNucleotides!==!1,y=e.useArrows!==!1,f=e.logScale===!0,p=e.fwdColor||"#90a4ae",m=e.revColor||"#f06292",w=e.arrowStyle||"pointed",b=e.arrowSize||4,j=C.useRef(null);C.useEffect(()=>{if(l&&j.current){const $=j.current;($.chrom!==l.chrom||Math.abs($.start-l.start)>$.end-$.start)&&T(0)}j.current=l},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end]),C.useEffect(()=>{if(!l||!x){h(null);return}const $=l.end-l.start;if(t/$<Pc||$>2e3){h(null);return}if(c&&c.chrom===l.chrom&&c.start<=l.start&&c.end>=l.end)return;const R=Math.max(0,l.start-500),U=l.end+500,P=`${l.chrom}:${R}-${U}`;d.current!==P&&(d.current=P,yn.sequence(l.chrom,R,U).then(W=>h({chrom:l.chrom,start:R,end:U,sequence:W.data.sequence})).catch(()=>{}))},[l==null?void 0:l.chrom,l==null?void 0:l.start,l==null?void 0:l.end,t,x]);const S=C.useCallback($=>{var W;if(!((W=a==null?void 0:a.reads)!=null&&W.length)||!$.shiftKey&&Math.abs($.deltaX)>Math.abs($.deltaY))return;const A=x&&c?Fi:Oi,R=Math.max(0,...a.reads.map(O=>O.row)),U=Math.floor(n/(A+Ii)),P=Math.max(0,R-U+2);P<=0||($.preventDefault(),$.stopPropagation(),T(O=>Math.max(0,Math.min(P,O+Math.sign($.deltaY)*3))))},[a,n,x,c]);C.useEffect(()=>{var k;const $=o.current;if(!$)return;const A=window.devicePixelRatio||1;$.width=t*A,$.height=n*A;const R=$.getContext("2d");if(R.scale(A,A),R.clearRect(0,0,t,n),R.fillStyle=i.canvasBg,R.fillRect(0,0,t,n),u&&!a){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!a){r&&r(null);return}const U=l.start,P=l.end-l.start;if(a.bins){const Q=a.max_value||1,ee=e.scaleMax!=null?e.scaleMax:Q,ce=e.color||"#78909c",he=e.barAutoWidth!==!1,pe=e.barWidth||2,ae=t/P;if(e.showBars!==!1){R.fillStyle=ce;for(const ne of a.bins){const xe=(ne.end-ne.start)/P*t,Me=he?ae>=1?Math.max(1,Math.min(ae,xe)):Math.max(1,xe):Math.min(pe,xe),ve=(ne.start-U)/P*t,et=(f?_c(ne.value,ee):Math.min(1,ne.value/ee))*(n-14);R.fillRect(ve,n-et-2,Me,et)}}if(e.showOutline&&a.bins.length>0){const ne=e.outlineSmooth||0,xe=a.bins.map(me=>f?_c(me.value,ee):Math.min(1,me.value/ee)),Me=$y(xe,ne),ve=a.bins.map(me=>((me.start+me.end)/2-U)/P*t),Fe=Me.map(me=>n-me*(n-14)-2),et=e.outlineColor||i.textPrimary||"#fff";if(R.beginPath(),R.moveTo(ve[0],Fe[0]),ne>0){for(let me=0;me<ve.length-1;me++)R.quadraticCurveTo(ve[me],Fe[me],(ve[me]+ve[me+1])/2,(Fe[me]+Fe[me+1])/2);R.lineTo(ve[ve.length-1],Fe[Fe.length-1])}else for(let me=0;me<ve.length;me++)R.lineTo(ve[me],Fe[me]);R.strokeStyle=et,R.lineWidth=1.5,R.stroke()}const ie=f?" log₂":"";Lc(R,`${ee.toFixed(1)}${ie}`,2,2,i),Lc(R,"0",2,n-12,i,!0),R.fillStyle="#ffb74d",R.font="10px Arial, Helvetica, sans-serif",R.textAlign="right",R.fillText("zoom in for reads",t-4,10),r&&r(e.scaleMax!=null&&Q>e.scaleMax?`Bars clipped: max value ${Q.toFixed(1)} exceeds scale ${e.scaleMax.toFixed(1)}`:null);return}if(!((k=a.reads)!=null&&k.length)){R.fillStyle=i.textTertiary,R.font="11px Arial, Helvetica, sans-serif",R.fillText("No reads in region",8,n/2+4),r&&r(null);return}const W=Q=>(Q-U)/P*t,O=t/P,Y=x&&O>=Pc&&c!=null,I=Y?Fi:Oi,L=Ii,D=Math.max(0,...a.reads.map(Q=>Q.row))+1,z=Math.floor(n/(I+L)),F=D>z,V=Math.min(g,Math.max(0,D-z+1));let M=0;for(const Q of a.reads){const ee=(Q.row-V)*(I+L)+2;if(ee+I<0||ee>n){M++;continue}const ce=Q.strand==="+"?p:m,he=Q.segments;if(he&&he.length>0){const pe=W(Q.start),ae=W(Q.end);R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(pe,ee+I/2),R.lineTo(ae,ee+I/2),R.stroke();let ie=0;for(const ne of he)if(ne.type==="M"){const xe=W(ne.start),Me=Math.max(1,W(ne.end)-xe);if(R.fillStyle=ce,R.fillRect(xe,ee,Me,I),Y&&Q.sequence){const ve=ne.end-ne.start;for(let Fe=0;Fe<ve;Fe++){const et=ne.start+Fe,me=W(et),gt=W(et+1)-me,G=(Q.sequence[ie+Fe]||"").toUpperCase();let J="";c&&et>=c.start&&et<c.end&&(J=(c.sequence[et-c.start]||"").toUpperCase());const te=J&&G&&G!==J&&G!=="N";te&&(R.fillStyle=By,R.fillRect(me,ee,gt,I)),gt>=6&&(R.fillStyle=te?"#000":My[G]||"#999",R.font=`bold ${Math.min(11,gt-1)}px monospace`,R.textAlign="center",R.textBaseline="middle",R.fillText(G,me+gt/2,ee+I/2))}ie+=ve}}else if(ne.type==="D"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=1&&(R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke())}else if(ne.type==="N"){const xe=W(ne.start),Me=W(ne.end)-xe;Me>=2&&(R.setLineDash([2,2]),R.strokeStyle=ce,R.lineWidth=1,R.beginPath(),R.moveTo(xe,ee+I/2),R.lineTo(xe+Me,ee+I/2),R.stroke(),R.setLineDash([]))}else ne.type==="I"?(R.fillStyle=Ly,R.fillRect(W(ne.pos)-1,ee-1,2,I+2),Y&&(ie+=ne.length)):ne.type==="S"&&Y&&(ie+=ne.length)}else{const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe);R.fillStyle=Q.strand==="+"?p:m,R.fillRect(pe,ee,ae,I)}if(y&&w!=="flat"){const pe=W(Q.start),ae=Math.max(2,W(Q.end)-pe),ie=Math.min(b,ae/2);ie>=2&&zy(R,w,Q.strand,pe,ee,ae,I,ie,ce,i.canvasBg)}if(!Y&&!x){const pe=W(Q.start);Math.max(2,W(Q.end)-pe)>60&&(R.fillStyle=i.canvasBg,R.font="8px Arial, Helvetica, sans-serif",R.textAlign="left",R.fillText(Q.name.slice(0,20),pe+2,ee+I-1))}}if(F){const Q=t-Vo;R.fillStyle=i.inputBg||"#2a2a2a",R.fillRect(Q,0,Vo,n);const ee=z/D,ce=Math.max(20,ee*n),pe=(D>z?V/(D-z):0)*(n-ce);R.fillStyle="#555",R.fillRect(Q+1,pe,Vo-2,ce)}r&&(M>0&&!F?r(`${M} read${M>1?"s":""} hidden — increase track height to show all`):r(F?`${D} rows · Shift+scroll or drag scrollbar to navigate`:null))},[a,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 E=C.useCallback($=>{var D;if(!((D=a==null?void 0:a.reads)!=null&&D.length))return;const A=o.current;if(!A)return;const R=A.getBoundingClientRect();if(($.clientX-R.left)*(t/R.width)<t-Vo)return;const P=x&&c?Fi:Oi,O=Math.max(0,...a.reads.map(z=>z.row))+1,Y=Math.floor(n/(P+Ii)),I=Math.max(0,O-Y+1);if(I<=0)return;$.preventDefault(),v.current={maxScroll:I,startY:$.clientY,startRow:g};function L(z){if(!v.current)return;const F=z.clientY-v.current.startY,V=Math.round(F/n*v.current.maxScroll);T(Math.max(0,Math.min(v.current.maxScroll,v.current.startRow+V)))}function N(){v.current=null,window.removeEventListener("mousemove",L),window.removeEventListener("mouseup",N)}window.addEventListener("mousemove",L),window.addEventListener("mouseup",N)},[a,t,n,g,x,c]);return s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onWheel:S,onMouseDown:E})}function zy(e,t,n,r,o,l,i,a,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-a,o),e.lineTo(r+l-a,o+i),e.fill()):(e.beginPath(),e.moveTo(r,o+i/2),e.lineTo(r+a,o),e.lineTo(r+a,o+i),e.fill());else if(t==="chevron")e.strokeStyle=c,e.lineWidth=1.5,h?(e.beginPath(),e.moveTo(r+l-a,o),e.lineTo(r+l,o+i/2),e.lineTo(r+l-a,o+i),e.stroke()):(e.beginPath(),e.moveTo(r+a,o),e.lineTo(r,o+i/2),e.lineTo(r+a,o+i),e.stroke());else if(t==="fade")if(h){const d=e.createLinearGradient(r+l-a*2,0,r+l,0);d.addColorStop(0,"rgba(0,0,0,0)"),d.addColorStop(1,c),e.fillStyle=d,e.fillRect(r+l-a*2,o,a*2,i)}else{const d=e.createLinearGradient(r,0,r+a*2,0);d.addColorStop(0,c),d.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=d,e.fillRect(r,o,a*2,i)}}function $y(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),a=Math.min(e.length-1,r+t);for(let u=i;u<=a;u++)o+=e[u],l++;n[r]=o/l}return n}function Lc(e,t,n,r,o,l=!1){e.font="10px Arial, Helvetica, sans-serif",e.textAlign="left",e.textBaseline="top";const i=2,a=e.measureText(t).width+i*2;e.fillStyle=o.canvasBg||"#1e1e1e",e.globalAlpha=.75,e.fillRect(n,r,a,12),e.globalAlpha=1,e.fillStyle=l?o.textTertiary||"#666":o.textSecondary||"#aaa",e.fillText(t,n+i,r+1),e.textBaseline="alphabetic"}const Ny=16,Oy=22,Fy=4,_p=8,Mc=6,Bc={A:"#4caf50",T:"#f44336",C:"#2196f3",G:"#ff9800",N:"#9e9e9e"};function Iy({track:e,width:t,height:n,onWarning:r}){var $,A,R,U;const o=C.useRef(null),{region:l,navigateTo:i}=at(),{tracks:a}=Jt(),{theme:u}=Xe(),{data:c,loading:h,error:d}=ei(e,l,t),g=e.useArrows!==!1,T=e.showNucleotides!==!1,v=C.useRef([]),[x,y]=C.useState(null),[f,p]=C.useState(null),m=C.useRef(null);C.useEffect(()=>{if(!l||!T){p(null);return}const P=l.end-l.start;if(t/P<Mc||P>2e3){p(null);return}if(f&&f.chrom===l.chrom&&f.start<=l.start&&f.end>=l.end)return;const O=Math.max(0,l.start-500),Y=l.end+500,I=`${l.chrom}:${O}-${Y}`;m.current!==I&&(m.current=I,yn.sequence(l.chrom,O,Y).then(L=>p({chrom:l.chrom,start:O,end:Y,sequence:L.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 V,M;const P=o.current;if(!P)return;const W=window.devicePixelRatio||1;P.width=t*W,P.height=n*W;const O=P.getContext("2d");if(O.scale(W,W),O.clearRect(0,0,t,n),O.fillStyle=u.canvasBg,O.fillRect(0,0,t,n),v.current=[],h&&!((V=c==null?void 0:c.features)!=null&&V.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(!((M=c==null?void 0:c.features)!=null&&M.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 Y=l.end-l.start,I=t/Y,L=T&&I>=Mc&&f!=null,N=L?Oy:Ny,D=[],z=[];let F=0;if(L){const Q=n-14;O.fillStyle=u.canvasBg,O.fillRect(0,Q,t,14),O.strokeStyle=u.border||"#333",O.lineWidth=.5,O.beginPath(),O.moveTo(0,Q),O.lineTo(t,Q),O.stroke();const ee=Math.min(10,I-1);if(ee>=5){O.font=`bold ${ee}px monospace`,O.textAlign="center",O.textBaseline="middle";for(let ce=Math.floor(l.start);ce<Math.ceil(l.end);ce++)if(f&&ce>=f.start&&ce<f.end){const he=(f.sequence[ce-f.start]||"").toUpperCase(),pe=(ce-l.start)/Y*t;O.fillStyle=Bc[he]||"#999",O.fillText(he,pe+I/2,Q+14/2)}}}for(const k of c.features){let Q=D.findIndex(ae=>k.start>=ae);Q===-1&&(Q=D.length),D[Q]=k.end;const ee=(k.start-l.start)/Y*t,ce=Math.max(2,(k.end-k.start)/Y*t),he=Q*(N+Fy)+2;if(he+N>n){F++;continue}const pe=zc(k.feature_type,e,u);if(k.sub_features&&k.sub_features.length>0){O.fillStyle=pe+"66",O.fillRect(ee,he+N/2-1,ce,2);for(const ae of k.sub_features){const ie=(ae.start-l.start)/Y*t,ne=Math.max(1,(ae.end-ae.start)/Y*t),xe=zc(ae.feature_type,e,u),Me=ae.feature_type==="CDS"?N:N-6,ve=ae.feature_type==="CDS"?he:he+3;g?Ac(O,xe,ie,ve,ne,Me,ae.strand||k.strand):(O.fillStyle=xe,O.fillRect(ie,ve,ne,Me))}}else g?Ac(O,pe,ee,he,ce,N,k.strand):(O.fillStyle=pe,O.fillRect(ee,he,ce,N));if(L){const ae=Math.max(k.start,l.start),ie=Math.min(k.end,l.end);for(let ne=ae;ne<ie;ne++)if(f&&ne>=f.start&&ne<f.end){const xe=(f.sequence[ne-f.start]||"").toUpperCase(),Me=(ne-l.start)/Y*t,ve=I;ve>=6&&(O.fillStyle=Bc[xe]||"#999",O.font=`bold ${Math.min(10,ve-1)}px monospace`,O.textAlign="center",O.textBaseline="middle",O.fillText(xe,Me+ve/2,he+N/2))}}else if(ce>20){O.fillStyle="#fff",O.font="10px Arial, Helvetica, sans-serif",O.textAlign="left",O.textBaseline="alphabetic";const ae=k.name||k.feature_type,ie=Math.floor((ce-(g?_p:0)-4)/6);ie>0&&O.fillText(ae.slice(0,ie),ee+3,he+N-4)}z.push({feat:k,x:ee,y:he,w:ce,h:N})}v.current=z,r&&r(F>0?`${F} feature${F>1?"s":""} hidden — increase track height to show all`:null)},[c,h,d,t,n,l,f,e.color,e.annotationColors,g,e.showNucleotides,u]);const w=C.useCallback(P=>{const W=o.current;if(!W)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=Math.min(P.clientX+14,window.innerWidth-300),D=Math.min(P.clientY+14,window.innerHeight-260);y({feat:L.feat,x:Math.max(4,N),y:Math.max(4,D)});return}y(null)},[t,n]),b=C.useCallback(()=>y(null),[]),j=C.useCallback(P=>{const W=o.current;if(!W||!l)return;const O=W.getBoundingClientRect(),Y=(P.clientX-O.left)*(t/O.width),I=(P.clientY-O.top)*(n/O.height);for(const L of v.current)if(Y>=L.x&&Y<=L.x+L.w&&I>=L.y&&I<=L.y+L.h){const N=L.feat,z=(N.end-N.start)*.15/(1-.3),F=N.start-z,V=N.end+z;i(l.chrom,F,V),y(null);return}},[t,n,l,i]),S=x?Dy(x.feat,a,l==null?void 0:l.chrom):[],E=x?Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:x.x,top:x.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:[s.jsx("div",{style:{fontWeight:700,fontSize:12,marginBottom:2},children:x.feat.name||x.feat.feature_type}),s.jsx(en,{label:"Type",value:x.feat.feature_type}),s.jsx(en,{label:"Strand",value:x.feat.strand||"."}),s.jsx(en,{label:"Location",value:`${x.feat.start.toLocaleString()}–${x.feat.end.toLocaleString()}`}),s.jsx(en,{label:"Length",value:`${(x.feat.end-x.feat.start).toLocaleString()} bp`}),(($=x.feat.attributes)==null?void 0:$.gene)&&x.feat.attributes.gene!==x.feat.name&&s.jsx(en,{label:"Gene",value:x.feat.attributes.gene}),((A=x.feat.attributes)==null?void 0:A.locus_tag)&&s.jsx(en,{label:"Locus",value:x.feat.attributes.locus_tag}),((R=x.feat.attributes)==null?void 0:R.product)&&s.jsx(en,{label:"Product",value:x.feat.attributes.product}),((U=x.feat.attributes)==null?void 0:U.note)&&s.jsx(en,{label:"Note",value:String(x.feat.attributes.note).slice(0,120)}),S.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("div",{style:{borderTop:`1px solid ${u.tooltipBorder}`,margin:"4px 0",paddingTop:4},children:s.jsx("span",{style:{color:u.textSecondary,fontWeight:600,fontSize:10,textTransform:"uppercase"},children:"Track totals in gene"})}),S.map(P=>s.jsxs("div",{style:{display:"flex",justifyContent:"space-between",gap:8},children:[s.jsx("span",{style:{color:u.textSecondary,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",flex:1},children:P.name}),s.jsx("span",{style:{color:u.textPrimary,fontWeight:600,flexShrink:0},children:P.total.toFixed(1)})]},P.trackId))]})]}),document.body):null;return s.jsxs("div",{style:{position:"relative",width:"100%",height:n},children:[s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n},onMouseMove:w,onMouseLeave:b,onDoubleClick:j}),E]})}function en({label:e,value:t}){return t?s.jsxs("div",{style:{display:"flex",gap:6},children:[s.jsxs("span",{style:{opacity:.6,flexShrink:0},children:[e,":"]}),s.jsx("span",{children:t})]}):null}function Dy(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=ly(l.id,n);if(!((o=i==null?void 0:i.bins)!=null&&o.length))continue;let a=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));a+=c+h}a>0&&r.push({trackId:l.id,name:l.name,total:a})}return r}function Ac(e,t,n,r,o,l,i){e.fillStyle=t;const a=Math.min(_p,o*.4);e.beginPath(),i==="+"?(e.moveTo(n,r),e.lineTo(n+o-a,r),e.lineTo(n+o,r+l/2),e.lineTo(n+o-a,r+l),e.lineTo(n,r+l),e.closePath()):i==="-"?(e.moveTo(n+a,r),e.lineTo(n+o,r),e.lineTo(n+o,r+l),e.lineTo(n+a,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 zc(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 Uy({track:e,width:t,height:n,onWarning:r}){const o=C.useRef(null),{region:l}=at(),{theme:i}=Xe(),{data:a,loading:u}=ei(e,l,t);return C.useEffect(()=>{var f,p;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&&!((f=a==null?void 0:a.variants)!=null&&f.length)){d.fillStyle=i.textTertiary,d.font="11px Arial, Helvetica, sans-serif",d.fillText("Loading…",8,n/2+4),r&&r(null);return}if(!((p=a==null?void 0:a.variants)!=null&&p.length)){a&&(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,x=T?1:Math.max(.5,v),y=T?5:Math.max(2,v*2);for(const m of a.variants){const w=(m.pos-l.start)/g*t,b=Wy(m.ref,m.alt);d.strokeStyle=b,d.lineWidth=x,d.beginPath(),d.moveTo(w,n-4),d.lineTo(w,14),d.stroke(),d.fillStyle=b,d.beginPath(),d.arc(w,10,y,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=a.variants.filter(w=>w.pos>=l.start&&w.pos<=l.end).length;r(m>50?`${m} variants overlapping — zoom in for detail`:null)}},[a,u,t,n,l,e.color,e.barAutoWidth,e.barWidth,i]),s.jsx("canvas",{ref:o,style:{display:"block",width:"100%",height:n}})}function Wy(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 Hy({message:e,theme:t}){const[n,r]=C.useState(!1),o=C.useRef(null),l=o.current?o.current.getBoundingClientRect():null;return s.jsxs(s.Fragment,{children:[s.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&&Wn.createPortal(s.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 Vy({width:e,height:t,trackData:n,trackType:r}){const{region:o,selection:l,clearSelection:i}=at(),{theme:a}=Xe(),[u,c]=C.useState(!1),[h,d]=C.useState({x:0,y:0}),g=C.useRef(null),T=C.useCallback(A=>{d({x:A.clientX,y:A.clientY}),c(!0)},[]),v=C.useCallback(()=>c(!1),[]);if(!l||!o||l.chrom!==o.chrom)return null;const x=o.end-o.start;if(x<=0)return null;const y=(l.start-o.start)/x,f=(l.end-o.start)/x,p=Math.max(0,y*e),w=Math.min(e,f*e)-p;if(w<1)return null;const b=Gy(l,n,r),j=l.end-l.start,S=260,E=Math.min(h.x+14,window.innerWidth-S-10),$=Math.min(h.y+14,window.innerHeight-200);return s.jsxs("div",{ref:g,style:{position:"absolute",top:0,left:0,width:e,height:t,pointerEvents:"none"},children:[s.jsx("div",{style:{position:"absolute",left:p,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:A=>{A.stopPropagation(),i()}}),u&&Wn.createPortal(s.jsxs("div",{style:{position:"fixed",left:E,top:$,background:a.panelBg,border:`1px solid ${a.borderAccent}`,borderRadius:6,padding:"8px 12px",fontSize:11,color:a.textPrimary,lineHeight:1.6,pointerEvents:"none",zIndex:1e4,boxShadow:"0 4px 16px rgba(0,0,0,0.4)",minWidth:180,maxWidth:S},children:[s.jsx("div",{style:{fontWeight:700,marginBottom:4,fontSize:12},children:"Selected Region"}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Region:"})," ",l.chrom,":",l.start.toLocaleString(),"-",l.end.toLocaleString()]}),s.jsxs("div",{children:[s.jsx("span",{style:{color:a.textSecondary},children:"Length:"})," ",j.toLocaleString()," bp"]}),b.map((A,R)=>s.jsxs("div",{children:[s.jsxs("span",{style:{color:a.textSecondary},children:[A.label,":"]})," ",A.value]},R)),s.jsx("div",{style:{fontSize:9,color:a.textTertiary,marginTop:4},children:"Click to dismiss"})]}),document.body)]})}function Gy(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 a=i.cigar.match(/(\d+)I/g);if(a)for(const u of a)l+=parseInt(u)}if(l>0&&r.push({label:"Insertion bases",value:l.toLocaleString()}),o.length>0){const i=o.reduce((a,u)=>a+(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,a=Math.max(...l),u=Math.min(...l);r.push({label:"Avg coverage",value:i.toFixed(1)}),r.push({label:"Max coverage",value:a.toFixed(1)}),u!==a&&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 Yy 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?s.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 Qy({track:e,containerWidth:t,labelWidth:n=140,onLabelResizeStart:r,isDragging:o,isDropTarget:l,onDragStart:i,onDragOver:a,onDrop:u,onDragEnd:c}){const{theme:h}=Xe(),{updateTrack:d,removeTrack:g}=Jt(),T=C.useRef(null),v=C.useRef(null),[x,y]=C.useState(!1),[f,p]=C.useState(!1),[m,w]=C.useState(null),b=C.useRef(null),j=C.useRef(null),S=e.track_type==="annotations"||e.track_type==="genome_annotations";Pp(T);const E=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],$=t-n,A={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"}},R=C.useCallback(P=>{P.preventDefault(),P.stopPropagation();const W=P.clientY,O=e.height;function Y(L){const N=Math.max(30,Math.min(500,O+(L.clientY-W)));d(e.id,{height:N})}function I(){window.removeEventListener("mousemove",Y),window.removeEventListener("mouseup",I),document.body.style.cursor="",document.body.style.userSelect=""}document.body.style.cursor="ns-resize",document.body.style.userSelect="none",window.addEventListener("mousemove",Y),window.addEventListener("mouseup",I)},[e.id,e.height,d]);function U(){const P={track:e,width:$,height:e.height,onWarning:w};switch(e.track_type){case"reads":return s.jsx(Ay,{...P});case"coverage":return s.jsx(Py,{...P});case"variants":return s.jsx(Uy,{...P});case"annotations":case"genome_annotations":return s.jsx(Iy,{...P});default:return s.jsx("div",{style:{padding:8,color:h.textTertiary,fontSize:11},children:"Unknown track type"})}}return s.jsxs("div",{style:{...A.row,height:e.height,position:"relative",opacity:o?.4:1,borderTop:l?"2px solid #888":void 0},onDragOver:P=>{P.preventDefault(),P.dataTransfer.dropEffect="move",a==null||a()},onDrop:P=>{P.preventDefault(),u==null||u()},onDragEnd:c,children:[s.jsxs("div",{style:A.label,children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsx("div",{draggable:!0,onDragStart:P=>{P.dataTransfer.effectAllowed="move",P.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:"≡"}),s.jsx("div",{ref:b,children:S?s.jsxs(s.Fragment,{children:[s.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:P=>{P.stopPropagation(),p(W=>!W)}}),f&&Wn.createPortal(s.jsx(Jy,{track:e,theme:h,anchorRef:b,onClose:()=>p(!1),onChange:(P,W)=>{const O={...e.annotationColors||{},[P]:W};d(e.id,{annotationColors:O})},onReset:()=>d(e.id,{annotationColors:null})}),document.body)]}):s.jsxs(s.Fragment,{children:[s.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:P=>{P.stopPropagation(),y(!0)},onDoubleClick:P=>{var W;P.stopPropagation(),y(!1),(W=j.current)==null||W.click()}}),s.jsx("input",{ref:j,type:"color",value:e.color||"#78909c",onChange:P=>d(e.id,{color:P.target.value}),style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0}}),x&&Wn.createPortal(s.jsx("div",{style:{position:"fixed",left:b.current?b.current.getBoundingClientRect().left:0,top:b.current?b.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:()=>y(!1),children:E.map(P=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:P,cursor:"pointer",border:P===e.color?`2px solid ${h.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onMouseUp:()=>{d(e.id,{color:P}),y(!1)}},P))}),document.body)]})}),s.jsx("div",{style:{...A.trackName,flex:1},title:e.name,children:e.name}),s.jsx("span",{title:"Remove track",onClick:P=>{P.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:P=>P.currentTarget.style.opacity="1",onMouseLeave:P=>P.currentTarget.style.opacity="0.7",children:"×"})]}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4},children:[s.jsxs("div",{style:A.trackType,children:[e.file_format," · ",e.track_type]}),m&&s.jsx(Hy,{message:m,theme:h})]}),r&&s.jsx("div",{onMouseDown:r,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]}),s.jsxs("div",{style:A.trackArea,ref:T,children:[s.jsx(Yy,{children:U()}),s.jsx(Vy,{width:$,height:e.height,trackData:jp(e.id),trackType:e.track_type})]}),s.jsx("div",{ref:v,onMouseDown:R,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:P=>P.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:P=>P.currentTarget.style.background="transparent"})]})}const Xy=[{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"}],Ky=["#f44336","#ef5350","#e57373","#ff5722","#ff8a65","#ff9800","#ffa726","#ffb74d","#ffc107","#fff176","#4caf50","#66bb6a","#81c784","#aed581","#009688","#26c6da","#80cbc4","#2196f3","#42a5f5","#64b5f6","#7e57c2","#9575cd","#9c27b0","#ab47bc","#ce93d8","#e91e63","#f06292","#795548","#8d6e63","#607d8b","#78909c"],qy={cds:"geneCds",exon:"geneExon",gene:"geneGene",transcript:"geneTranscript",utr:"geneUtr",rrna:"geneRrna",trna:"geneTrna",repeat:"geneRepeat",default:"geneDefault"};function Jy({track:e,theme:t,anchorRef:n,onClose:r,onChange:o,onReset:l}){var x;const[i,a]=C.useState(null),u=C.useRef(null),[c,h]=C.useState(null),d=e.annotationColors||{},g=(x=n.current)==null?void 0:x.getBoundingClientRect();function T(y){return d[y]||t[qy[y]]||Sp[y]}function v(y){h(y),u.current&&(u.current.value=T(y),u.current.click())}return s.jsxs("div",{style:{position:"fixed",left:g?Math.min(g.left,window.innerWidth-220):0,top:g?g.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:[s.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"}),Xy.map(({key:y,label:f})=>{const p=T(y);return s.jsxs("div",{children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"4px 10px",cursor:"pointer",fontSize:11,color:t.textPrimary},onMouseEnter:m=>m.currentTarget.style.background=t.selectedRow,onMouseLeave:m=>m.currentTarget.style.background="transparent",onClick:()=>a(i===y?null:y),children:[s.jsx("span",{style:{display:"inline-block",width:14,height:14,borderRadius:3,background:p,border:"1px solid rgba(255,255,255,0.15)",flexShrink:0,cursor:"pointer"},onDoubleClick:m=>{m.stopPropagation(),v(y)},title:"Click to expand, double-click for full picker"}),s.jsx("span",{style:{flex:1},children:f}),s.jsx("span",{style:{fontSize:9,color:t.textTertiary},children:i===y?"▲":"▼"})]}),i===y&&s.jsx("div",{style:{padding:"4px 10px 6px 32px",display:"grid",gridTemplateColumns:"repeat(5, 18px)",gap:3},children:Ky.map(m=>s.jsx("span",{style:{width:18,height:18,borderRadius:3,background:m,cursor:"pointer",border:m===p?`2px solid ${t.textPrimary}`:"1px solid rgba(255,255,255,0.15)",boxSizing:"border-box"},onClick:()=>{o(y,m),a(null)}},m))})]},y)}),s.jsx("div",{style:{borderTop:`1px solid ${t.border}`,marginTop:4,paddingTop:4},children:s.jsx("div",{style:{padding:"4px 10px",fontSize:10,color:t.textTertiary,cursor:"pointer",textAlign:"center"},onMouseEnter:y=>{y.currentTarget.style.color=t.textPrimary},onMouseLeave:y=>{y.currentTarget.style.color=t.textTertiary},onClick:l,children:"Reset to defaults"})}),s.jsx("input",{ref:u,type:"color",style:{position:"absolute",left:-9999,top:-9999,opacity:0,width:0,height:0},onChange:y=>{c&&o(c,y.target.value)}})]})}function Zy({labelWidth:e}){const{genome:t,region:n}=at(),{tracks:r}=Jt(),{theme:o,themeName:l,customTheme:i}=Xe(),[a,u]=C.useState(!1),[c,h]=C.useState(!1),d=!!t;C.useEffect(()=>{if(!d)return;function x(y){y.preventDefault(),y.returnValue=""}return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[d]),C.useEffect(()=>{if(!d)return;function x(y){(y.ctrlKey||y.metaKey)&&y.key==="w"&&(y.preventDefault(),u(!0))}return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[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 x=Da(t,n,r,l,i,e);Ua(x),Rp(x)}catch{}h(!1),window.onbeforeunload=null,window.close(),window.location.href="about:blank"},[t,n,r,l,i,e]);return a?s.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:s.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:x=>x.stopPropagation(),children:[s.jsx("div",{style:{fontSize:16,fontWeight:700,color:o.textPrimary,marginBottom:8},children:"Leave BiNgo Genome Viewer?"}),s.jsxs("div",{style:{fontSize:12,color:o.textSecondary,lineHeight:1.7,marginBottom:20},children:["You have an active session with"," ",s.jsxs("strong",{style:{color:o.textPrimary},children:[r.length," track",r.length!==1?"s":""]})," loaded. Unsaved changes will be lost."]}),s.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8},children:[s.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"}),s.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"}),s.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 $c="2.4.0";let ex=0;function Nc({size:e=32}){const[t]=Hs.useState(()=>`blogo${++ex}`);return s.jsxs("svg",{width:e,height:e,viewBox:"0 0 100 100",style:{flexShrink:0},xmlns:"http://www.w3.org/2000/svg",children:[s.jsxs("defs",{children:[s.jsxs("radialGradient",{id:`${t}_bg`,cx:"35%",cy:"30%",r:"65%",children:[s.jsx("stop",{offset:"0%",stopColor:"#5eb8ff"}),s.jsx("stop",{offset:"50%",stopColor:"#1976d2"}),s.jsx("stop",{offset:"100%",stopColor:"#0d47a1"})]}),s.jsxs("radialGradient",{id:`${t}_sh`,cx:"30%",cy:"25%",r:"30%",children:[s.jsx("stop",{offset:"0%",stopColor:"#ffffff",stopOpacity:"0.7"}),s.jsx("stop",{offset:"100%",stopColor:"#ffffff",stopOpacity:"0"})]})]}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_bg)`}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"white"}),s.jsx("circle",{cx:"50",cy:"48",r:"28",fill:"none",stroke:"#1565c0",strokeWidth:"2.5"}),s.jsx("text",{x:"50",y:"39",textAnchor:"middle",fontSize:"13",fontWeight:"800",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"BN"}),s.jsx("text",{x:"50",y:"64",textAnchor:"middle",fontSize:"30",fontWeight:"900",fontFamily:"Arial, sans-serif",fill:"#0d47a1",children:"1"}),s.jsx("circle",{cx:"50",cy:"50",r:"48",fill:`url(#${t}_sh)`})]})}function tx({theme:e,labelWidth:t}){return s.jsxs("div",{style:{display:"flex",borderBottom:`1px solid ${e.border}`,height:60,opacity:.45},children:[s.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:s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6},children:[s.jsx("span",{style:{fontSize:14,color:e.textTertiary,userSelect:"none",lineHeight:1},children:"≡"}),s.jsx("span",{style:{width:10,height:10,borderRadius:2,background:"#78909c",flexShrink:0}}),s.jsx("span",{style:{fontSize:11,fontWeight:600,color:e.textSecondary,flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:"Track Name"}),s.jsx("span",{style:{fontSize:13,color:e.textTertiary,lineHeight:1,padding:"0 2px"},children:"×"})]})}),s.jsx("div",{style:{flex:1,background:e.canvasBg}})]})}function nx(){const{theme:e}=Xe(),{genome:t,region:n,setGenome:r,navigateTo:o}=at(),{tracks:l,reorderTracks:i,addTrack:a,uploadTrack:u,commitTrack:c,discardTrack:h,addGenomeAnnotationTrack:d,restoreAnnotationTracks:g}=Jt(),T=C.useRef(null),[v,x]=C.useState(800),[y,f]=C.useState(!1),[p,m]=C.useState(!1),[w,b]=C.useState(!1),[j,S]=C.useState(!1),[E,$]=C.useState(!1),[A,R]=C.useState(!1),[U,P]=C.useState(140),[W,O]=C.useState(null),[Y,I]=C.useState(null),[L,N]=C.useState(!1),[D,z]=C.useState(null),[F,V]=C.useState(null),[M,k]=C.useState(null),Q=C.useRef(0);Sy(U),C.useEffect(()=>{const B=()=>fetch("/api/heartbeat").catch(()=>{});B();const q=setInterval(B,1e4);return()=>clearInterval(q)},[]);const ee=C.useRef(n==null?void 0:n.chrom);C.useEffect(()=>{n!=null&&n.chrom&&n.chrom!==ee.current&&(ee.current=n.chrom,g())},[n==null?void 0:n.chrom,g]);const ce=new Set([".gb",".gbk",".genbank",".fasta",".fa"]),he=new Set([".bam",".bw",".bigwig",".wig",".bedgraph",".bdg",".vcf",".bed",".gtf",".gff",".gff2",".gff3"]),pe=new Set([".bai"]);function ae(B){if(!B)return"";if(B.toLowerCase().endsWith(".vcf.gz"))return".vcf.gz";const q=B.lastIndexOf(".");return q>=0?B.slice(q).toLowerCase():""}const ie=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current++,Q.current===1&&N(!0))},[]),ne=C.useCallback(B=>{var q,X;B.preventDefault(),B.stopPropagation(),(X=(q=B.dataTransfer)==null?void 0:q.types)!=null&&X.includes("Files")&&(Q.current--,Q.current<=0&&(Q.current=0,N(!1)))},[]),xe=C.useCallback(B=>{B.preventDefault(),B.stopPropagation()},[]);function Me(B){const q=B==null?void 0:B.compatibility;return q&&q.status!=="ok"&&q.status!=="no_genome"}const ve=C.useCallback(async B=>{var Ie,ut,Wa,Ha,Va;if(B.preventDefault(),B.stopPropagation(),Q.current=0,N(!1),!((ut=(Ie=B.dataTransfer)==null?void 0:Ie.types)!=null&&ut.includes("Files")))return;const q=Array.from(B.dataTransfer.files);if(!q.length)return;const X=[],Z=[],le=[],oe=[];for(const Re of q){const Be=ae(Re.name),yt=Re.name.toLowerCase();ce.has(Be)?X.push(Re):he.has(Be)||Be===".vcf.gz"?Z.push(Re):pe.has(Be)||yt.endsWith(".bam.bai")?le.push(Re):oe.push(Re)}const fe=Z.filter(Re=>Re.name.toLowerCase().endsWith(".bam")&&Re.size>50*1024*1024),we=le.filter(Re=>Re.size>10*1024*1024);if(fe.length||we.length){const Re=[...fe,...we].map(yt=>yt.name).join(", "),Be=[...fe,...we].reduce((yt,jo)=>yt+jo.size,0)/(1024*1024);z({error:`${Re} (${Be.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(()=>z(null),1e4);return}if(oe.length&&!X.length&&!Z.length&&!le.length){z({error:`Unsupported file${oe.length>1?"s":""}: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3);return}try{if(X.length>0&&!t){z({msg:`Loading genome: ${X[0].name}...`});const Be=(await yn.load(X[0])).data;if(Be.name&&(Be.name=Ft(Be.name)),r(Be),((Wa=Be.chromosomes)==null?void 0:Wa.length)>0){const yt=Be.chromosomes[0];o(yt.name,0,Math.min(yt.length,5e4))}Be.is_annotated&&d({id:"genome_annotations",name:`${Be.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:Be.annotated_chromosomes||null})}else X.length>0&&t&&V({files:X});if(Z.length>0){if(!t&&X.length===0){z({error:"Load a genome file first (.fasta, .gb, .genbank)"}),setTimeout(()=>z(null),4e3);return}z({msg:`Loading ${Z.length} track${Z.length>1?"s":""}...`});const Re=[],Be=[],yt=[];for(const jo of Z)try{const kn=await u(jo,void 0);Me(kn)?Be.push(kn):(c(kn),Re.push(kn))}catch(kn){yt.push(`${jo.name}: ${((Va=(Ha=kn.response)==null?void 0:Ha.data)==null?void 0:Va.detail)||kn.message}`)}if(yt.length){z({error:yt.join("; ")}),setTimeout(()=>z(null),5e3);return}Be.length>0&&k({tracks:Be})}oe.length?(z({error:`Skipped unsupported: ${oe.map(Re=>Re.name).join(", ")}`}),setTimeout(()=>z(null),4e3)):(z({msg:"Files loaded"}),setTimeout(()=>z(null),2e3))}catch(Re){z({error:Re.message||"Drop failed"}),setTimeout(()=>z(null),5e3)}},[t,r,o,a,d]),Fe=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{const Z=[];for(const le of B){z({msg:`Adding chromosomes from ${le.name}...`});try{const fe=(await yn.addChromosomes(le)).data;fe.name&&(fe.name=Ft(fe.name)),r(fe),fe.is_annotated&&d({id:"genome_annotations",name:`${fe.name} (annotations)`,track_type:"genome_annotations",file_format:"genbank",targetChromosomes:fe.annotated_chromosomes||null})}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added chromosomes from ${B.length} file${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to add chromosomes"}),setTimeout(()=>z(null),5e3)}},[F,r,d]),et=C.useCallback(async()=>{var q,X;if(!F)return;const B=F.files;V(null);try{z({msg:`Loading ${B.length} track${B.length>1?"s":""}...`});const Z=[];for(const le of B)try{await a(le,void 0)}catch(oe){Z.push(`${le.name}: ${((X=(q=oe.response)==null?void 0:q.data)==null?void 0:X.detail)||oe.message}`)}Z.length?(z({error:Z.join("; ")}),setTimeout(()=>z(null),5e3)):(z({msg:`Added ${B.length} track${B.length>1?"s":""}`}),setTimeout(()=>z(null),3e3))}catch(Z){z({error:Z.message||"Failed to load tracks"}),setTimeout(()=>z(null),5e3)}},[F,a]),me=C.useCallback(async()=>{if(M){for(const B of M.tracks)await h(B.id);k(null)}},[M,h]),gt=C.useCallback(()=>{if(M){for(const B of M.tracks)c(B);k(null),z({msg:`Added ${M.tracks.length} track${M.tracks.length>1?"s":""}`}),setTimeout(()=>z(null),3e3)}},[M,c]),G=C.useCallback(B=>{B.preventDefault();const q=B.clientX,X=U;function Z(oe){P(Math.max(60,Math.min(400,X+(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)},[U]);C.useEffect(()=>{if(!T.current)return;const B=new ResizeObserver(q=>{for(const X of q)x(X.contentRect.width)});return B.observe(T.current),()=>B.disconnect()},[]);const J=C.useCallback(B=>B.visible?!B.targetChromosomes||!(n!=null&&n.chrom)?!0:B.targetChromosomes.includes(n.chrom):!1,[n==null?void 0:n.chrom]),te={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 s.jsxs("div",{style:te.app,onDragEnter:ie,onDragLeave:ne,onDragOver:xe,onDrop:ve,children:[s.jsxs("div",{style:te.header,children:[s.jsxs("div",{style:te.headerLeft,children:[s.jsx(Nc,{size:34}),s.jsxs("div",{children:[s.jsx("div",{style:te.title,children:"BiNgo Genome Viewer"}),t&&s.jsxs("div",{style:te.subtitle,children:[t.name," · ",t.chromosomes.length," chr"]})]}),s.jsxs("button",{onClick:()=>$(!0),title:"About / References",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:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.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"}),s.jsx("circle",{cx:"8",cy:"4.5",r:"1.2"}),s.jsx("rect",{x:"7",y:"6.5",width:"2",height:"5.5",rx:"0.8"})]}),"Info"]}),s.jsxs("button",{onClick:()=>R(!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:B=>{B.currentTarget.style.color=e.textPrimary,B.currentTarget.style.borderColor=e.textSecondary},onMouseLeave:B=>{B.currentTarget.style.color=e.textSecondary,B.currentTarget.style.borderColor=e.border},children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"currentColor",style:{flexShrink:0},children:[s.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"}),s.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"]})]}),s.jsxs("div",{style:te.headerBtns,"data-tour":"header-btns",children:[s.jsxs("button",{style:te.btn,onClick:()=>S(!0),title:"Save or restore a session",children:[s.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:[s.jsx("path",{d:"M2 2h8v8H2z"}),s.jsx("path",{d:"M4 2v4h4V2"}),s.jsx("path",{d:"M5 3h2"})]}),"Save Session"]}),s.jsxs("button",{style:te.btn,onClick:()=>m(!0),title:"Customize color theme",children:[s.jsxs("svg",{width:"12",height:"12",viewBox:"0 0 12 12",style:{flexShrink:0},children:[s.jsx("rect",{x:"0",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#66bb6a"}),s.jsx("rect",{x:"6.5",y:"0",width:"5.5",height:"5.5",rx:"1",fill:"#42a5f5"}),s.jsx("rect",{x:"0",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ffa726"}),s.jsx("rect",{x:"6.5",y:"6.5",width:"5.5",height:"5.5",rx:"1",fill:"#ab47bc"})]}),"Theme"]}),s.jsxs("button",{"data-tour":"btn-export",style:{...te.btn,...n&&l.length>0?{}:{opacity:.35,cursor:"default"}},onClick:()=>{n&&l.length>0&&b(!0)},title:"Export current view as SVG or PNG",children:[s.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:s.jsx("path",{d:"M6 1v7M3 5.5L6 8.5 9 5.5M2 11h8"})}),"Export Image"]}),s.jsxs("button",{"data-tour":"btn-settings",style:{...te.btn,...l.length===0?{opacity:.35,cursor:"default"}:{}},onClick:()=>{l.length>0&&f(!0)},title:"Adjust height, scale, color, and bar width for tracks",children:["⚙"," Track Settings"]})]})]}),s.jsx(W0,{}),s.jsx(jy,{}),s.jsxs("div",{style:te.trackArea,ref:T,"data-tour":"track-area",children:[l.filter(J).length===0&&s.jsx(tx,{theme:e,labelWidth:U}),t?n?s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{display:"flex"},children:[s.jsx("div",{style:{width:U,minWidth:U,background:e.panelBg,borderRight:`1px solid ${e.border}`,position:"relative"},children:s.jsx("div",{onMouseDown:G,style:{position:"absolute",right:-3,top:0,bottom:0,width:6,cursor:"ew-resize",zIndex:10},onMouseEnter:B=>B.currentTarget.style.background="rgba(255,255,255,0.15)",onMouseLeave:B=>B.currentTarget.style.background="transparent"})}),s.jsx(Ey,{width:v-U})]}),l.filter(J).map(B=>s.jsx(Qy,{track:B,containerWidth:v,labelWidth:U,onLabelResizeStart:G,isDragging:W===B.id,isDropTarget:Y===B.id,onDragStart:()=>O(B.id),onDragOver:()=>I(B.id),onDrop:()=>{W&&W!==B.id&&i(W,B.id),O(null),I(null)},onDragEnd:()=>{O(null),I(null)}},B.id)),l.length===0&&s.jsx("div",{style:{padding:24,color:e.textMuted,fontSize:13},children:"Add tracks above — BAM, VCF, BigWig, BED, GTF, GFF, WIG..."})]}):s.jsx("div",{style:te.emptyState,children:s.jsx("div",{style:te.emptyHint,children:"Select a chromosome to begin"})}):s.jsxs("div",{style:te.emptyState,children:[s.jsx("div",{style:te.emptyTitle,children:"No genome loaded"}),s.jsx("div",{style:te.emptyHint,children:"Load a FASTA or GenBank file above to get started"})]})]}),y&&s.jsx(Q0,{onClose:()=>f(!1)}),p&&s.jsx(Z0,{onClose:()=>m(!1)}),w&&s.jsx(ay,{onClose:()=>b(!1)}),j&&s.jsx(by,{onClose:()=>S(!1),labelWidth:U,setLabelWidth:P}),A&&s.jsx(Ty,{onClose:()=>{R(!1),f(!1),m(!1)},theme:e,onAction:B=>{B==="open-settings"?(f(!0),m(!1)):B==="open-theme"?(m(!0),f(!1)):(f(!1),m(!1))}}),E&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},onClick:()=>$(!1),children:s.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:B=>B.stopPropagation(),children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,marginBottom:16},children:[s.jsx(Nc,{size:44}),s.jsx("div",{style:{fontSize:20,fontWeight:700},children:"BiNgo Genome Viewer"})]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Version:"})," ",$c]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:12},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Publisher:"})," Billy M Ngo"]}),s.jsxs("div",{style:{fontSize:13,color:e.textSecondary,marginBottom:20},children:[s.jsx("strong",{style:{color:e.textPrimary},children:"Published:"})," April 2026"]}),s.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",$c,") [Software]."]}),s.jsxs("details",{style:{marginBottom:20},children:[s.jsx("summary",{style:{cursor:"pointer",fontSize:13,fontWeight:600,color:e.textPrimary,marginBottom:8},children:"References & Acknowledgments"}),s.jsxs("div",{style:{fontSize:11,color:e.textSecondary,lineHeight:1.8,paddingTop:8},children:[s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginBottom:4},children:"Software Dependencies"}),s.jsxs("div",{children:[s.jsx("strong",{children:"FastAPI"})," ","—"," Ram","í","rez, S. (2018). A modern web framework for building APIs with Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Uvicorn"})," ","—"," Encode OSS. ASGI server implementation for Python."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BioPython"})," ","—"," Cock, P.J.A. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(11), 1422","–","1423."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"pyfaidx"})," ","—"," Shirley, M.D. et al. (2015). ",s.jsx("em",{children:"PeerJ PrePrints"}),", 3:e1196."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"bamnostic"})," ","—"," Sherman, M.A. & Mills, R.E. (2019). Pure Python BAM parser."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"React"})," ","—"," Meta Platforms, Inc. JavaScript UI library."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"Vite"})," ","—"," You, E. (2020). Next generation frontend tooling."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"File Format Specifications"}),s.jsxs("div",{children:[s.jsx("strong",{children:"SAM/BAM"})," ","—"," Li, H. et al. (2009). ",s.jsx("em",{children:"Bioinformatics"}),", 25(16), 2078","–","2079."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"VCF"})," ","—"," Danecek, P. et al. (2011). ",s.jsx("em",{children:"Bioinformatics"}),", 27(15), 2156","–","2158."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BigWig/WIG"})," ","—"," Kent, W.J. et al. (2010). ",s.jsx("em",{children:"Bioinformatics"}),", 26(17), 2204","–","2207."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"BED"})," ","—"," UCSC Genome Browser, UC Santa Cruz."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GFF3"})," ","—"," Sequence Ontology Project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GTF"})," ","—"," Ensembl genome database project."]}),s.jsxs("div",{children:[s.jsx("strong",{children:"GenBank"})," ","—"," Benson, D.A. et al. (2013). ",s.jsx("em",{children:"Nucleic Acids Res."}),", 41(D1), D36","–","D42."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Inspiration"}),s.jsxs("div",{children:[s.jsx("strong",{children:"IGV"})," ","—"," Robinson, J.T. et al. (2011). ",s.jsx("em",{children:"Nature Biotechnology"}),", 29(1), 24","–","26."]}),s.jsx("div",{style:{fontWeight:600,color:e.textPrimary,marginTop:12,marginBottom:4},children:"Acknowledgments"}),s.jsx("div",{children:"Early version testing and feedback:"}),s.jsx("div",{children:"Amanda Antoch, Isaac Poarch, Otto Chipashvili, Jake Colautti"})]})]}),s.jsx("div",{style:{textAlign:"right"},children:s.jsx("button",{onClick:()=>$(!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"})})]})}),F&&(()=>{const B=F.files.length>1,q=F.files.map(X=>X.name).join(", ");return s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.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:X=>X.stopPropagation(),children:[s.jsxs("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:["Genome file",B?"s":""," detected"]}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[s.jsx("strong",{style:{color:e.textPrimary},children:q}),B?" appear to be genome files. A genome is already loaded.":" appears to be a genome file. A genome is already loaded.",s.jsx("br",{}),"How would you like to handle ",B?"them":"it","?"]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:()=>V(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"}),s.jsxs("button",{onClick:et,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",B?"s":""]}),s.jsxs("button",{onClick:Fe,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:["Add as Chromosome",B?"s":""]})]})]})})})(),M&&s.jsx("div",{style:{position:"fixed",inset:0,background:"rgba(0,0,0,0.45)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999},children:s.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:B=>B.stopPropagation(),children:[s.jsx("div",{style:{fontSize:14,fontWeight:700,color:e.textPrimary,marginBottom:8},children:"Track compatibility warning"}),s.jsxs("div",{style:{fontSize:12,color:e.textSecondary,lineHeight:1.6,marginBottom:16},children:[M.tracks.map(B=>{var q;return s.jsxs("div",{style:{marginBottom:6},children:[s.jsx("strong",{style:{color:e.textPrimary},children:B.name})," — ",((q=B.compatibility)==null?void 0:q.message)||"Possible mismatch with loaded genome"]},B.id)}),s.jsx("div",{style:{marginTop:8},children:M.tracks.length>1?"These tracks may not match the loaded genome.":"This track may not match the loaded genome."})]}),s.jsxs("div",{style:{display:"flex",gap:8,justifyContent:"flex-end",flexWrap:"wrap"},children:[s.jsx("button",{onClick:me,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"}),s.jsx("button",{onClick:gt,style:{background:"#1976d2",border:"none",borderRadius:4,color:"#fff",padding:"5px 16px",cursor:"pointer",fontSize:12,fontWeight:600},children:"Load Anyway"})]})]})}),L&&s.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:s.jsxs("div",{style:{border:`3px dashed ${e.textSecondary}`,borderRadius:16,padding:"40px 60px",textAlign:"center"},children:[s.jsx("div",{style:{fontSize:28,fontWeight:300,color:e.textPrimary,marginBottom:8},children:"Drop files here"}),s.jsx("div",{style:{fontSize:13,color:e.textSecondary},children:"Genome (.gb, .fasta) or track files (.bam, .bw, .wig, .vcf, .bed, .gff, .gtf)"})]})}),D&&s.jsx("div",{style:{position:"fixed",bottom:20,left:"50%",transform:"translateX(-50%)",zIndex:10001,padding:"8px 20px",borderRadius:6,background:D.error?"#c62828":e.panelBg,border:`1px solid ${D.error?"#e53935":e.borderAccent}`,color:D.error?"#fff":"#81c784",fontSize:12,fontWeight:600,boxShadow:"0 4px 16px rgba(0,0,0,0.5)"},children:D.error||D.msg}),t&&s.jsx(Zy,{labelWidth:U})]})}function rx(){return s.jsx(F0,{children:s.jsx(rg,{children:s.jsx($0,{children:s.jsx(nx,{})})})})}Di.createRoot(document.getElementById("root")).render(s.jsx(Hs.StrictMode,{children:s.jsx(rx,{})}));
@@ -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-Dbtbm6Rs.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-v6csp4Bc.js"></script>
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
@@ -73,7 +73,10 @@ async def add_chromosomes(file: UploadFile = File(...)):
73
73
  async def load_genome_from_path(path: str = Form(...)):
74
74
  """Load genome from a local file path."""
75
75
  from pathlib import Path as P
76
- path = path.strip().strip('"').strip("'").replace('\\ ', ' ')
76
+ path = path.strip()
77
+ for q in ('"', "'", '`'):
78
+ path = path.strip(q)
79
+ path = path.strip().replace('\\ ', ' ')
77
80
  p = P(path).expanduser()
78
81
  if not p.exists() and not p.resolve().exists():
79
82
  parent = p.parent
@@ -94,8 +94,12 @@ async def load_track_from_path(path: str = Form(...), name: str = Form("")):
94
94
  """Load track from a local file path (no upload needed)."""
95
95
  from pathlib import Path as P
96
96
 
97
- # Clean up the path: strip whitespace, quotes, and shell escape backslashes
98
- path = path.strip().strip('"').strip("'")
97
+ # Clean up the path: strip whitespace, all quote types, shell escapes
98
+ path = path.strip()
99
+ # Strip matching or trailing quotes (handles '/path', "/path", `/path`, path')
100
+ for q in ('"', "'", '`'):
101
+ path = path.strip(q)
102
+ path = path.strip()
99
103
  # Remove shell-escaped spaces (e.g., /path/to/Sequencing\ Results/ → /path/to/Sequencing Results/)
100
104
  path = path.replace('\\ ', ' ')
101
105
  if path.lower().endswith('.bai'):
@@ -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.3.4")
27
+ app = FastAPI(title="BiNgo Genome Viewer API", version="2.4.0")
28
28
 
29
29
  app.add_middleware(
30
30
  CORSMiddleware,
@@ -5,17 +5,19 @@ CRAM is not supported by bamnostic; use BAM instead.
5
5
  """
6
6
 
7
7
  from pathlib import Path
8
+ from typing import Optional
8
9
 
9
10
  import bamnostic as bam
10
11
 
11
12
  MAX_READS_RETURNED = 5000
13
+ MAX_COVERAGE_READS = 500_000 # cap reads iterated for coverage computation
12
14
  READ_DETAIL_THRESHOLD = 50_000 # bp
13
15
 
14
16
  # Standard index naming conventions: file.bam.bai and file.bai
15
17
  _INDEX_SUFFIXES = (".bam.bai", ".bai")
16
18
 
17
19
 
18
- def _find_index(bam_path: str) -> str | None:
20
+ def _find_index(bam_path: str) -> Optional[str]:
19
21
  """Locate a .bai index for the given BAM file.
20
22
 
21
23
  Checks both naming conventions (.bam.bai and .bai) in the same
@@ -96,8 +98,10 @@ class BamReader:
96
98
  def get_coverage(self, chrom: str, start: int, end: int, bins: int = 1000) -> list[dict]:
97
99
  """Return binned coverage by piling up fetched reads.
98
100
 
99
- For performance with large BAM files, bins reads directly into
100
- coverage bins instead of computing per-base depth first.
101
+ For large regions, splits into sub-regions (50kb chunks) to ensure
102
+ bamnostic's index-based fetch covers the entire span reliably.
103
+ Large BAM files can fail to return all reads from a single huge
104
+ fetch spanning millions of bases.
101
105
  """
102
106
  chrom = self._resolve_chrom(chrom)
103
107
  region_len = end - start
@@ -106,33 +110,45 @@ class BamReader:
106
110
 
107
111
  n_bins = min(bins, region_len)
108
112
  bin_size = region_len / n_bins
109
- # Accumulate coverage directly into bins
110
- counts = [0.0] * n_bins # sum of base-coverage per bin
113
+ counts = [0.0] * n_bins
114
+
115
+ # Split large regions into chunks for reliable index traversal
116
+ CHUNK_SIZE = 50_000
117
+ total_reads = 0
118
+
111
119
  try:
112
- for read in self._aln.fetch(chrom, start, end):
113
- if read.is_unmapped:
114
- continue
115
- rs = read.reference_start
116
- re = read.reference_end if read.reference_end else rs + 1
117
- # Clamp to region
118
- rs = max(rs, start)
119
- re = min(re, end)
120
- if rs >= re:
121
- continue
122
- # Map read span to bin range
123
- bi_start = int((rs - start) / bin_size)
124
- bi_end = int((re - 1 - start) / bin_size) + 1
125
- bi_start = max(0, min(bi_start, n_bins - 1))
126
- bi_end = max(1, min(bi_end, n_bins))
127
- for bi in range(bi_start, bi_end):
128
- # Calculate overlap between read and this bin
129
- b_lo = start + bi * bin_size
130
- b_hi = start + (bi + 1) * bin_size
131
- overlap = min(re, b_hi) - max(rs, b_lo)
132
- if overlap > 0:
133
- counts[bi] += overlap / (b_hi - b_lo)
120
+ chunk_start = start
121
+ while chunk_start < end:
122
+ chunk_end = min(chunk_start + CHUNK_SIZE, end)
123
+ for read in self._aln.fetch(chrom, chunk_start, chunk_end):
124
+ if read.is_unmapped:
125
+ continue
126
+ rs = read.reference_start
127
+ re = read.reference_end if read.reference_end else rs + 1
128
+ rs = max(rs, start)
129
+ re = min(re, end)
130
+ if rs >= re:
131
+ continue
132
+ bi_start = int((rs - start) / bin_size)
133
+ bi_end = int((re - 1 - start) / bin_size) + 1
134
+ bi_start = max(0, min(bi_start, n_bins - 1))
135
+ bi_end = max(1, min(bi_end, n_bins))
136
+ for bi in range(bi_start, bi_end):
137
+ b_lo = start + bi * bin_size
138
+ b_hi = start + (bi + 1) * bin_size
139
+ overlap = min(re, b_hi) - max(rs, b_lo)
140
+ if overlap > 0:
141
+ counts[bi] += overlap / (b_hi - b_lo)
142
+ total_reads += 1
143
+ if total_reads >= MAX_COVERAGE_READS:
144
+ break
145
+ if total_reads >= MAX_COVERAGE_READS:
146
+ break
147
+ chunk_start = chunk_end
134
148
  except KeyError:
135
149
  return []
150
+ except Exception:
151
+ pass
136
152
 
137
153
  result = []
138
154
  for i in range(n_bins):
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "BiNgoViewer"
7
- version = "2.3.4"
7
+ version = "2.4.0"
8
8
  description = "BiNgo Genome Viewer — a lightweight browser-based genomics viewer"
9
9
  readme = "README.md"
10
10
  license = {text = "Proprietary"}
11
- requires-python = ">=3.10"
11
+ requires-python = ">=3.9"
12
12
  authors = [
13
13
  {name = "Billy M Ngo", email = "billy.ngo0108@gmail.com"},
14
14
  ]
@@ -18,6 +18,7 @@ classifiers = [
18
18
  "Intended Audience :: Science/Research",
19
19
  "Topic :: Scientific/Engineering :: Bio-Informatics",
20
20
  "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.9",
21
22
  "Programming Language :: Python :: 3.10",
22
23
  "Programming Language :: Python :: 3.11",
23
24
  "Programming Language :: Python :: 3.12",
File without changes