.br-wrap{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#f7f6f4;padding:40px 20px 48px} .br-fb{font-size:13px;padding:7px 18px;border-radius:20px;border:1px solid #ddd;background:#fff;color:#555;cursor:pointer;transition:all .15s;font-family:inherit} .br-fb:hover{border-color:#aaa;color:#111} .br-fb.on{background:#111;color:#fff;border-color:#111} .br-count{text-align:center;font-size:13px;color:#888;padding:10px 0 16px} .br-card{background:#fff;border-radius:12px;overflow:hidden;border:1px solid #e8e4df;transition:box-shadow .2s;cursor:pointer;height:100%} .br-card:hover{box-shadow:0 4px 20px rgba(0,0,0,.09)} /* single-image cards (unchanged look) */ .br-img-wrap{position:relative;overflow:hidden;background:#f0eee9;height:210px;display:flex;align-items:center;justify-content:center} .br-img{width:100%!important;height:100%!important;max-width:none!important;object-fit:contain!important;object-position:center!important;display:block;transition:transform .3s;padding:8px} .br-card:hover .br-img{transform:scale(1.01)} /* split-frame strip (montage + multi-file cards) */ .br-strip-wrap{position:relative;background:#eef0f4;height:210px} .br-strip-scroll{display:flex;height:100%;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none} .br-strip-scroll::-webkit-scrollbar{display:none} .br-frame{flex:0 0 100%;min-width:0;overflow:hidden;height:100%;scroll-snap-align:center;display:flex;align-items:center;justify-content:center} .br-frame-inner{width:100%;height:100%;background-repeat:no-repeat;background-color:#eef0f4} .br-fimg{width:100%!important;height:100%!important;max-width:none!important;object-fit:cover!important;object-position:center!important;display:block} .br-strip-arrow{position:absolute;top:50%;transform:translateY(-50%);width:30px;height:30px;border-radius:50%;background:rgba(0,0,0,.4);color:#fff;border:none;cursor:pointer;font-size:16px;line-height:1;display:flex;align-items:center;justify-content:center;z-index:2;opacity:0;transition:opacity .2s} .br-card:hover .br-strip-arrow{opacity:1} .br-strip-arrow.pv{left:8px} .br-strip-arrow.nx{right:8px} .br-strip-arrow:disabled{opacity:0 !important;pointer-events:none} .br-strip-count{position:absolute;top:8px;right:8px;background:rgba(0,0,0,.5);color:#fff;font-size:11px;padding:2px 8px;border-radius:10px;z-index:2} .br-dots{position:absolute;bottom:8px;left:0;right:0;display:flex;justify-content:center;gap:5px;z-index:2;flex-wrap:wrap;padding:0 10px} .br-dot{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.55);box-shadow:0 0 2px rgba(0,0,0,.4);transition:background .2s,transform .2s} .br-dot.on{background:#fff;transform:scale(1.35)} .br-zoom{position:absolute;bottom:10px;right:10px;background:rgba(0,0,0,.45);color:#fff;border-radius:50%;width:32px;height:32px;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s;z-index:2} .br-card:hover .br-zoom{opacity:1} .br-meta{padding:13px 15px 15px} .br-tag{display:inline-block;font-size:11px;font-weight:500;padding:3px 10px;border-radius:4px;margin-bottom:7px} .br-tag-aug{background:#fce8f3;color:#9b1a6a} .br-tag-pexy{background:#e8f0fb;color:#1a4fa0} .br-tag-augpexy{background:#f0e8fb;color:#5b1aa0} .br-tag-reduction{background:#e6f4ea;color:#1a6e38} .br-tag-revision{background:#fef3e2;color:#b45309} .br-card h3{font-size:14px;font-weight:500;color:#111;margin:0 0 4px;line-height:1.35} .br-card p{font-size:12px;color:#666;line-height:1.55;margin:0} .br-disc{text-align:center;font-size:11px;color:#aaa;padding:24px 0 0;max-width:640px;margin:0 auto;line-height:1.6} .br-modal{display:none;position:fixed;inset:0;z-index:99999;align-items:center;justify-content:center} .br-modal.open{display:flex} .br-overlay{position:absolute;inset:0;background:rgba(0,0,0,.9)} .br-modal-inner{position:relative;z-index:1;max-width:94vw;max-height:92vh;display:flex;flex-direction:column;align-items:center} .br-modal-stage{max-width:94vw;display:flex;align-items:center;justify-content:center} .br-modal-img{max-width:100%;max-height:78vh;border-radius:8px;display:block;object-fit:contain} .br-mframe{width:min(94vw,1100px);height:min(78vh,760px);max-width:94vw;background-repeat:no-repeat;background-color:#111;border-radius:8px} .br-modal-meta{margin-top:14px;text-align:center;color:#fff} .br-modal-meta strong{font-size:15px;display:block;margin-bottom:4px} .br-modal-meta span{font-size:13px;color:rgba(255,255,255,.65)} .br-modal-fcount{margin-top:8px;font-size:12px;color:rgba(255,255,255,.6)} .br-modal-close{position:absolute;top:-14px;right:-14px;width:36px;height:36px;border-radius:50%;background:#fff;border:none;cursor:pointer;font-size:18px;display:flex;align-items:center;justify-content:center;color:#111;box-shadow:0 2px 8px rgba(0,0,0,.3);z-index:3} .br-modal-prev,.br-modal-next{position:fixed;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:none;color:#fff;font-size:22px;width:44px;height:44px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s;z-index:2} .br-modal-prev{left:16px} .br-modal-next{right:16px} .br-modal-prev:hover,.br-modal-next:hover{background:rgba(255,255,255,.3)} @media (hover:none){ .br-strip-arrow,.br-zoom{opacity:1} } @media (max-width:575.98px){ .br-wrap{padding:28px 12px 38px} .br-img-wrap,.br-strip-wrap{height:230px} .br-modal-prev,.br-modal-next{width:38px;height:38px;font-size:18px} .br-modal-prev{left:6px} .br-modal-next{right:6px} .br-modal-meta{padding:0 24px} } All casesAugmentationAug + mastopexyMastopexyRevision / removalReductionReal patient results. Individual outcomes vary. All procedures performed by board-certified plastic surgeons. ←×→ const BASE="https://storage.googleapis.com/treatspace-prod-media/pracimg/u-3304/"; /* Montage split layouts (measured). Cases with an imgs[] array below are made of separate files and become a strip of those files instead. NOTE: any case that resolves to 2 or fewer views is now rendered as a single whole image (see viewsFor). Leaving 2-frame GRID entries in the map is harmless — viewsFor short-circuits them. */ const INSET=0.02; const GRID={ "Slide1_3xXeGcL.webp":{c:2,r:1},"Slide2_dhKGY8M.webp":{c:2,r:1},"Slide3-3.webp":{c:3,r:1}, "Slide4-3.webp":{c:2,r:1},"Slide5-3.webp":{c:2,r:3},"Slide6-3.webp":{c:2,r:3}, "Slide7-3.webp":{c:2,r:1},"Slide8-3.webp":{c:1,r:2},"Slide9-3.webp":{c:2,r:1}, "Slide10-3.webp":{c:2,r:1},"Slide11-3.webp":{c:2,r:1},"Slide12-3.webp":{c:2,r:1}, "Slide13-3.webp":{c:2,r:1},"Slide14-3.webp":{c:2,r:1},"Slide15-3.webp":{c:2,r:1}, "Slide16-3.webp":{c:2,r:1},"Slide17-3.webp":{c:2,r:1},"Slide18-3.webp":{c:2,r:3}, "Slide19-3.webp":{c:2,r:3},"Slide20-3.webp":{c:1,r:2},"Slide21-3.webp":{c:2,r:3}, "Slide22-2.webp":{c:2,r:1},"Slide23-2.webp":{c:2,r:1},"Slide24-2.webp":{c:2,r:3}, "Slide25.webp":{c:2,r:1},"Slide26.webp":{c:2,r:2},"Slide27.webp":{c:2,r:3}, "Slide28.webp":{c:2,r:3},"Slide29.webp":{c:2,r:3},"Slide30.webp":{c:2,r:3}, "Slide31.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-12-570x190.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-17-570x190.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-18-570x190.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-24-570x190.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-29-570x190.webp":{c:2,r:1}, "patient-2741-breast-correction-before-after-30-570x190.webp":{c:2,r:1}, "patient-2855-breast-reduction-before-after-11-570x190.webp":{c:2,r:1}, "patient-2855-breast-reduction-before-after-2.webp":{c:2,r:1}, "patient-2855-breast-reduction-before-after-13-570x190.webp":{c:2,r:1}, "patient-2876-breast-reduction-before-after.webp":{c:2,r:1}, "patient-2869-breast-reduction-before-after.webp":{c:2,r:1}, "patient-2855-breast-reduction-before-after-6-570x170.webp":{c:2,r:1} }; const CASES=[ {img:"Slide1_3xXeGcL.webp",cat:"Augmentation",title:"Breast augmentation",detail:"Mentor Xtra 325cc, IMF incision, age 33."}, {img:"Slide2_dhKGY8M.webp",cat:"Augmentation",title:"Breast augmentation",detail:"275cc Mentor Memory Gel, IMF incision, age 40."}, {img:"Slide3-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"250cc Mentor Memory Gel, CVR mastopexy incision, age 28."}, {img:"Slide4-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"275cc Mentor Memory Gel, CVR mastopexy incision, age 31."}, {img:"Slide5-3.webp",cat:"Revision",title:"Implant removal + fat transfer",detail:"Implant removal with fat transfer, periareolar mastopexy incision, age 38."}, {img:"Slide6-3.webp",cat:"Mastopexy",title:"Mastopexy symmetry procedure",detail:"CVR mastopexy for symmetry correction, no implants, age 20."}, {img:"Slide7-3.webp",cat:"Mastopexy",title:"Mastopexy + small reduction",detail:"CVR mastopexy with minor breast reduction, no implants, age 30."}, {img:"Slide8-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"320cc Mentor Moderate Plus, IMF raising CVR mastopexy, age 34."}, {img:"Slide9-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"300cc Mentor Moderate Plus Memory Gel, IMF incision, age 27."}, {img:"Slide10-3.webp",cat:"Revision",title:"Implant exchange",detail:"Exchange to 475cc Mentor Moderate Plus, IMF incision, age 32."}, {img:"Slide11-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"425cc Mentor Memory Gel Moderate Plus, transaxillary incision, age 42."}, {img:"Slide12-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"375cc Mentor Moderate Plus, IMF incision, age 33."}, {img:"Slide13-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"300cc Mentor Moderate Plus, IMF incision, age 42."}, {img:"Slide14-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"300cc Mentor Memory Gel Moderate Plus, periareolar mastopexy, age 43."}, {img:"Slide15-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"325cc Saline Moderate Plus, IMF incision, age 36."}, {img:"Slide16-3.webp",cat:"Augmentation",title:"Augmentation — upper pole fullness",detail:"200cc Mentor Boost, transaxillary incision, age 36."}, {img:"Slide17-3.webp",cat:"Augmentation",title:"Augmentation — body builder",detail:"Motiva Ergo Mini 310cc, subglandular placement, age 32."}, {img:"Slide18-3.webp",cat:"Augmentation",title:"Breast augmentation",detail:"325cc Mentor Moderate Plus Memory Gel, IMF incision, age 39."}, {img:"Slide19-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"350cc Mentor Moderate Plus, CVR mastopexy incision, age 38."}, {img:"Slide20-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"250cc Mentor Moderate Plus Memory Gel, CVR mastopexy, age 36."}, {img:"Slide21-3.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"300cc Mentor Moderate Plus Memory Gel, CVR mastopexy, submuscular, age 52."}, {img:"Slide22-2.webp",cat:"Aug + Mastopexy",title:"Augmentation + periareolar mastopexy",detail:"325cc Mentor Moderate Plus Memory Gel, submuscular, age 33."}, {img:"Slide23-2.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"225cc Mentor Moderate Plus Memory Gel, CVR mastopexy, age 38."}, {img:"Slide24-2.webp",cat:"Aug + Mastopexy",title:"Augmentation + periareolar mastopexy + lipo",detail:"375cc Mentor Moderate Plus, BAM submuscular, periareolar mastopexy with abdominal lipo, age 29."}, {img:"Slide25.webp",cat:"Augmentation",title:"Breast augmentation",detail:"350cc Mentor Moderate Plus, BAM transaxillary incision, age 22."}, {img:"Slide26.webp",cat:"Augmentation",title:"Breast augmentation — saline",detail:"Saline implants via IMF incision. First saline case in practice."}, {img:"Slide27.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"CVR mastopexy with augmentation, Mentor Moderate Plus Memory Gel, submuscular, age 30."}, {img:"Slide28.webp",cat:"Aug + Mastopexy",title:"Augmentation + mastopexy",detail:"275cc Mentor Moderate Plus, CVR submuscular mastopexy, age 42."}, {img:"Slide29.webp",cat:"Revision",title:"Revision augmentation + mastopexy",detail:"275cc Mentor Moderate Plus Memory Gel, CVR mastopexy revision, submuscular, age 33."}, {img:"Slide30.webp",cat:"Augmentation",title:"Augmentation — upper pole fullness",detail:"200cc Mentor Moderate Plus, submuscular, with abdominal lipo, age 37."}, {img:"Slide31.webp",cat:"Augmentation",title:"Breast augmentation",detail:"IMF incision, natural result with improved projection and symmetry."}, {img:"Screenshot_2026-06-22_113849.webp",cat:"Augmentation",title:"Breast augmentation",detail:"275cc Mentor Memory Gel, IMF incision, submuscular, age 40.",imgs:["Screenshot_2026-06-22_113849.webp","Screenshot_2026-06-22_113901.webp","Screenshot_2026-06-22_113910.webp","Screenshot_2026-06-22_113917.webp","Screenshot_2026-06-22_113926.webp"]}, {img:"Transaxillary_Breast_Augmentation_2_Page_1.webp",cat:"Augmentation",title:"Breast augmentation — transaxillary",detail:"300cc Mentor Memory Gel Moderate Plus, transaxillary incision, submuscular, age 27.",imgs:["Transaxillary_Breast_Augmentation_2_Page_1.webp","Transaxillary_Breast_Augmentation_2_Page_2.webp","Transaxillary_Breast_Augmentation_2_Page_3.webp","Transaxillary_Breast_Augmentation_2_Page_4.webp","Transaxillary_Breast_Augmentation_2_Page_5.webp"]}, {img:"patient-2741-breast-correction-before-after-12-570x190.webp",cat:"Revision",title:"Revision augmentation — tuberous correction",detail:"Implant exchange with tuberous breast correction, improved symmetry and shape, IMF incision."}, {img:"patient-2741-breast-correction-before-after-17-570x190.webp",cat:"Revision",title:"Revision augmentation — implant exchange",detail:"Implant exchange for bottoming out and malposition correction, IMF incision."}, {img:"patient-2741-breast-correction-before-after-18-570x190.webp",cat:"Revision",title:"Revision augmentation + mastopexy",detail:"Implant exchange with CVR mastopexy for ptosis and asymmetry correction."}, {img:"patient-2741-breast-correction-before-after-24-570x190.webp",cat:"Revision",title:"Revision augmentation — asymmetry correction",detail:"Implant exchange with pocket revision for asymmetry and mild ptosis correction, IMF incision."}, {img:"patient-2741-breast-correction-before-after-29-570x190.webp",cat:"Revision",title:"Revision augmentation + periareolar mastopexy",detail:"Implant revision with periareolar mastopexy for shape and areolar symmetry correction."}, {img:"patient-2741-breast-correction-before-after-30-570x190.webp",cat:"Revision",title:"Revision — scar revision + implant correction",detail:"Hypertrophic periareolar scar revision with implant pocket correction, improved contour and symmetry."}, {img:"patient-2855-breast-reduction-before-after-11-570x190.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral breast reduction with mastopexy, improved symmetry and relief of macromastia symptoms."}, {img:"patient-2855-breast-reduction-before-after-2.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral reduction mammaplasty, anchor incision, significant volume reduction with improved shape."}, {img:"patient-2855-breast-reduction-before-after-13-570x190.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral breast reduction, improved contour and nipple position, anchor incision."}, {img:"patient-2876-breast-reduction-before-after.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral reduction mammaplasty with mastopexy, improved symmetry and upper pole contour."}, {img:"patient-2869-breast-reduction-before-after.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral breast reduction, anchor incision, significant volume reduction and lift."}, {img:"patient-2855-breast-reduction-before-after-6-570x170.webp",cat:"Reduction",title:"Breast reduction",detail:"Bilateral reduction mammaplasty, improved shape and symmetry, relief of macromastia."} ]; const TAG={"Augmentation":"br-tag-aug","Aug + Mastopexy":"br-tag-augpexy","Mastopexy":"br-tag-pexy","Revision":"br-tag-revision","Reduction":"br-tag-reduction"}; const ZOOM_SVG=''; let active="All",filtered=[],modalIdx=0,modalViews=null,modalViewIdx=0,modalNat=null; /* Hide every case that would generate a multi-image scrolling strip. */ function hasMultipleViews(c){ if(c.imgs && c.imgs.length>1) return true; const g=GRID[c.img]; if(!g) return false; if(g.frames) return g.frames.length>2; if(g.cols && g.rows) return (g.cols.length*g.rows.length)>2; if(g.c && g.r) return (g.c*g.r)>2; return false; } const VISIBLE_CASES=CASES.filter(function(c){ return !hasMultipleViews(c); }); function win(x,y,w,h){ return {x:x,y:y,w:w,h:h,sizeX:100/w,sizeY:100/h,posX:w>=1?0:(x/(1-w))*100,posY:h>=1?0:(y/(1-h))*100}; } const BR_TRIM_CACHE={}; /* Returns a case's views (>1 = a strip), or null for a single image. imgs[] => separate files ; GRID => slices of one montage. Any case that resolves to 2 or fewer views is collapsed to a single image. */ function viewsFor(c){ let out=null; if(c.imgs && c.imgs.length>1){ out=c.imgs.map(function(src){return {file:src};}); } else { if(BR_TRIM_CACHE[c.img]){ return BR_TRIM_CACHE[c.img].map(function(f){return {slice:f};}); } const g=GRID[c.img]; if(!g) return null; out=[]; if(g.frames){ g.frames.forEach(function(f){ out.push({slice:win(f[0],f[1],f[2],f[3])}); }); } else if(g.cols&&g.rows;){ g.rows.forEach(function(ry){ g.cols.forEach(function(cx){ out.push({slice:win(cx[0],ry[0],cx[1]-cx[0],ry[1]-ry[0])}); }); }); } else { for(let row=0;row225&&g;>225&&b;>225; const paleNeutral=max-min<12&&r;>210&&g;>210&&b;>210; const blank=a<12||nearWhite||paleNeutral; if(!blank){ if(xxmaxX)maxX=xx; if(yymaxY)maxY=yy; } } } if(maxX<0)return f; /* Small padding prevents overly tight crops around the body. */ const padX=Math.max(step*2,Math.round(W*0.025)); const padY=Math.max(step*2,Math.round(H*0.025)); minX=Math.max(0,minX-padX); minY=Math.max(0,minY-padY); maxX=Math.min(W-1,maxX+padX); maxY=Math.min(H-1,maxY+padY); return win( (X+minX)/NW, (Y+minY)/NH, (maxX-minX+1)/NW, (maxY-minY+1)/NH ); } function analyzeBreastSlices(scroll,c,nominalViews){ if(BR_TRIM_CACHE[c.img])return; const direct=BASE+c.img; const proxy="https://wsrv.nl/?url="+encodeURIComponent( direct.replace(/^https?:\/\//,"") ); const sources=[direct,proxy]; (function trySource(idx){ if(idx>=sources.length)return; const im=new Image(); im.crossOrigin="anonymous"; im.onload=function(){ let ctx; try{ const canvas=document.createElement("canvas"); canvas.width=im.naturalWidth; canvas.height=im.naturalHeight; ctx=canvas.getContext("2d",{willReadFrequently:true}); ctx.drawImage(im,0,0); }catch(e){ trySource(idx+1); return; } const trimmed=[]; for(let i=0;ic.cat===active); const cnt=document.getElementById("br-count"); if(cnt)cnt.textContent="Showing "+filtered.length+" case"+(filtered.length!==1?"s":""); const grid=document.getElementById("br-grid"); if(!grid)return; grid.innerHTML=""; BR_STRIPS=[]; filtered.forEach(function(c,i){ const col=document.createElement("div"); col.className="col-12 col-sm-6 col-lg-4"; const card=document.createElement("div"); card.className="br-card"; card.dataset.i=i; const views=null; /* multi-view cards are intentionally hidden */ if(views){ const wrap=document.createElement("div"); wrap.className="br-strip-wrap"; const scroll=document.createElement("div"); scroll.className="br-strip-scroll"; let hasSlice=false; views.forEach(function(v){ const fr=document.createElement("div"); fr.className="br-frame"; if(v.slice){ hasSlice=true; const inner=document.createElement("div"); inner.className="br-frame-inner"; inner.style.backgroundImage="url('"+BASE+c.img+"')"; inner.style.backgroundSize=v.slice.sizeX.toFixed(3)+"% "+v.slice.sizeY.toFixed(3)+"%"; inner.style.backgroundPosition=v.slice.posX.toFixed(3)+"% "+v.slice.posY.toFixed(3)+"%"; fr.appendChild(inner); } else { const img=document.createElement("img"); img.className="br-fimg"; img.loading="lazy"; img.src=BASE+v.file; img.alt=c.title; fr.appendChild(img); } scroll.appendChild(fr); }); wrap.appendChild(scroll); BR_STRIPS.push({scroll:scroll,views:views,img:c.img}); const pv=document.createElement("button"); pv.className="br-strip-arrow pv"; pv.innerHTML="‹"; const nx=document.createElement("button"); nx.className="br-strip-arrow nx"; nx.innerHTML="›"; const cc=document.createElement("div"); cc.className="br-strip-count"; cc.textContent="1 / "+views.length; const dots=document.createElement("div"); dots.className="br-dots"; views.forEach(function(_,di){const d=document.createElement("div"); d.className="br-dot"+(di===0?" on":""); dots.appendChild(d);}); wrap.appendChild(pv); wrap.appendChild(nx); wrap.appendChild(cc); wrap.appendChild(dots); const zoom=document.createElement("div"); zoom.className="br-zoom"; zoom.innerHTML=ZOOM_SVG; wrap.appendChild(zoom); card.appendChild(wrap); function cur(){var w=scroll.clientWidth;return w?Math.round(scroll.scrollLeft/w):0;} function update(){ const k=cur(); cc.textContent=(k+1)+" / "+views.length; dots.querySelectorAll(".br-dot").forEach(function(d,di){d.classList.toggle("on",di===k);}); pv.disabled=k<=0; nx.disabled=k>=views.length-1; } scroll.addEventListener("scroll",function(){window.requestAnimationFrame(update);}); pv.addEventListener("click",function(e){e.stopPropagation();scroll.scrollBy({left:-scroll.clientWidth,behavior:"smooth"});}); nx.addEventListener("click",function(e){e.stopPropagation();scroll.scrollBy({left:scroll.clientWidth,behavior:"smooth"});}); zoom.addEventListener("click",function(e){e.stopPropagation();openModal(i,cur());}); let sx=0,moved=false; scroll.addEventListener("pointerdown",function(e){sx=e.clientX;moved=false;}); scroll.addEventListener("pointermove",function(e){if(Math.abs(e.clientX-sx)>6)moved=true;}); scroll.addEventListener("click",function(){if(!moved)openModal(i,cur());}); requestAnimationFrame(update); if(hasSlice) coverSlices(scroll,c,views,update); } else { const wrap=document.createElement("div"); wrap.className="br-img-wrap"; const img=document.createElement("img"); img.className="br-img"; img.loading="lazy"; img.src=BASE+c.img; img.alt=c.title; const zoom=document.createElement("div"); zoom.className="br-zoom"; zoom.innerHTML=ZOOM_SVG; wrap.appendChild(img); wrap.appendChild(zoom); card.appendChild(wrap); card.addEventListener("click",function(){openModal(i,0);}); } const meta=document.createElement("div"); meta.className="br-meta"; meta.innerHTML=''+c.cat+''+c.title+''+c.detail+''; card.appendChild(meta); col.appendChild(card); grid.appendChild(col); }); } function openModal(i,viewIdx){ modalIdx=i; const c=filtered[i]; const stage=document.getElementById("br-modal-stage"); document.getElementById("br-modal-title").textContent=c.title; document.getElementById("br-modal-detail").textContent=c.detail; stage.innerHTML=""; modalNat=null; modalViews=viewsFor(c); modalViewIdx=viewIdx||0; if(modalViews){ if(modalViewIdx>=modalViews.length)modalViewIdx=modalViews.length-1; const usesSlice=!!modalViews[0].slice; if(usesSlice){ const box=document.createElement("div"); box.className="br-mframe"; box.style.backgroundImage="url('"+BASE+c.img+"')"; stage.appendChild(box); const im=new Image(); im.onload=function(){ modalNat={w:im.naturalWidth,h:im.naturalHeight}; showModalView(); }; im.src=BASE+c.img; } else { const img=document.createElement("img"); img.className="br-modal-img"; stage.appendChild(img); } showModalView(); } else { const img=document.createElement("img"); img.className="br-modal-img"; img.src=BASE+c.img; img.alt=c.title; stage.appendChild(img); document.getElementById("br-modal-fcount").textContent=""; } document.getElementById("br-modal").classList.add("open"); document.body.style.overflow="hidden"; } function showModalView(){ if(!modalViews)return; const n=modalViews.length; modalViewIdx=(modalViewIdx+n)%n; const v=modalViews[modalViewIdx]; if(v.slice){ const box=document.querySelector("#br-modal-stage .br-mframe"); if(!box)return; const f=v.slice; if(modalNat){ const maxW=Math.min(window.innerWidth*0.94,1100); const maxH=Math.min(window.innerHeight*0.78,760); const cropAspect=(f.w*modalNat.w)/(f.h*modalNat.h); let BW=maxW, BH=BW/cropAspect; if(BH>maxH){BH=maxH;BW=BH*cropAspect;} box.style.width=Math.max(280,BW).toFixed(1)+"px"; box.style.height=Math.max(260,BH).toFixed(1)+"px"; requestAnimationFrame(function(){ const liveW=box.clientWidth||BW; const liveH=box.clientHeight||BH; const scale=Math.max(liveW/(f.w*modalNat.w),liveH/(f.h*modalNat.h)); const bgW=scale*modalNat.w, bgH=scale*modalNat.h; const posX=liveW/2-(f.x+f.w/2)*bgW; const posY=liveH/2-(f.y+f.h/2)*bgH; box.style.backgroundSize=bgW.toFixed(1)+"px "+bgH.toFixed(1)+"px"; box.style.backgroundPosition=posX.toFixed(1)+"px "+posY.toFixed(1)+"px"; }); } } else { const img=document.querySelector("#br-modal-stage .br-modal-img"); if(img){ img.src=BASE+v.file; img.alt=document.getElementById("br-modal-title").textContent||"Patient result"; } } document.getElementById("br-modal-fcount").textContent="View "+(modalViewIdx+1)+" of "+n; } function closeModal(){ document.getElementById("br-modal").classList.remove("open"); document.body.style.overflow=""; modalViews=null; modalNat=null; } function step(dir){ if(modalViews){ const next=modalViewIdx+dir; if(next>=0 && next