@mochabug/adapt-web 1.0.1-rc.15 → 1.0.1-rc.17

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.
@@ -1 +1 @@
1
- import{SVG_POPOUT,SVG_WINDOW}from"./panel-setup.js";let iframeDragDepth=0;function disableIframePointEvents(){return iframeDragDepth++,document.documentElement.classList.add("mb-dragging"),{release(){--iframeDragDepth<=0&&(iframeDragDepth=0,document.documentElement.classList.remove("mb-dragging"))}}}class Panel{constructor(id,element,title){this.group=null;this.id=id,this.element=element,this.title=title||id,this.wrapper=document.createElement("div"),this.wrapper.className="mb-panel",this.wrapper.dataset.panelId=id,this.wrapper.dataset.active="false",this.wrapper.appendChild(element)}}let groupIdCounter=0;class PanelGroup{constructor(id){this._panels=[];this._activePanel=null;this._headerHidden=!1;this._locked=!1;this._onTabClose=null;this._onTabPointerDown=null;this._onTabPopOut=null;this._location="grid";this._onLocationChangedCb=null;this._isInFloatingSplit=!1;this._onSplitStateChangedCb=null;this._dragConstraint="any";this._dockingBlocked=!1;this._dialogDockingBlocked=!1;this._onPanelCountChangedCb=null;this._onActivePanelChangedCb=null;this.id=id||`group-${++groupIdCounter}`,this.element=document.createElement("div"),this.element.className="mb-group",this.element.dataset.groupId=this.id,this.headerElement=document.createElement("div"),this.headerElement.className="mb-group-header",this.headerPrefix=document.createElement("div"),this.headerPrefix.className="mb-group-header-prefix",this.tabsElement=document.createElement("div"),this.tabsElement.className="mb-group-tabs",this.headerVoid=document.createElement("div"),this.headerVoid.className="mb-group-header-void",this.headerActions=document.createElement("div"),this.headerActions.className="mb-group-header-actions",this.headerElement.appendChild(this.headerPrefix),this.headerElement.appendChild(this.tabsElement),this.headerElement.appendChild(this.headerVoid),this.headerElement.appendChild(this.headerActions),this.contentElement=document.createElement("div"),this.contentElement.className="mb-group-content",this.element.appendChild(this.headerElement),this.element.appendChild(this.contentElement)}get panels(){return this._panels}get activePanel(){return this._activePanel}get size(){return this._panels.length}get locked(){return this._locked}set locked(value){this._locked=value}setHeaderHidden(hidden){this._headerHidden=hidden,this.headerElement.style.display=hidden?"none":""}get headerHidden(){return this._headerHidden}setHeaderActions(element){this.headerActions.innerHTML="",this.headerActions.appendChild(element)}setHeaderPrefix(element){this.headerPrefix.innerHTML="",this.headerPrefix.appendChild(element)}onTabClose(cb){this._onTabClose=cb}onTabPointerDown(cb){this._onTabPointerDown=cb}get location(){return this._location}set location(value){this._location!==value&&(this._location=value,this._onLocationChangedCb?.(value))}onLocationChanged(cb){this._onLocationChangedCb=cb}fireLocationChanged(){this._onLocationChangedCb?.(this._location)}get isInFloatingSplit(){return this._isInFloatingSplit}set isInFloatingSplit(value){this._isInFloatingSplit!==value&&(this._isInFloatingSplit=value,this._onSplitStateChangedCb?.(value))}onSplitStateChanged(cb){this._onSplitStateChangedCb=cb}onTabPopOut(cb){this._onTabPopOut=cb}get dragConstraint(){return this._dragConstraint}set dragConstraint(v){this._dragConstraint=v}get dockingBlocked(){return this._dockingBlocked}set dockingBlocked(v){this._dockingBlocked=v}get dialogDockingBlocked(){return this._dialogDockingBlocked}set dialogDockingBlocked(v){this._dialogDockingBlocked=v}onPanelCountChanged(cb){this._onPanelCountChangedCb=cb}onActivePanelChanged(cb){this._onActivePanelChangedCb=cb}addPanel(panel){if(this._panels.some(p=>p.id===panel.id))return;panel.group=this,this._panels.push(panel),this.contentElement.appendChild(panel.wrapper);const tab=this.createTab(panel);this.tabsElement.appendChild(tab),this.activatePanel(panel.id),this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length)}removePanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),panel.wrapper.remove(),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}detachPanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}activatePanel(panelId){const panel=this._panels.find(p=>p.id===panelId);if(!panel)return;this._activePanel=panel;for(const p of this._panels)p.wrapper.dataset.active=p===panel?"true":"false";const tabs=this.tabsElement.querySelectorAll(".mb-tab");for(const tab of tabs){const isActive=tab.dataset.tabId===panelId;tab.dataset.active=isActive?"true":"false"}this._onActivePanelChangedCb?.(panelId)}reorderPanel(panelId,dropX){const panelIdx=this._panels.findIndex(p=>p.id===panelId);if(panelIdx===-1)return;const panel=this._panels[panelIdx],tabs=Array.from(this.tabsElement.querySelectorAll(".mb-tab"));let targetIdx=this._panels.length;for(let i=0;i<tabs.length;i++){const rect=tabs[i].getBoundingClientRect();if(dropX<rect.left+rect.width/2){targetIdx=i;break}}if(targetIdx===panelIdx||targetIdx===panelIdx+1)return;this._panels.splice(panelIdx,1);const insertAt=panelIdx<targetIdx?targetIdx-1:targetIdx;this._panels.splice(insertAt,0,panel);const tabEl=this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`);if(tabEl){const refTab=this.tabsElement.querySelectorAll(".mb-tab")[insertAt];refTab&&refTab!==tabEl?this.tabsElement.insertBefore(tabEl,refTab):this.tabsElement.appendChild(tabEl)}}createTab(panel){const tab=document.createElement("div");tab.className="mb-tab",tab.dataset.tabId=panel.id,tab.dataset.active="false";const label=document.createElement("span");label.className="mb-tab-label",label.innerHTML=SVG_WINDOW,label.title=panel.title,tab.appendChild(label);const actions=document.createElement("div");actions.className="mb-tab-actions";const popOutBtn=document.createElement("button");popOutBtn.className="mb-tab-popout",popOutBtn.title="Pop out",popOutBtn.innerHTML=SVG_POPOUT,popOutBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabPopOut?.(panel.id)}),actions.appendChild(popOutBtn);const closeBtn=document.createElement("button");return closeBtn.className="mb-tab-close",closeBtn.title="Close",closeBtn.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="4" y1="4" x2="12" y2="12"/><line x1="12" y1="4" x2="4" y2="12"/></svg>',closeBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabClose?.(panel.id)}),actions.appendChild(closeBtn),tab.appendChild(actions),tab.addEventListener("pointerdown",e=>{e.target.closest(".mb-tab-close")||e.target.closest(".mb-tab-popout")||e.button===0&&(e.preventDefault(),this._onTabPointerDown?.(panel.id,e))}),tab}dispose(){this._panels=[],this._activePanel=null,this.element.remove()}}let zIndexCounter=1e5;class FloatingOverlay{constructor(group,opts,parentElement,insertBefore){this.internalLayout=null;this.toolbarElement=null;this.savedBounds=null;this._isMaximized=!1;this._onDragEnd=null;this._onDragMove=null;this.group=group,this.bounds={...opts},this.element=document.createElement("div"),this.element.className="mb-floating-overlay",this.element.dataset.groupId=group.id,this.applyBounds();const directions=["n","s","e","w","ne","nw","se","sw"];for(const dir of directions){const handle=document.createElement("div");handle.className=`mb-resize-handle mb-resize-${dir}`,handle.addEventListener("pointerdown",e=>this.onResizeStart(e,dir)),this.element.appendChild(handle)}this.element.addEventListener("pointerdown",()=>this.bringToFront(),!0),group.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),group.headerVoid.style.cursor="grab";const parent=parentElement??document.body;insertBefore?parent.insertBefore(this.element,insertBefore):parent.appendChild(this.element),this.element.appendChild(group.element),this.bringToFront()}get isMaximized(){return this._isMaximized}set onDragEnd(cb){this._onDragEnd=cb}set onDragMove(cb){this._onDragMove=cb}bringToFront(){zIndexCounter+=2,this.element.style.zIndex=String(zIndexCounter)}maximize(){this._isMaximized||(this.savedBounds={...this.bounds},this._isMaximized=!0,this.element.style.inset="0",this.element.style.width="auto",this.element.style.height="auto",this.element.classList.add("mb-floating-maximized"))}restore(){!this._isMaximized||!this.savedBounds||(this._isMaximized=!1,this.bounds={...this.savedBounds},this.savedBounds=null,this.element.classList.remove("mb-floating-maximized"),this.element.style.inset="",this.applyBounds())}hide(){this.element.style.display="none"}show(){this.element.style.display=""}dispose(){this.internalLayout&&(this.internalLayout.dispose(),this.internalLayout=null),this.removeToolbar(),this.element.remove()}getBounds(){return{...this.bounds}}setBounds(partial){if(this._isMaximized)return;const pad=10;partial.width!==void 0&&(this.bounds.width=Math.min(partial.width,window.innerWidth-this.bounds.x-pad)),partial.height!==void 0&&(this.bounds.height=Math.min(partial.height,window.innerHeight-this.bounds.y-pad)),this.applyBounds()}setFullBounds(bounds){if(this._isMaximized)return;const vw=window.innerWidth,vh=window.innerHeight,pad=10,minVisible=100;this.bounds={width:Math.max(minVisible,Math.min(bounds.width,vw-pad)),height:Math.max(minVisible,Math.min(bounds.height,vh-pad)),x:Math.max(0,Math.min(bounds.x,vw-minVisible)),y:Math.max(0,Math.min(bounds.y,vh-minVisible))},this.applyBounds()}applyBounds(){this.element.style.position="fixed",this.element.style.left=`${this.bounds.x}px`,this.element.style.top=`${this.bounds.y}px`,this.element.style.width=`${this.bounds.width}px`,this.element.style.height=`${this.bounds.height}px`}setDragGroup(newGroup){newGroup.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),newGroup.headerVoid.style.cursor="grab"}setToolbar(el){this.removeToolbar(),this.toolbarElement=el,this.getToolbarHost().headerActions.appendChild(el)}removeToolbar(){this.toolbarElement&&(this.toolbarElement.remove(),this.toolbarElement=null)}repositionToolbar(){this.toolbarElement&&this.getToolbarHost().headerActions.appendChild(this.toolbarElement)}getToolbarHost(){if(!this.internalLayout)return this.group;const root=this.internalLayout.getRoot();return root?FloatingOverlay.topRightGroup(root):this.group}static topRightGroup(node){return node.kind==="leaf"?node.group:node.direction==="horizontal"?FloatingOverlay.topRightGroup(node.second):FloatingOverlay.topRightGroup(node.first)}get hasToolbar(){return this.toolbarElement!==null}getAllGroups(){return this.internalLayout?.allGroups()??[this.group]}updateTotalTabCount(){const groups=this.getAllGroups();let total=0;for(const g of groups)total+=g.size;this.element.dataset.totalTabCount=String(total)}onDragStart(e){if(this._isMaximized)return;e.preventDefault();const handle=e.currentTarget,startX=e.clientX,startY=e.clientY,origLeft=this.bounds.x,origTop=this.bounds.y,iframes=disableIframePointEvents();handle.style.cursor="grabbing",handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;this.bounds.x=Math.max(0,Math.min(origLeft+dx,window.innerWidth-this.bounds.width)),this.bounds.y=Math.max(0,Math.min(origTop+dy,window.innerHeight-this.bounds.height)),this.applyBounds(),this._onDragMove?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)},onUp=()=>{iframes.release(),handle.style.cursor="grab",handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp),this._onDragEnd?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}onResizeStart(e,dir){if(this._isMaximized)return;e.preventDefault(),e.stopPropagation();const startX=e.clientX,startY=e.clientY,orig={...this.bounds},handle=e.currentTarget,minW=200,minH=100,iframes=disableIframePointEvents();handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;if(dir.includes("e")&&(this.bounds.width=Math.max(minW,orig.width+dx)),dir.includes("w")){const newW=Math.max(minW,orig.width-dx);this.bounds.x=orig.x+(orig.width-newW),this.bounds.width=newW}if(dir.includes("s")&&(this.bounds.height=Math.max(minH,orig.height+dy)),dir.includes("n")){const newH=Math.max(minH,orig.height-dy);this.bounds.y=orig.y+(orig.height-newH),this.bounds.height=newH}const pad=10;this.bounds.x=Math.max(0,this.bounds.x),this.bounds.y=Math.max(0,this.bounds.y),this.bounds.x+this.bounds.width>window.innerWidth-pad&&(this.bounds.width=window.innerWidth-this.bounds.x-pad),this.bounds.y+this.bounds.height>window.innerHeight-pad&&(this.bounds.height=window.innerHeight-this.bounds.y-pad),this.applyBounds()},onUp=()=>{iframes.release(),handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}}class SplitLayout{constructor(container){this.root=null;this.element=document.createElement("div"),this.element.className="mb-layout",container.appendChild(this.element)}getRoot(){return this.root}setMainGroup(group){const leaf=this.createLeaf(group);leaf.element.style.flex="1",this.root=leaf,this.element.appendChild(leaf.element)}splitGroup(targetGroup,newGroup,direction,newGroupSize){const splitDir=this.dockToSplitDirection(direction),leafNode=this.findGroupNode(targetGroup);if(!leafNode)return!1;const newLeafEl=document.createElement("div");newLeafEl.className="mb-split-leaf",newLeafEl.style.flex="1";const splitEl=document.createElement("div");splitEl.className=`mb-split-container ${splitDir==="horizontal"?"mb-split-horizontal":"mb-split-vertical"}`,splitEl.style.flex=leafNode.element.style.flex||"1",splitEl.style.minWidth="0",splitEl.style.minHeight="0";const separator=document.createElement("div"),isVerticalSplit=splitDir==="vertical";separator.className=`mb-layout-separator ${isVerticalSplit?"mb-layout-separator-h":"mb-layout-separator-v"}`;const existingFirst=direction==="right"||direction==="bottom";leafNode.element.parentElement.insertBefore(splitEl,leafNode.element),existingFirst?(splitEl.appendChild(leafNode.element),splitEl.appendChild(separator),splitEl.appendChild(newLeafEl)):(splitEl.appendChild(newLeafEl),splitEl.appendChild(separator),splitEl.appendChild(leafNode.element)),newLeafEl.appendChild(newGroup.element),newGroupSize!==void 0&&newGroupSize>0?existingFirst?(leafNode.element.style.flex="1",newLeafEl.style.flex=`0 0 ${newGroupSize}px`):(newLeafEl.style.flex=`0 0 ${newGroupSize}px`,leafNode.element.style.flex="1"):(leafNode.element.style.flex="1",newLeafEl.style.flex="1");const newLeaf={kind:"leaf",group:newGroup,element:newLeafEl},splitNode={kind:"split",direction:splitDir,first:existingFirst?leafNode:newLeaf,second:existingFirst?newLeaf:leafNode,element:splitEl,separator};return separator.addEventListener("pointerdown",e=>this.onSeparatorDrag(e,splitNode)),this.replaceNodeInTree(leafNode,splitNode),leafNode.element.style.display==="none"&&(separator.style.display="none",newLeafEl.dataset.savedFlex=newLeafEl.style.flex,newLeafEl.style.flex="1",leafNode.element.dataset.savedFlex=leafNode.element.style.flex),!0}removeGroup(group){const leafNode=this.findGroupNode(group);if(!leafNode)return;if(this.root===leafNode){leafNode.element.remove(),this.root=null;return}this.restoreMaximizedLeaf(group);const parentSplit=this.findParentSplit(leafNode);if(!parentSplit)return;const sibling=parentSplit.first===leafNode?parentSplit.second:parentSplit.first;this.restoreMaximizedSubtree(sibling),sibling.element.style.flex=parentSplit.element.style.flex||"1",parentSplit.element.parentElement.insertBefore(sibling.element,parentSplit.element),leafNode.element.remove(),parentSplit.separator.remove(),parentSplit.element.remove(),this.replaceNodeInTree(parentSplit,sibling)}findGroupNode(group){return this.findGroupNodeIn(this.root,group)}getGroupPosition(group){const leaf=this.findGroupNode(group);if(!leaf)return null;const parent=this.findParentSplit(leaf);if(!parent)return null;const isFirst=parent.first===leaf,siblingNode=isFirst?parent.second:parent.first,siblingGroup=this.firstGroupIn(siblingNode);if(!siblingGroup)return null;let direction;return parent.direction==="horizontal"?direction=isFirst?"left":"right":direction=isFirst?"top":"bottom",{siblingGroup,direction}}firstGroupIn(node){return node.kind==="leaf"?node.group:this.firstGroupIn(node.first)}collapseLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;const parent=this.findParentSplit(leaf);if(parent){const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex=sibling.element.style.flex,sibling.element.style.flex="1",parent.separator.style.display="none"}leaf.element.dataset.savedFlex=leaf.element.style.flex,leaf.element.style.display="none"}expandLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;leaf.element.style.display="",leaf.element.dataset.savedFlex!==void 0&&(leaf.element.style.flex=leaf.element.dataset.savedFlex,delete leaf.element.dataset.savedFlex);const parent=this.findParentSplit(leaf);if(parent){parent.separator.style.display="";const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex!==void 0&&(sibling.element.style.flex=sibling.element.dataset.savedFlex,delete sibling.element.dataset.savedFlex)}}maximizeLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay===void 0&&(sibling.element.dataset.maxSavedDisplay=sibling.element.style.display),sibling.element.style.display="none",parent.separator.dataset.maxSavedDisplay===void 0&&(parent.separator.dataset.maxSavedDisplay=parent.separator.style.display),parent.separator.style.display="none",current.element.dataset.maxSavedFlex===void 0&&(current.element.dataset.maxSavedFlex=current.element.style.flex),current.element.style.flex="1",current=parent,parent=this.findParentSplit(current)}}restoreMaximizedLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay!==void 0&&(sibling.element.style.display=sibling.element.dataset.maxSavedDisplay,delete sibling.element.dataset.maxSavedDisplay),parent.separator.dataset.maxSavedDisplay!==void 0&&(parent.separator.style.display=parent.separator.dataset.maxSavedDisplay,delete parent.separator.dataset.maxSavedDisplay),current.element.dataset.maxSavedFlex!==void 0&&(current.element.style.flex=current.element.dataset.maxSavedFlex,delete current.element.dataset.maxSavedFlex),current=parent,parent=this.findParentSplit(current)}}restoreMaximizedSubtree(node){node.element.dataset.maxSavedDisplay!==void 0&&(node.element.style.display=node.element.dataset.maxSavedDisplay,delete node.element.dataset.maxSavedDisplay),node.element.dataset.maxSavedFlex!==void 0&&(node.element.style.flex=node.element.dataset.maxSavedFlex,delete node.element.dataset.maxSavedFlex),node.kind==="split"&&(node.separator.dataset.maxSavedDisplay!==void 0&&(node.separator.style.display=node.separator.dataset.maxSavedDisplay,delete node.separator.dataset.maxSavedDisplay),this.restoreMaximizedSubtree(node.first),this.restoreMaximizedSubtree(node.second))}allGroups(){const result=[];return this.collectGroups(this.root,result),result}toJSON(){return this.serializeNode(this.root)}restoreFlexFromSerialized(serialized){if(!serialized||!this.root)return;const flexMap=new Map;this.collectFlexValues(serialized,flexMap),this.applyFlexValues(this.root,flexMap)}animateTransition(){const cls=node=>{node&&(node.kind==="leaf"?node.element.classList.add("mb-split-leaf--animating"):(node.element.classList.add("mb-split-container--animating"),node.separator&&node.separator.classList.add("mb-layout-separator--animating"),cls(node.first),cls(node.second)))};cls(this.root);const cleanup=()=>{this.element.querySelectorAll(".mb-split-leaf--animating, .mb-split-container--animating, .mb-layout-separator--animating").forEach(el=>{el.classList.remove("mb-split-leaf--animating","mb-split-container--animating","mb-layout-separator--animating")})},timer=setTimeout(cleanup,350);this.element.addEventListener("transitionend",()=>{clearTimeout(timer),cleanup()},{once:!0})}dispose(){this.element.remove(),this.root=null}createLeaf(group){const leafEl=document.createElement("div");return leafEl.className="mb-split-leaf",leafEl.style.flex="1",leafEl.appendChild(group.element),{kind:"leaf",group,element:leafEl}}dockToSplitDirection(pos){return pos==="left"||pos==="right"?"horizontal":"vertical"}findGroupNodeIn(node,group){return node?node.kind==="leaf"?node.group===group?node:null:this.findGroupNodeIn(node.first,group)??this.findGroupNodeIn(node.second,group):null}collectGroups(node,result){node&&(node.kind==="leaf"?result.push(node.group):(this.collectGroups(node.first,result),this.collectGroups(node.second,result)))}findParentSplit(target){return this.findParentSplitIn(this.root,target)}findParentSplitIn(node,target){return!node||node.kind==="leaf"?null:node.first===target||node.second===target?node:this.findParentSplitIn(node.first,target)??this.findParentSplitIn(node.second,target)}replaceNodeInTree(oldNode,newNode){if(this.root===oldNode){this.root=newNode;return}const parent=this.findParentSplit(oldNode);parent&&(parent.first===oldNode?parent.first=newNode:parent.second=newNode)}collectFlexValues(node,map){node.kind==="leaf"?map.set(node.groupId,node.flex):(this.collectFlexValues(node.first,map),this.collectFlexValues(node.second,map))}applyFlexValues(node,map){if(node.kind==="leaf"){const saved=map.get(node.group.id);saved&&this.isValidFlex(saved)&&(node.element.style.flex=saved)}else this.applyFlexValues(node.first,map),this.applyFlexValues(node.second,map)}isValidFlex(value){if(value.includes("px"))return!0;const n=Number(value);return Number.isFinite(n)&&n>=0}serializeNode(node){return node?node.kind==="leaf"?{kind:"leaf",groupId:node.group.id,flex:node.element.style.flex||"1"}:{kind:"split",direction:node.direction,first:this.serializeNode(node.first),second:this.serializeNode(node.second),flex:node.element.style.flex||"1"}:null}onSeparatorDrag(e,splitNode){if(e.preventDefault(),splitNode.first.element.style.display==="none"||splitNode.second.element.style.display==="none")return;const isHorizontal=splitNode.direction==="horizontal",startPos=isHorizontal?e.clientX:e.clientY,firstEl=splitNode.first.element,secondEl=splitNode.second.element;this.lockDescendantSizes(splitNode.first,isHorizontal),this.lockDescendantSizes(splitNode.second,isHorizontal);const origFirstSize=isHorizontal?firstEl.offsetWidth:firstEl.offsetHeight,origSecondSize=isHorizontal?secondEl.offsetWidth:secondEl.offsetHeight,totalSize=origFirstSize+origSecondSize;if(totalSize<=0)return;const minSize=150,iframes=disableIframePointEvents();splitNode.separator.setPointerCapture(e.pointerId),splitNode.separator.classList.add("mb-layout-separator--active");const onMove=ev=>{if(firstEl.style.display==="none"||secondEl.style.display==="none"){splitNode.separator.releasePointerCapture(ev.pointerId),onUp();return}const delta=(isHorizontal?ev.clientX:ev.clientY)-startPos;let newFirst=origFirstSize+delta,newSecond=origSecondSize-delta;newFirst<minSize&&(newFirst=minSize,newSecond=totalSize-minSize),newSecond<minSize&&(newSecond=minSize,newFirst=totalSize-minSize),firstEl.style.flex=String(newFirst/totalSize),secondEl.style.flex=String(newSecond/totalSize)},onUp=()=>{iframes.release(),splitNode.separator.classList.remove("mb-layout-separator--active"),splitNode.separator.removeEventListener("pointermove",onMove),splitNode.separator.removeEventListener("pointerup",onUp),splitNode.separator.removeEventListener("pointercancel",onUp),this.unlockDescendantSizes(splitNode.first,isHorizontal),this.unlockDescendantSizes(splitNode.second,isHorizontal)};splitNode.separator.addEventListener("pointermove",onMove),splitNode.separator.addEventListener("pointerup",onUp),splitNode.separator.addEventListener("pointercancel",onUp)}lockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height;node.first.element.style.flex=`0 0 ${firstSize}px`,node.second.element.style.flex="1",this.lockDescendantSizes(node.first,isHorizontal),this.lockDescendantSizes(node.second,isHorizontal)}unlockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;this.unlockDescendantSizes(node.first,isHorizontal),this.unlockDescendantSizes(node.second,isHorizontal);const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height,secondSize=isHorizontal?node.second.element.getBoundingClientRect().width:node.second.element.getBoundingClientRect().height,total=firstSize+secondSize;total>0?(node.first.element.style.flex=String(firstSize/total),node.second.element.style.flex=String(secondSize/total)):(node.first.element.style.flex="0.5",node.second.element.style.flex="0.5")}}class PanelManager{constructor(opts){this.groups=new Map;this.panels=new Map;this.floatingOverlays=new Map;this.mainGroupId=null;this.onPanelRemovedCbs=[];this.onGroupCreatedByDragCb=null;this.disposed=!1;this.dragState=null;this.portals=new Map;this.portalRaf=0;this.mainGroupCollapsed=!1;this._beforeTabClose=null;this.container=opts.container,this.splitEdgeSize=opts.splitEdgeSize??100,this.layout=new SplitLayout(this.container),opts.onPanelRemoved&&this.onPanelRemovedCbs.push(opts.onPanelRemoved),this.onGroupCreatedByDragCb=opts.onGroupCreatedByDrag??null,this.dropOverlay=document.createElement("div"),this.dropOverlay.className="mb-drop-overlay",this.container.appendChild(this.dropOverlay),this.portalLayer=document.createElement("div"),this.portalLayer.className="mb-iframe-portal-layer",this.container.appendChild(this.portalLayer),this.syncPortals()}setBeforeTabClose(cb){this._beforeTabClose=cb}addPanel(opts){const panel=new Panel(opts.id,opts.element,opts.title);this.panels.set(opts.id,panel);const groupId=opts.groupId;if(groupId){const group=this.groups.get(groupId);group&&(group.addPanel(panel),this.registerPortal(panel.id,panel.element,panel.wrapper))}return panel}removePanel(panelId){const panel=this.panels.get(panelId);if(panel){if(this.unregisterPortal(panelId),panel.group){const group=panel.group;group.removePanel(panelId),group.size===0&&group.id!==this.mainGroupId&&this.removeGroup(group.id)}this.panels.delete(panelId);for(const cb of this.onPanelRemovedCbs)cb(panel)}}getPanel(panelId){return this.panels.get(panelId)}addGroup(opts){const group=new PanelGroup(opts?.id);if(this.groups.set(group.id,group),this.wireGroupCallbacks(group),opts?.floating)this.addFloatingGroup(group,opts.floating);else if(opts?.direction){const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,opts.direction,opts.initialSize)}return group}removeGroup(groupId){const group=this.groups.get(groupId);if(!group)return;for(const panel of[...group.panels])this.unregisterPortal(panel.id);const overlay=this.floatingOverlays.get(groupId);if(overlay)if(overlay.internalLayout){overlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):overlay.dispose()}else overlay.dispose(),this.floatingOverlays.delete(groupId);if(!overlay){const parentOverlay=this.findOverlayForGroup(group);parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay))}this.layout.findGroupNode(group)&&this.layout.removeGroup(group),group.isInFloatingSplit=!1,group.dispose(),this.groups.delete(groupId)}getGroup(groupId){return this.groups.get(groupId)}getMainGroup(){if(this.mainGroupId)return this.groups.get(this.mainGroupId)}setMainGroup(group){this.mainGroupId=group.id,this.layout.setMainGroup(group)}collapseMainGroup(){const main=this.getMainGroup();!main||this.mainGroupCollapsed||(this.layout.collapseLeaf(main),this.mainGroupCollapsed=!0)}expandMainGroup(){const main=this.getMainGroup();!main||!this.mainGroupCollapsed||(this.layout.expandLeaf(main),this.mainGroupCollapsed=!1)}isMainGroupCollapsed(){return this.mainGroupCollapsed}getDockedGroups(){return this.layout.allGroups()}collapseDockedGroup(group){this.layout.collapseLeaf(group)}expandDockedGroup(group){this.layout.expandLeaf(group)}maximizeDockedGroup(group){this.layout.maximizeLeaf(group)}restoreMaximizedDockedGroup(group){this.layout.restoreMaximizedLeaf(group)}restoreLayoutFlex(serialized){this.layout.restoreFlexFromSerialized(serialized)}addFloatingGroup(group,opts){const existingOverlay=this.floatingOverlays.get(group.id);existingOverlay&&this.floatingOverlays.delete(group.id);const parentOverlay=existingOverlay?null:this.findOverlayForGroup(group),overlay=new FloatingOverlay(group,opts,this.container,this.portalLayer);if(this.floatingOverlays.set(group.id,overlay),this.layout.findGroupNode(group)&&this.layout.removeGroup(group),existingOverlay?.internalLayout){existingOverlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(existingOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,existingOverlay):existingOverlay.dispose()}else existingOverlay?existingOverlay.dispose():parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));return group.isInFloatingSplit=!1,group.location="floating",overlay.updateTotalTabCount(),overlay}dockGroup(groupId,position,initialSize){const group=this.groups.get(groupId);if(!group||groupId===this.mainGroupId)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;const directOverlay=this.floatingOverlays.get(groupId),parentOverlay=directOverlay?null:this.findOverlayForGroup(group);if(this.layout.splitGroup(mainGroup,group,position,initialSize)){if(directOverlay)if(directOverlay.internalLayout){directOverlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(directOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,directOverlay):directOverlay.dispose()}else directOverlay.dispose(),this.floatingOverlays.delete(groupId);else parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));group.location="grid",group.isInFloatingSplit=!1}}getFloatingOverlay(groupId){return this.floatingOverlays.get(groupId)}dockOverlay(groupId){const overlay=this.floatingOverlays.get(groupId);if(!overlay)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;if(!overlay.internalLayout){this.dockGroup(groupId,"right");return}const allGroups=overlay.internalLayout.allGroups();if(allGroups.length===0)return;const first=allGroups[0];this.layout.splitGroup(mainGroup,first,"right"),first.location="grid",first.isInFloatingSplit=!1;for(let i=1;i<allGroups.length;i++){const g=allGroups[i];this.layout.splitGroup(first,g,"bottom"),g.location="grid",g.isInFloatingSplit=!1}overlay.internalLayout.dispose(),overlay.internalLayout=null,overlay.dispose(),this.floatingOverlays.delete(groupId)}findOverlayContaining(groupId){const group=this.groups.get(groupId);if(group)return this.findOverlayForGroup(group)??void 0}movePanel(panelId,targetGroupId){const panel=this.panels.get(panelId);if(!panel)return;const sourceGroup=panel.group;if(!sourceGroup||sourceGroup.id===targetGroupId)return;const targetGroup=this.groups.get(targetGroupId);targetGroup&&(sourceGroup.detachPanel(panelId),targetGroup.addPanel(panel),sourceGroup.size===0&&sourceGroup.id!==this.mainGroupId&&this.removeGroup(sourceGroup.id))}serializeLayout(){const floatingGroups=[];for(const[groupId,overlay]of this.floatingOverlays){const entry={groupId,bounds:overlay.getBounds(),internalLayout:overlay.internalLayout?.toJSON()??null};overlay.isMaximized&&(entry.isMaximized=!0),floatingGroups.push(entry)}const panelLocations={};for(const[panelId,panel]of this.panels)panel.group&&(panelLocations[panelId]=panel.group.id);return{mainLayout:this.layout.toJSON(),floatingGroups,panelLocations}}getFloatingOverlays(){return this.floatingOverlays}onDidRemovePanel(cb){return this.onPanelRemovedCbs.push(cb),{dispose:()=>{const idx=this.onPanelRemovedCbs.indexOf(cb);idx!==-1&&this.onPanelRemovedCbs.splice(idx,1)}}}dispose(){if(!this.disposed){this.disposed=!0,this.cancelTabDrag(),cancelAnimationFrame(this.portalRaf);for(const overlay of this.floatingOverlays.values())overlay.dispose();this.floatingOverlays.clear();for(const group of this.groups.values())group.dispose();this.groups.clear(),this.panels.clear(),this.onPanelRemovedCbs=[],this.dropOverlay.remove();for(const portal of this.portals.values())portal.entry.remove();this.portals.clear(),this.portalLayer.remove(),this.layout.dispose()}}wireGroupCallbacks(group){group.onTabClose(panelId=>{if(this._beforeTabClose){const result=this._beforeTabClose(panelId);result&&typeof result.then=="function"?result.then(allowed=>{allowed&&this.removePanel(panelId)}):result!==!1&&this.removePanel(panelId);return}this.removePanel(panelId)}),group.onTabPointerDown((panelId,e)=>{this.onTabPointerDown(panelId,group,e)}),group.onTabPopOut(panelId=>{this.detachPanelToFloating(panelId,window.innerWidth/2,window.innerHeight/2)})}onTabPointerDown(panelId,sourceGroup,e){if(this.dragState)return;this.dragState={panelId,sourceGroup,startX:e.clientX,startY:e.clientY,isDragging:!1,ghost:null,iframes:null,currentZone:null};const onMove=ev=>{if(!this.dragState)return;if(!this.dragState.isDragging){const dx=ev.clientX-this.dragState.startX,dy=ev.clientY-this.dragState.startY;if(dx*dx+dy*dy<25)return;this.dragState.isDragging=!0,this.dragState.iframes=disableIframePointEvents(),this.dragState.ghost=this.createDragGhost(panelId),this.container.appendChild(this.dragState.ghost)}this.dragState.ghost.style.left=`${ev.clientX+8}px`,this.dragState.ghost.style.top=`${ev.clientY+8}px`;let zone=this.hitTestDropZone(ev.clientX,ev.clientY);zone=this.applyDragConstraints(zone,this.dragState.sourceGroup),this.updateDropOverlay(zone)},onUp=ev=>{if(document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),!this.dragState)return;if(!this.dragState.isDragging){sourceGroup.activatePanel(panelId),this.dragState=null;return}this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null);const zone=this.applyDragConstraints(this.hitTestDropZone(ev.clientX,ev.clientY),sourceGroup);if(zone)switch(zone.kind){case"header":case"content-center":zone.group.id===sourceGroup.id?sourceGroup.reorderPanel(panelId,ev.clientX):this.movePanel(panelId,zone.group.id);break;case"content-split":this.dockTabFromDrag(panelId,zone.direction,zone.group);break}this.dragState=null},onCancel=()=>{document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),this.cancelTabDrag()};document.addEventListener("pointermove",onMove),document.addEventListener("pointerup",onUp),document.addEventListener("pointercancel",onCancel)}cancelTabDrag(){this.dragState&&(this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null),this.dragState=null)}createDragGhost(panelId){const panel=this.panels.get(panelId),ghost=document.createElement("div");return ghost.className="mb-drag-ghost",ghost.innerHTML=SVG_WINDOW,ghost.title=panel?.title||panelId,ghost}hitTestDropZone(x,y,skipGroupId){const floatingEntries=[...this.floatingOverlays.entries()].filter(([,overlay])=>overlay.element.style.display!=="none").sort((a,b)=>{const zA=parseInt(a[1].element.style.zIndex||"0");return parseInt(b[1].element.style.zIndex||"0")-zA});for(const[,overlay]of floatingEntries){const overlayGroups=overlay.internalLayout?overlay.internalLayout.allGroups():[overlay.group];for(const group of overlayGroups){if(group.id===skipGroupId||group.locked==="no-drop-target")continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom)return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}}for(const group of this.groups.values()){if(this.floatingOverlays.has(group.id)||this.findOverlayForGroup(group)||group.id===skipGroupId)continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom&&group.locked!=="no-drop-target")return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}return null}classifyContentZone(x,y,rect,group){if(group.locked==="no-drop-target"){const dT2=y-rect.top,dB2=rect.bottom-y,dL2=x-rect.left,dR2=rect.right-x;let direction;return dT2<=dB2&&dT2<=dL2&&dT2<=dR2?direction="top":dB2<=dT2&&dB2<=dL2&&dB2<=dR2?direction="bottom":dL2<=dR2?direction="left":direction="right",{kind:"content-split",group,direction}}const edgeSize=this.splitEdgeSize,dT=y-rect.top,dB=rect.bottom-y,dL=x-rect.left,dR=rect.right-x;if(Math.min(dT,dB,dL,dR)<edgeSize){let direction;return dT<=dB&&dT<=dL&&dT<=dR?direction="top":dB<=dT&&dB<=dL&&dB<=dR?direction="bottom":dL<=dR?direction="left":direction="right",{kind:"content-split",group,direction}}return{kind:"content-center",group}}applyDragConstraints(zone,sourceGroup){if(!zone)return null;if(!("group"in zone))return zone;const targetInOverlay=this.findOverlayForGroup(zone.group)!==null,targetIsLocked=!!zone.group.locked;return(zone.kind==="content-center"||zone.kind==="header")&&targetIsLocked||sourceGroup.dockingBlocked&&!targetInOverlay?null:zone.kind==="content-split"&&targetInOverlay&&sourceGroup.dialogDockingBlocked?{kind:"content-center",group:zone.group}:zone}updateDropOverlay(zone){const prev=this.dragState?.currentZone??null;if(prev&&prev.kind==="header"&&prev.group.headerElement.classList.remove("mb-group-header--drop-target"),this.dropOverlay.style.display="none",zone===null){this.dragState&&(this.dragState.currentZone=null);return}switch(zone.kind){case"header":zone.group.headerElement.classList.add("mb-group-header--drop-target");break;case"content-center":{const rect=zone.group.contentElement.getBoundingClientRect();this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height),this.dropOverlay.dataset.zone="center";break}case"content-split":this.showSplitIndicator(zone.group,zone.direction);break}this.dragState&&(this.dragState.currentZone=zone)}showSplitIndicator(group,direction){const rect=group.contentElement.getBoundingClientRect();switch(direction){case"top":this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height/2);break;case"bottom":this.positionDropOverlay(rect.left,rect.top+rect.height/2,rect.width,rect.height/2);break;case"left":this.positionDropOverlay(rect.left,rect.top,rect.width/2,rect.height);break;case"right":this.positionDropOverlay(rect.left+rect.width/2,rect.top,rect.width/2,rect.height);break}this.dropOverlay.dataset.zone=direction}positionDropOverlay(left,top,width,height){const el=this.dropOverlay;el.style.display="block",el.style.left=`${left}px`,el.style.top=`${top}px`,el.style.width=`${width}px`,el.style.height=`${height}px`}detachPanelToFloating(panelId,_x,_y){const panel=this.panels.get(panelId);if(!panel||!panel.group||panel.group.id===this.mainGroupId)return;const fw=Math.min(600,window.innerWidth*.8),fh=Math.min(450,window.innerHeight*.7),newGroup=this.addGroup({floating:{x:(window.innerWidth-fw)/2,y:(window.innerHeight-fh)/2,width:fw,height:fh}});this.movePanel(panelId,newGroup.id),this.onGroupCreatedByDragCb?.(newGroup)}dockTabFromDrag(panelId,direction,targetGroup){const layoutForGroup=this.getLayoutForGroup(targetGroup);if(!layoutForGroup)return;const newGroup=new PanelGroup;if(this.groups.set(newGroup.id,newGroup),this.wireGroupCallbacks(newGroup),!layoutForGroup.splitGroup(targetGroup,newGroup,direction)){this.groups.delete(newGroup.id),newGroup.dispose(),this.movePanel(panelId,targetGroup.id);return}const overlayForTarget=this.findOverlayForGroup(targetGroup);overlayForTarget?.internalLayout&&(overlayForTarget.setDragGroup(newGroup),newGroup.location="floating",this.updateFloatingSplitState(overlayForTarget)),this.movePanel(panelId,newGroup.id),overlayForTarget&&overlayForTarget.updateTotalTabCount(),this.onGroupCreatedByDragCb?.(newGroup)}getLayoutForGroup(group){if(this.layout.findGroupNode(group))return this.layout;const overlay=this.findOverlayForGroup(group);return overlay?(overlay.internalLayout||(overlay.internalLayout=new SplitLayout(overlay.element),overlay.internalLayout.setMainGroup(overlay.group)),overlay.internalLayout):null}escapeGroupFromSplit(groupId){const group=this.groups.get(groupId);if(!group||!group.isInFloatingSplit)return;const overlay=this.findOverlayForGroup(group);if(!overlay?.internalLayout)return;const rect=overlay.element.getBoundingClientRect(),wasOwner=this.floatingOverlays.get(groupId)===overlay,newOverlay=new FloatingOverlay(group,{x:Math.min(rect.left+30,window.innerWidth-320),y:Math.min(rect.top+30,window.innerHeight-220),width:Math.max(300,rect.width*.6),height:Math.max(200,rect.height*.8)},this.container,this.portalLayer);this.floatingOverlays.set(groupId,newOverlay),overlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);wasOwner&&remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):remaining.length===0&&overlay.dispose(),group.isInFloatingSplit=!1,group.location==="floating"?group.fireLocationChanged():group.location="floating"}updateFloatingSplitState(overlay){if(!overlay.internalLayout)return;const groups=overlay.internalLayout.allGroups(),isInSplit=groups.length>1;for(const g of groups)g.location="floating",g.isInFloatingSplit=isInSplit;overlay.repositionToolbar()}cleanupOrphanedFloatingLeaf(overlay){if(!overlay.internalLayout)return[];const remaining=overlay.internalLayout.allGroups();return remaining.length<=1?(remaining.length===1&&(overlay.element.appendChild(remaining[0].element),remaining[0].isInFloatingSplit=!1),overlay.internalLayout.dispose(),overlay.internalLayout=null,remaining.length===1&&(overlay.setDragGroup(remaining[0]),remaining[0].location="floating",overlay.repositionToolbar())):this.updateFloatingSplitState(overlay),overlay.updateTotalTabCount(),remaining}minimizeDocked(group){const pos=this.layout.getGroupPosition(group);return this.layout.findGroupNode(group)&&this.layout.removeGroup(group),pos?{siblingGroupId:pos.siblingGroup.id,direction:pos.direction}:null}restoreDocked(group,position,initialSize,siblingGroupId){if(siblingGroupId){const sibling=this.groups.get(siblingGroupId);if(sibling&&this.layout.findGroupNode(sibling)&&this.layout.splitGroup(sibling,group,position,initialSize))return}const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,position,initialSize)}findOverlayForGroup(group){const direct=this.floatingOverlays.get(group.id);if(direct)return direct;for(const overlay of this.floatingOverlays.values())if(overlay.internalLayout?.findGroupNode(group))return overlay;return null}registerPortal(panelId,element,anchor){const entry=document.createElement("div");entry.className="mb-iframe-portal",entry.dataset.portalId=panelId,this.portalLayer.appendChild(entry),entry.appendChild(element),this.portals.set(panelId,{entry,anchor})}unregisterPortal(panelId){const portal=this.portals.get(panelId);portal&&(portal.entry.remove(),this.portals.delete(panelId))}syncPortals(){if(this.disposed)return;const updates=[];for(const[,portal]of this.portals){const{entry,anchor}=portal;if(anchor.offsetParent===null)updates.push({entry,rect:null,zIndex:"0"});else{const overlay=anchor.closest(".mb-floating-overlay"),overlayZ=overlay?.style.zIndex;updates.push({entry,rect:anchor.getBoundingClientRect(),zIndex:overlay?String(parseInt(overlayZ||"100000",10)+1):"50"})}}for(const{entry,rect,zIndex}of updates)rect?(entry.style.display="",entry.style.left=`${rect.left}px`,entry.style.top=`${rect.top}px`,entry.style.width=`${rect.width}px`,entry.style.height=`${rect.height}px`,entry.style.zIndex=zIndex):entry.style.display="none";this.portalRaf=requestAnimationFrame(()=>this.syncPortals())}}export{FloatingOverlay,Panel,PanelGroup,PanelManager,SplitLayout};
1
+ import{SVG_POPOUT,SVG_WINDOW}from"./panel-setup.js";let iframeDragDepth=0;function disableIframePointEvents(){return iframeDragDepth++,document.documentElement.classList.add("mb-dragging"),{release(){--iframeDragDepth<=0&&(iframeDragDepth=0,document.documentElement.classList.remove("mb-dragging"))}}}class Panel{constructor(id,element,title){this.group=null;this.id=id,this.element=element,this.title=title||id,this.wrapper=document.createElement("div"),this.wrapper.className="mb-panel",this.wrapper.dataset.panelId=id,this.wrapper.dataset.active="false",this.wrapper.appendChild(element)}}let groupIdCounter=0;class PanelGroup{constructor(id){this._panels=[];this._activePanel=null;this._headerHidden=!1;this._locked=!1;this._onTabClose=null;this._onTabPointerDown=null;this._onTabPopOut=null;this._location="grid";this._onLocationChangedCb=null;this._isInFloatingSplit=!1;this._onSplitStateChangedCb=null;this._dragConstraint="any";this._dockingBlocked=!1;this._dialogDockingBlocked=!1;this._onPanelCountChangedCb=null;this._onActivePanelChangedCb=null;this.id=id||`group-${++groupIdCounter}`,this.element=document.createElement("div"),this.element.className="mb-group",this.element.dataset.groupId=this.id,this.headerElement=document.createElement("div"),this.headerElement.className="mb-group-header",this.headerPrefix=document.createElement("div"),this.headerPrefix.className="mb-group-header-prefix",this.tabsElement=document.createElement("div"),this.tabsElement.className="mb-group-tabs",this.headerVoid=document.createElement("div"),this.headerVoid.className="mb-group-header-void",this.headerActions=document.createElement("div"),this.headerActions.className="mb-group-header-actions",this.headerElement.appendChild(this.headerPrefix),this.headerElement.appendChild(this.tabsElement),this.headerElement.appendChild(this.headerVoid),this.headerElement.appendChild(this.headerActions),this.contentElement=document.createElement("div"),this.contentElement.className="mb-group-content",this.element.appendChild(this.headerElement),this.element.appendChild(this.contentElement)}get panels(){return this._panels}get activePanel(){return this._activePanel}get size(){return this._panels.length}get locked(){return this._locked}set locked(value){this._locked=value}setHeaderHidden(hidden){this._headerHidden=hidden,this.headerElement.style.display=hidden?"none":""}get headerHidden(){return this._headerHidden}setHeaderActions(element){this.headerActions.innerHTML="",this.headerActions.appendChild(element)}setHeaderPrefix(element){this.headerPrefix.innerHTML="",this.headerPrefix.appendChild(element)}onTabClose(cb){this._onTabClose=cb}onTabPointerDown(cb){this._onTabPointerDown=cb}get location(){return this._location}set location(value){this._location!==value&&(this._location=value,this._onLocationChangedCb?.(value))}onLocationChanged(cb){this._onLocationChangedCb=cb}fireLocationChanged(){this._onLocationChangedCb?.(this._location)}get isInFloatingSplit(){return this._isInFloatingSplit}set isInFloatingSplit(value){this._isInFloatingSplit!==value&&(this._isInFloatingSplit=value,this._onSplitStateChangedCb?.(value))}onSplitStateChanged(cb){this._onSplitStateChangedCb=cb}onTabPopOut(cb){this._onTabPopOut=cb}get dragConstraint(){return this._dragConstraint}set dragConstraint(v){this._dragConstraint=v}get dockingBlocked(){return this._dockingBlocked}set dockingBlocked(v){this._dockingBlocked=v}get dialogDockingBlocked(){return this._dialogDockingBlocked}set dialogDockingBlocked(v){this._dialogDockingBlocked=v}onPanelCountChanged(cb){this._onPanelCountChangedCb=cb}onActivePanelChanged(cb){this._onActivePanelChangedCb=cb}addPanel(panel){if(this._panels.some(p=>p.id===panel.id))return;panel.group=this,this._panels.push(panel),this.contentElement.appendChild(panel.wrapper);const tab=this.createTab(panel);this.tabsElement.appendChild(tab),this.activatePanel(panel.id),this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length)}removePanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),panel.wrapper.remove(),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}detachPanel(panelId){const idx=this._panels.findIndex(p=>p.id===panelId);if(idx===-1)return null;const panel=this._panels[idx];if(this._panels.splice(idx,1),this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`)?.remove(),panel.group=null,this._activePanel===panel&&(this._activePanel=null,this._panels.length>0)){const newActive=this._panels[Math.min(idx,this._panels.length-1)];newActive&&this.activatePanel(newActive.id)}return this.element.dataset.tabCount=String(this._panels.length),this._onPanelCountChangedCb?.(this._panels.length),panel}activatePanel(panelId){const panel=this._panels.find(p=>p.id===panelId);if(!panel)return;this._activePanel=panel;for(const p of this._panels)p.wrapper.dataset.active=p===panel?"true":"false";const tabs=this.tabsElement.querySelectorAll(".mb-tab");for(const tab of tabs){const isActive=tab.dataset.tabId===panelId;tab.dataset.active=isActive?"true":"false"}this._onActivePanelChangedCb?.(panelId)}reorderPanel(panelId,dropX){const panelIdx=this._panels.findIndex(p=>p.id===panelId);if(panelIdx===-1)return;const panel=this._panels[panelIdx],tabs=Array.from(this.tabsElement.querySelectorAll(".mb-tab"));let targetIdx=this._panels.length;for(let i=0;i<tabs.length;i++){const rect=tabs[i].getBoundingClientRect();if(dropX<rect.left+rect.width/2){targetIdx=i;break}}if(targetIdx===panelIdx||targetIdx===panelIdx+1)return;this._panels.splice(panelIdx,1);const insertAt=panelIdx<targetIdx?targetIdx-1:targetIdx;this._panels.splice(insertAt,0,panel);const tabEl=this.tabsElement.querySelector(`[data-tab-id="${panelId}"]`);if(tabEl){const refTab=this.tabsElement.querySelectorAll(".mb-tab")[insertAt];refTab&&refTab!==tabEl?this.tabsElement.insertBefore(tabEl,refTab):this.tabsElement.appendChild(tabEl)}}createTab(panel){const tab=document.createElement("div");tab.className="mb-tab",tab.dataset.tabId=panel.id,tab.dataset.active="false";const label=document.createElement("span");label.className="mb-tab-label",label.innerHTML=SVG_WINDOW,label.title=panel.title,tab.appendChild(label);const actions=document.createElement("div");actions.className="mb-tab-actions";const popOutBtn=document.createElement("button");popOutBtn.className="mb-tab-popout",popOutBtn.title="Pop out",popOutBtn.innerHTML=SVG_POPOUT,popOutBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabPopOut?.(panel.id)}),actions.appendChild(popOutBtn);const closeBtn=document.createElement("button");return closeBtn.className="mb-tab-close",closeBtn.title="Close",closeBtn.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><line x1="4" y1="4" x2="12" y2="12"/><line x1="12" y1="4" x2="4" y2="12"/></svg>',closeBtn.addEventListener("click",e=>{e.stopPropagation(),this._onTabClose?.(panel.id)}),actions.appendChild(closeBtn),tab.appendChild(actions),tab.addEventListener("pointerdown",e=>{e.target.closest(".mb-tab-close")||e.target.closest(".mb-tab-popout")||e.button===0&&(e.preventDefault(),this._onTabPointerDown?.(panel.id,e))}),tab}dispose(){this._panels=[],this._activePanel=null,this.element.remove()}}let zIndexCounter=1e5;class FloatingOverlay{constructor(group,opts,parentElement,insertBefore){this.internalLayout=null;this.toolbarElement=null;this.savedBounds=null;this._isMaximized=!1;this._onDragEnd=null;this._onDragMove=null;this.group=group,this.bounds={...opts},this.element=document.createElement("div"),this.element.className="mb-floating-overlay",this.element.dataset.groupId=group.id,this.applyBounds();const directions=["n","s","e","w","ne","nw","se","sw"];for(const dir of directions){const handle=document.createElement("div");handle.className=`mb-resize-handle mb-resize-${dir}`,handle.addEventListener("pointerdown",e=>this.onResizeStart(e,dir)),this.element.appendChild(handle)}this.element.addEventListener("pointerdown",()=>this.bringToFront(),!0),group.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),group.headerVoid.style.cursor="grab";const parent=parentElement??document.body;insertBefore?parent.insertBefore(this.element,insertBefore):parent.appendChild(this.element),this.element.appendChild(group.element),this.bringToFront()}get isMaximized(){return this._isMaximized}set onDragEnd(cb){this._onDragEnd=cb}set onDragMove(cb){this._onDragMove=cb}bringToFront(){zIndexCounter+=2,this.element.style.zIndex=String(zIndexCounter)}maximize(){this._isMaximized||(this.savedBounds={...this.bounds},this._isMaximized=!0,this.element.style.inset="0",this.element.style.width="auto",this.element.style.height="auto",this.element.classList.add("mb-floating-maximized"))}restore(){!this._isMaximized||!this.savedBounds||(this._isMaximized=!1,this.bounds={...this.savedBounds},this.savedBounds=null,this.element.classList.remove("mb-floating-maximized"),this.element.style.inset="",this.applyBounds())}hide(){this.element.style.display="none"}show(){this.element.style.display=""}dispose(){this.internalLayout&&(this.internalLayout.dispose(),this.internalLayout=null),this.removeToolbar(),this.element.remove()}getBounds(){return{...this.bounds}}setBounds(partial){if(this._isMaximized)return;const pad=10;partial.width!==void 0&&(this.bounds.width=Math.min(partial.width,window.innerWidth-this.bounds.x-pad)),partial.height!==void 0&&(this.bounds.height=Math.min(partial.height,window.innerHeight-this.bounds.y-pad)),this.applyBounds()}setFullBounds(bounds){if(this._isMaximized)return;const vw=window.innerWidth,vh=window.innerHeight,pad=10,minVisible=100;this.bounds={width:Math.max(minVisible,Math.min(bounds.width,vw-pad)),height:Math.max(minVisible,Math.min(bounds.height,vh-pad)),x:Math.max(0,Math.min(bounds.x,vw-minVisible)),y:Math.max(0,Math.min(bounds.y,vh-minVisible))},this.applyBounds()}applyBounds(){this.element.style.position="fixed",this.element.style.left=`${this.bounds.x}px`,this.element.style.top=`${this.bounds.y}px`,this.element.style.width=`${this.bounds.width}px`,this.element.style.height=`${this.bounds.height}px`}setDragGroup(newGroup){newGroup.headerVoid.addEventListener("pointerdown",e=>this.onDragStart(e)),newGroup.headerVoid.style.cursor="grab"}setToolbar(el){this.removeToolbar(),this.toolbarElement=el,this.getToolbarHost().headerActions.appendChild(el)}removeToolbar(){this.toolbarElement&&(this.toolbarElement.remove(),this.toolbarElement=null)}repositionToolbar(){this.toolbarElement&&this.getToolbarHost().headerActions.appendChild(this.toolbarElement)}getToolbarHost(){if(!this.internalLayout)return this.group;const root=this.internalLayout.getRoot();return root?FloatingOverlay.topRightGroup(root):this.group}static topRightGroup(node){return node.kind==="leaf"?node.group:node.direction==="horizontal"?FloatingOverlay.topRightGroup(node.second):FloatingOverlay.topRightGroup(node.first)}get hasToolbar(){return this.toolbarElement!==null}getAllGroups(){return this.internalLayout?.allGroups()??[this.group]}updateTotalTabCount(){const groups=this.getAllGroups();let total=0;for(const g of groups)total+=g.size;this.element.dataset.totalTabCount=String(total)}onDragStart(e){if(this._isMaximized)return;e.preventDefault();const handle=e.currentTarget,startX=e.clientX,startY=e.clientY,origLeft=this.bounds.x,origTop=this.bounds.y,iframes=disableIframePointEvents();handle.style.cursor="grabbing",handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;this.bounds.x=Math.max(0,Math.min(origLeft+dx,window.innerWidth-this.bounds.width)),this.bounds.y=Math.max(0,Math.min(origTop+dy,window.innerHeight-this.bounds.height)),this.applyBounds(),this._onDragMove?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)},onUp=()=>{iframes.release(),handle.style.cursor="grab",handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp),this._onDragEnd?.(this.bounds.x+this.bounds.width/2,this.bounds.y+this.bounds.height/2)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}onResizeStart(e,dir){if(this._isMaximized)return;e.preventDefault(),e.stopPropagation();const startX=e.clientX,startY=e.clientY,orig={...this.bounds},handle=e.currentTarget,minW=200,minH=100,iframes=disableIframePointEvents();handle.setPointerCapture(e.pointerId);const onMove=ev=>{const dx=ev.clientX-startX,dy=ev.clientY-startY;if(dir.includes("e")&&(this.bounds.width=Math.max(minW,orig.width+dx)),dir.includes("w")){const newW=Math.max(minW,orig.width-dx);this.bounds.x=orig.x+(orig.width-newW),this.bounds.width=newW}if(dir.includes("s")&&(this.bounds.height=Math.max(minH,orig.height+dy)),dir.includes("n")){const newH=Math.max(minH,orig.height-dy);this.bounds.y=orig.y+(orig.height-newH),this.bounds.height=newH}const pad=10;this.bounds.x=Math.max(0,this.bounds.x),this.bounds.y=Math.max(0,this.bounds.y),this.bounds.x+this.bounds.width>window.innerWidth-pad&&(this.bounds.width=window.innerWidth-this.bounds.x-pad),this.bounds.y+this.bounds.height>window.innerHeight-pad&&(this.bounds.height=window.innerHeight-this.bounds.y-pad),this.applyBounds()},onUp=()=>{iframes.release(),handle.removeEventListener("pointermove",onMove),handle.removeEventListener("pointerup",onUp),handle.removeEventListener("pointercancel",onUp)};handle.addEventListener("pointermove",onMove),handle.addEventListener("pointerup",onUp),handle.addEventListener("pointercancel",onUp)}}class SplitLayout{constructor(container){this.root=null;this.element=document.createElement("div"),this.element.className="mb-layout",container.appendChild(this.element)}getRoot(){return this.root}setMainGroup(group){const leaf=this.createLeaf(group);leaf.element.style.flex="1",this.root=leaf,this.element.appendChild(leaf.element)}splitGroup(targetGroup,newGroup,direction,newGroupSize){const splitDir=this.dockToSplitDirection(direction),leafNode=this.findGroupNode(targetGroup);if(!leafNode)return!1;const newLeafEl=document.createElement("div");newLeafEl.className="mb-split-leaf",newLeafEl.style.flex="1";const splitEl=document.createElement("div");splitEl.className=`mb-split-container ${splitDir==="horizontal"?"mb-split-horizontal":"mb-split-vertical"}`,splitEl.style.flex=leafNode.element.style.flex||"1",splitEl.style.minWidth="0",splitEl.style.minHeight="0";const separator=document.createElement("div"),isVerticalSplit=splitDir==="vertical";separator.className=`mb-layout-separator ${isVerticalSplit?"mb-layout-separator-h":"mb-layout-separator-v"}`;const existingFirst=direction==="right"||direction==="bottom";leafNode.element.parentElement.insertBefore(splitEl,leafNode.element),existingFirst?(splitEl.appendChild(leafNode.element),splitEl.appendChild(separator),splitEl.appendChild(newLeafEl)):(splitEl.appendChild(newLeafEl),splitEl.appendChild(separator),splitEl.appendChild(leafNode.element)),newLeafEl.appendChild(newGroup.element),newGroupSize!==void 0&&newGroupSize>0?existingFirst?(leafNode.element.style.flex="1",newLeafEl.style.flex=`0 0 ${newGroupSize}px`):(newLeafEl.style.flex=`0 0 ${newGroupSize}px`,leafNode.element.style.flex="1"):(leafNode.element.style.flex="1",newLeafEl.style.flex="1");const newLeaf={kind:"leaf",group:newGroup,element:newLeafEl},splitNode={kind:"split",direction:splitDir,first:existingFirst?leafNode:newLeaf,second:existingFirst?newLeaf:leafNode,element:splitEl,separator};return separator.addEventListener("pointerdown",e=>this.onSeparatorDrag(e,splitNode)),this.replaceNodeInTree(leafNode,splitNode),leafNode.element.style.display==="none"&&(separator.style.display="none",newLeafEl.dataset.savedFlex=newLeafEl.style.flex,newLeafEl.style.flex="1",leafNode.element.dataset.savedFlex=leafNode.element.style.flex),!0}removeGroup(group){const leafNode=this.findGroupNode(group);if(!leafNode)return;if(this.root===leafNode){leafNode.element.remove(),this.root=null;return}this.restoreMaximizedLeaf(group);const parentSplit=this.findParentSplit(leafNode);if(!parentSplit)return;const sibling=parentSplit.first===leafNode?parentSplit.second:parentSplit.first;this.restoreMaximizedSubtree(sibling),sibling.element.style.flex=parentSplit.element.style.flex||"1",parentSplit.element.parentElement.insertBefore(sibling.element,parentSplit.element),leafNode.element.remove(),parentSplit.separator.remove(),parentSplit.element.remove(),this.replaceNodeInTree(parentSplit,sibling)}findGroupNode(group){return this.findGroupNodeIn(this.root,group)}getGroupPosition(group){const leaf=this.findGroupNode(group);if(!leaf)return null;const parent=this.findParentSplit(leaf);if(!parent)return null;const isFirst=parent.first===leaf,siblingNode=isFirst?parent.second:parent.first,siblingGroup=this.firstGroupIn(siblingNode);if(!siblingGroup)return null;let direction;return parent.direction==="horizontal"?direction=isFirst?"left":"right":direction=isFirst?"top":"bottom",{siblingGroup,direction}}firstGroupIn(node){return node.kind==="leaf"?node.group:this.firstGroupIn(node.first)}collapseLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;const parent=this.findParentSplit(leaf);if(parent){const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex=sibling.element.style.flex,sibling.element.style.flex="1",parent.separator.style.display="none"}leaf.element.dataset.savedFlex=leaf.element.style.flex,leaf.element.style.display="none"}expandLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;leaf.element.style.display="",leaf.element.dataset.savedFlex!==void 0&&(leaf.element.style.flex=leaf.element.dataset.savedFlex,delete leaf.element.dataset.savedFlex);const parent=this.findParentSplit(leaf);if(parent){parent.separator.style.display="";const sibling=parent.first===leaf?parent.second:parent.first;sibling.element.dataset.savedFlex!==void 0&&(sibling.element.style.flex=sibling.element.dataset.savedFlex,delete sibling.element.dataset.savedFlex)}}maximizeLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay===void 0&&(sibling.element.dataset.maxSavedDisplay=sibling.element.style.display),sibling.element.style.display="none",parent.separator.dataset.maxSavedDisplay===void 0&&(parent.separator.dataset.maxSavedDisplay=parent.separator.style.display),parent.separator.style.display="none",current.element.dataset.maxSavedFlex===void 0&&(current.element.dataset.maxSavedFlex=current.element.style.flex),current.element.style.flex="1",current=parent,parent=this.findParentSplit(current)}}restoreMaximizedLeaf(group){const leaf=this.findGroupNode(group);if(!leaf)return;let current=leaf,parent=this.findParentSplit(current);for(;parent;){const sibling=parent.first===current?parent.second:parent.first;sibling.element.dataset.maxSavedDisplay!==void 0&&(sibling.element.style.display=sibling.element.dataset.maxSavedDisplay,delete sibling.element.dataset.maxSavedDisplay),parent.separator.dataset.maxSavedDisplay!==void 0&&(parent.separator.style.display=parent.separator.dataset.maxSavedDisplay,delete parent.separator.dataset.maxSavedDisplay),current.element.dataset.maxSavedFlex!==void 0&&(current.element.style.flex=current.element.dataset.maxSavedFlex,delete current.element.dataset.maxSavedFlex),current=parent,parent=this.findParentSplit(current)}}restoreMaximizedSubtree(node){node.element.dataset.maxSavedDisplay!==void 0&&(node.element.style.display=node.element.dataset.maxSavedDisplay,delete node.element.dataset.maxSavedDisplay),node.element.dataset.maxSavedFlex!==void 0&&(node.element.style.flex=node.element.dataset.maxSavedFlex,delete node.element.dataset.maxSavedFlex),node.kind==="split"&&(node.separator.dataset.maxSavedDisplay!==void 0&&(node.separator.style.display=node.separator.dataset.maxSavedDisplay,delete node.separator.dataset.maxSavedDisplay),this.restoreMaximizedSubtree(node.first),this.restoreMaximizedSubtree(node.second))}allGroups(){const result=[];return this.collectGroups(this.root,result),result}toJSON(){return this.serializeNode(this.root)}restoreFlexFromSerialized(serialized){if(!serialized||!this.root)return;const flexMap=new Map;this.collectFlexValues(serialized,flexMap),this.applyFlexValues(this.root,flexMap)}animateTransition(){const cls=node=>{node&&(node.kind==="leaf"?node.element.classList.add("mb-split-leaf--animating"):(node.element.classList.add("mb-split-container--animating"),node.separator&&node.separator.classList.add("mb-layout-separator--animating"),cls(node.first),cls(node.second)))};cls(this.root);const cleanup=()=>{this.element.querySelectorAll(".mb-split-leaf--animating, .mb-split-container--animating, .mb-layout-separator--animating").forEach(el=>{el.classList.remove("mb-split-leaf--animating","mb-split-container--animating","mb-layout-separator--animating")})},timer=setTimeout(cleanup,350);this.element.addEventListener("transitionend",()=>{clearTimeout(timer),cleanup()},{once:!0})}dispose(){this.element.remove(),this.root=null}createLeaf(group){const leafEl=document.createElement("div");return leafEl.className="mb-split-leaf",leafEl.style.flex="1",leafEl.appendChild(group.element),{kind:"leaf",group,element:leafEl}}dockToSplitDirection(pos){return pos==="left"||pos==="right"?"horizontal":"vertical"}findGroupNodeIn(node,group){return node?node.kind==="leaf"?node.group===group?node:null:this.findGroupNodeIn(node.first,group)??this.findGroupNodeIn(node.second,group):null}collectGroups(node,result){node&&(node.kind==="leaf"?result.push(node.group):(this.collectGroups(node.first,result),this.collectGroups(node.second,result)))}findParentSplit(target){return this.findParentSplitIn(this.root,target)}findParentSplitIn(node,target){return!node||node.kind==="leaf"?null:node.first===target||node.second===target?node:this.findParentSplitIn(node.first,target)??this.findParentSplitIn(node.second,target)}replaceNodeInTree(oldNode,newNode){if(this.root===oldNode){this.root=newNode;return}const parent=this.findParentSplit(oldNode);parent&&(parent.first===oldNode?parent.first=newNode:parent.second=newNode)}collectFlexValues(node,map){node.kind==="leaf"?map.set(node.groupId,node.flex):(this.collectFlexValues(node.first,map),this.collectFlexValues(node.second,map))}applyFlexValues(node,map){if(node.kind==="leaf"){const saved=map.get(node.group.id);saved&&this.isValidFlex(saved)&&(node.element.style.flex=saved)}else this.applyFlexValues(node.first,map),this.applyFlexValues(node.second,map)}isValidFlex(value){if(value.includes("px"))return!0;const n=Number(value);return Number.isFinite(n)&&n>=0}serializeNode(node){return node?node.kind==="leaf"?{kind:"leaf",groupId:node.group.id,flex:node.element.style.flex||"1"}:{kind:"split",direction:node.direction,first:this.serializeNode(node.first),second:this.serializeNode(node.second),flex:node.element.style.flex||"1"}:null}onSeparatorDrag(e,splitNode){if(e.preventDefault(),splitNode.first.element.style.display==="none"||splitNode.second.element.style.display==="none")return;const isHorizontal=splitNode.direction==="horizontal",startPos=isHorizontal?e.clientX:e.clientY,firstEl=splitNode.first.element,secondEl=splitNode.second.element;this.lockDescendantSizes(splitNode.first,isHorizontal),this.lockDescendantSizes(splitNode.second,isHorizontal);const origFirstSize=isHorizontal?firstEl.offsetWidth:firstEl.offsetHeight,origSecondSize=isHorizontal?secondEl.offsetWidth:secondEl.offsetHeight,totalSize=origFirstSize+origSecondSize;if(totalSize<=0)return;const minSize=150,iframes=disableIframePointEvents();splitNode.separator.setPointerCapture(e.pointerId),splitNode.separator.classList.add("mb-layout-separator--active");const onMove=ev=>{if(firstEl.style.display==="none"||secondEl.style.display==="none"){splitNode.separator.releasePointerCapture(ev.pointerId),onUp();return}const delta=(isHorizontal?ev.clientX:ev.clientY)-startPos;let newFirst=origFirstSize+delta,newSecond=origSecondSize-delta;newFirst<minSize&&(newFirst=minSize,newSecond=totalSize-minSize),newSecond<minSize&&(newSecond=minSize,newFirst=totalSize-minSize),firstEl.style.flex=String(newFirst/totalSize),secondEl.style.flex=String(newSecond/totalSize)},onUp=()=>{iframes.release(),splitNode.separator.classList.remove("mb-layout-separator--active"),splitNode.separator.removeEventListener("pointermove",onMove),splitNode.separator.removeEventListener("pointerup",onUp),splitNode.separator.removeEventListener("pointercancel",onUp),this.unlockDescendantSizes(splitNode.first,isHorizontal),this.unlockDescendantSizes(splitNode.second,isHorizontal)};splitNode.separator.addEventListener("pointermove",onMove),splitNode.separator.addEventListener("pointerup",onUp),splitNode.separator.addEventListener("pointercancel",onUp)}lockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height;node.first.element.style.flex=`0 0 ${firstSize}px`,node.second.element.style.flex="1",this.lockDescendantSizes(node.first,isHorizontal),this.lockDescendantSizes(node.second,isHorizontal)}unlockDescendantSizes(node,isHorizontal){if(node.kind!=="split"||node.direction==="horizontal"!==isHorizontal)return;this.unlockDescendantSizes(node.first,isHorizontal),this.unlockDescendantSizes(node.second,isHorizontal);const firstSize=isHorizontal?node.first.element.getBoundingClientRect().width:node.first.element.getBoundingClientRect().height,secondSize=isHorizontal?node.second.element.getBoundingClientRect().width:node.second.element.getBoundingClientRect().height,total=firstSize+secondSize;total>0?(node.first.element.style.flex=String(firstSize/total),node.second.element.style.flex=String(secondSize/total)):(node.first.element.style.flex="0.5",node.second.element.style.flex="0.5")}}class PanelManager{constructor(opts){this.groups=new Map;this.panels=new Map;this.floatingOverlays=new Map;this.mainGroupId=null;this.onPanelRemovedCbs=[];this.onGroupCreatedByDragCb=null;this.disposed=!1;this.dragState=null;this.portals=new Map;this.portalRaf=0;this.mainGroupCollapsed=!1;this._beforeTabClose=null;this.zBase=0;this.container=opts.container,this.splitEdgeSize=opts.splitEdgeSize??100,this.layout=new SplitLayout(this.container),opts.onPanelRemoved&&this.onPanelRemovedCbs.push(opts.onPanelRemoved),this.onGroupCreatedByDragCb=opts.onGroupCreatedByDrag??null,this.zBase=this.getZBase(),this.zBase!==0&&(zIndexCounter=1e5+this.zBase),this.dropOverlay=document.createElement("div"),this.dropOverlay.className="mb-drop-overlay",this.container.appendChild(this.dropOverlay),this.portalLayer=document.createElement("div"),this.portalLayer.className="mb-iframe-portal-layer",this.container.appendChild(this.portalLayer),this.syncPortals()}getZBase(){const v=getComputedStyle(this.container).getPropertyValue("--mb-adapt-z-base").trim();return parseInt(v,10)||0}setBeforeTabClose(cb){this._beforeTabClose=cb}addPanel(opts){const panel=new Panel(opts.id,opts.element,opts.title);this.panels.set(opts.id,panel);const groupId=opts.groupId;if(groupId){const group=this.groups.get(groupId);group&&(group.addPanel(panel),this.registerPortal(panel.id,panel.element,panel.wrapper))}return panel}removePanel(panelId){const panel=this.panels.get(panelId);if(panel){if(this.unregisterPortal(panelId),panel.group){const group=panel.group;group.removePanel(panelId),group.size===0&&group.id!==this.mainGroupId&&this.removeGroup(group.id)}this.panels.delete(panelId);for(const cb of this.onPanelRemovedCbs)cb(panel)}}getPanel(panelId){return this.panels.get(panelId)}addGroup(opts){const group=new PanelGroup(opts?.id);if(this.groups.set(group.id,group),this.wireGroupCallbacks(group),opts?.floating)this.addFloatingGroup(group,opts.floating);else if(opts?.direction){const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,opts.direction,opts.initialSize)}return group}removeGroup(groupId){const group=this.groups.get(groupId);if(!group)return;for(const panel of[...group.panels])this.unregisterPortal(panel.id);const overlay=this.floatingOverlays.get(groupId);if(overlay)if(overlay.internalLayout){overlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):overlay.dispose()}else overlay.dispose(),this.floatingOverlays.delete(groupId);if(!overlay){const parentOverlay=this.findOverlayForGroup(group);parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay))}this.layout.findGroupNode(group)&&this.layout.removeGroup(group),group.isInFloatingSplit=!1,group.dispose(),this.groups.delete(groupId)}getGroup(groupId){return this.groups.get(groupId)}getMainGroup(){if(this.mainGroupId)return this.groups.get(this.mainGroupId)}setMainGroup(group){this.mainGroupId=group.id,this.layout.setMainGroup(group)}collapseMainGroup(){const main=this.getMainGroup();!main||this.mainGroupCollapsed||(this.layout.collapseLeaf(main),this.mainGroupCollapsed=!0)}expandMainGroup(){const main=this.getMainGroup();!main||!this.mainGroupCollapsed||(this.layout.expandLeaf(main),this.mainGroupCollapsed=!1)}isMainGroupCollapsed(){return this.mainGroupCollapsed}getDockedGroups(){return this.layout.allGroups()}collapseDockedGroup(group){this.layout.collapseLeaf(group)}expandDockedGroup(group){this.layout.expandLeaf(group)}maximizeDockedGroup(group){this.layout.maximizeLeaf(group)}restoreMaximizedDockedGroup(group){this.layout.restoreMaximizedLeaf(group)}restoreLayoutFlex(serialized){this.layout.restoreFlexFromSerialized(serialized)}addFloatingGroup(group,opts){const existingOverlay=this.floatingOverlays.get(group.id);existingOverlay&&this.floatingOverlays.delete(group.id);const parentOverlay=existingOverlay?null:this.findOverlayForGroup(group),overlay=new FloatingOverlay(group,opts,this.container,this.portalLayer);if(this.floatingOverlays.set(group.id,overlay),this.layout.findGroupNode(group)&&this.layout.removeGroup(group),existingOverlay?.internalLayout){existingOverlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(existingOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,existingOverlay):existingOverlay.dispose()}else existingOverlay?existingOverlay.dispose():parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));return group.isInFloatingSplit=!1,group.location="floating",overlay.updateTotalTabCount(),overlay}dockGroup(groupId,position,initialSize){const group=this.groups.get(groupId);if(!group||groupId===this.mainGroupId)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;const directOverlay=this.floatingOverlays.get(groupId),parentOverlay=directOverlay?null:this.findOverlayForGroup(group);if(this.layout.splitGroup(mainGroup,group,position,initialSize)){if(directOverlay)if(directOverlay.internalLayout){directOverlay.internalLayout.removeGroup(group),this.floatingOverlays.delete(groupId);const remaining=this.cleanupOrphanedFloatingLeaf(directOverlay);remaining.length>0?this.floatingOverlays.set(remaining[0].id,directOverlay):directOverlay.dispose()}else directOverlay.dispose(),this.floatingOverlays.delete(groupId);else parentOverlay?.internalLayout&&(parentOverlay.internalLayout.removeGroup(group),this.cleanupOrphanedFloatingLeaf(parentOverlay));group.location="grid",group.isInFloatingSplit=!1}}getFloatingOverlay(groupId){return this.floatingOverlays.get(groupId)}dockOverlay(groupId){const overlay=this.floatingOverlays.get(groupId);if(!overlay)return;const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;if(!mainGroup)return;if(!overlay.internalLayout){this.dockGroup(groupId,"right");return}const allGroups=overlay.internalLayout.allGroups();if(allGroups.length===0)return;const first=allGroups[0];this.layout.splitGroup(mainGroup,first,"right"),first.location="grid",first.isInFloatingSplit=!1;for(let i=1;i<allGroups.length;i++){const g=allGroups[i];this.layout.splitGroup(first,g,"bottom"),g.location="grid",g.isInFloatingSplit=!1}overlay.internalLayout.dispose(),overlay.internalLayout=null,overlay.dispose(),this.floatingOverlays.delete(groupId)}findOverlayContaining(groupId){const group=this.groups.get(groupId);if(group)return this.findOverlayForGroup(group)??void 0}movePanel(panelId,targetGroupId){const panel=this.panels.get(panelId);if(!panel)return;const sourceGroup=panel.group;if(!sourceGroup||sourceGroup.id===targetGroupId)return;const targetGroup=this.groups.get(targetGroupId);targetGroup&&(sourceGroup.detachPanel(panelId),targetGroup.addPanel(panel),sourceGroup.size===0&&sourceGroup.id!==this.mainGroupId&&this.removeGroup(sourceGroup.id))}serializeLayout(){const floatingGroups=[];for(const[groupId,overlay]of this.floatingOverlays){const entry={groupId,bounds:overlay.getBounds(),internalLayout:overlay.internalLayout?.toJSON()??null};overlay.isMaximized&&(entry.isMaximized=!0),floatingGroups.push(entry)}const panelLocations={};for(const[panelId,panel]of this.panels)panel.group&&(panelLocations[panelId]=panel.group.id);return{mainLayout:this.layout.toJSON(),floatingGroups,panelLocations}}getFloatingOverlays(){return this.floatingOverlays}onDidRemovePanel(cb){return this.onPanelRemovedCbs.push(cb),{dispose:()=>{const idx=this.onPanelRemovedCbs.indexOf(cb);idx!==-1&&this.onPanelRemovedCbs.splice(idx,1)}}}dispose(){if(!this.disposed){this.disposed=!0,this.cancelTabDrag(),cancelAnimationFrame(this.portalRaf);for(const overlay of this.floatingOverlays.values())overlay.dispose();this.floatingOverlays.clear();for(const group of this.groups.values())group.dispose();this.groups.clear(),this.panels.clear(),this.onPanelRemovedCbs=[],this.dropOverlay.remove();for(const portal of this.portals.values())portal.entry.remove();this.portals.clear(),this.portalLayer.remove(),this.layout.dispose()}}wireGroupCallbacks(group){group.onTabClose(panelId=>{if(this._beforeTabClose){const result=this._beforeTabClose(panelId);result&&typeof result.then=="function"?result.then(allowed=>{allowed&&this.removePanel(panelId)}):result!==!1&&this.removePanel(panelId);return}this.removePanel(panelId)}),group.onTabPointerDown((panelId,e)=>{this.onTabPointerDown(panelId,group,e)}),group.onTabPopOut(panelId=>{this.detachPanelToFloating(panelId,window.innerWidth/2,window.innerHeight/2)})}onTabPointerDown(panelId,sourceGroup,e){if(this.dragState)return;this.dragState={panelId,sourceGroup,startX:e.clientX,startY:e.clientY,isDragging:!1,ghost:null,iframes:null,currentZone:null};const onMove=ev=>{if(!this.dragState)return;if(!this.dragState.isDragging){const dx=ev.clientX-this.dragState.startX,dy=ev.clientY-this.dragState.startY;if(dx*dx+dy*dy<25)return;this.dragState.isDragging=!0,this.dragState.iframes=disableIframePointEvents(),this.dragState.ghost=this.createDragGhost(panelId),this.container.appendChild(this.dragState.ghost)}this.dragState.ghost.style.left=`${ev.clientX+8}px`,this.dragState.ghost.style.top=`${ev.clientY+8}px`;let zone=this.hitTestDropZone(ev.clientX,ev.clientY);zone=this.applyDragConstraints(zone,this.dragState.sourceGroup),this.updateDropOverlay(zone)},onUp=ev=>{if(document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),!this.dragState)return;if(!this.dragState.isDragging){sourceGroup.activatePanel(panelId),this.dragState=null;return}this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null);const zone=this.applyDragConstraints(this.hitTestDropZone(ev.clientX,ev.clientY),sourceGroup);if(zone)switch(zone.kind){case"header":case"content-center":zone.group.id===sourceGroup.id?sourceGroup.reorderPanel(panelId,ev.clientX):this.movePanel(panelId,zone.group.id);break;case"content-split":this.dockTabFromDrag(panelId,zone.direction,zone.group);break}this.dragState=null},onCancel=()=>{document.removeEventListener("pointermove",onMove),document.removeEventListener("pointerup",onUp),document.removeEventListener("pointercancel",onCancel),this.cancelTabDrag()};document.addEventListener("pointermove",onMove),document.addEventListener("pointerup",onUp),document.addEventListener("pointercancel",onCancel)}cancelTabDrag(){this.dragState&&(this.dragState.ghost?.remove(),this.dragState.iframes?.release(),this.updateDropOverlay(null),this.dragState=null)}createDragGhost(panelId){const panel=this.panels.get(panelId),ghost=document.createElement("div");return ghost.className="mb-drag-ghost",ghost.innerHTML=SVG_WINDOW,ghost.title=panel?.title||panelId,ghost}hitTestDropZone(x,y,skipGroupId){const floatingEntries=[...this.floatingOverlays.entries()].filter(([,overlay])=>overlay.element.style.display!=="none").sort((a,b)=>{const zA=parseInt(a[1].element.style.zIndex||"0");return parseInt(b[1].element.style.zIndex||"0")-zA});for(const[,overlay]of floatingEntries){const overlayGroups=overlay.internalLayout?overlay.internalLayout.allGroups():[overlay.group];for(const group of overlayGroups){if(group.id===skipGroupId||group.locked==="no-drop-target")continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom)return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}}for(const group of this.groups.values()){if(this.floatingOverlays.has(group.id)||this.findOverlayForGroup(group)||group.id===skipGroupId)continue;if(!group.headerHidden){const hr=group.headerElement.getBoundingClientRect();if(x>=hr.left&&x<=hr.right&&y>=hr.top&&y<=hr.bottom&&group.locked!=="no-drop-target")return{kind:"header",group}}const cr=group.contentElement.getBoundingClientRect();if(x>=cr.left&&x<=cr.right&&y>=cr.top&&y<=cr.bottom)return this.classifyContentZone(x,y,cr,group)}return null}classifyContentZone(x,y,rect,group){if(group.locked==="no-drop-target"){const dT2=y-rect.top,dB2=rect.bottom-y,dL2=x-rect.left,dR2=rect.right-x;let direction;return dT2<=dB2&&dT2<=dL2&&dT2<=dR2?direction="top":dB2<=dT2&&dB2<=dL2&&dB2<=dR2?direction="bottom":dL2<=dR2?direction="left":direction="right",{kind:"content-split",group,direction}}const edgeSize=this.splitEdgeSize,dT=y-rect.top,dB=rect.bottom-y,dL=x-rect.left,dR=rect.right-x;if(Math.min(dT,dB,dL,dR)<edgeSize){let direction;return dT<=dB&&dT<=dL&&dT<=dR?direction="top":dB<=dT&&dB<=dL&&dB<=dR?direction="bottom":dL<=dR?direction="left":direction="right",{kind:"content-split",group,direction}}return{kind:"content-center",group}}applyDragConstraints(zone,sourceGroup){if(!zone)return null;if(!("group"in zone))return zone;const targetInOverlay=this.findOverlayForGroup(zone.group)!==null,targetIsLocked=!!zone.group.locked;return(zone.kind==="content-center"||zone.kind==="header")&&targetIsLocked||sourceGroup.dockingBlocked&&!targetInOverlay?null:zone.kind==="content-split"&&targetInOverlay&&sourceGroup.dialogDockingBlocked?{kind:"content-center",group:zone.group}:zone}updateDropOverlay(zone){const prev=this.dragState?.currentZone??null;if(prev&&prev.kind==="header"&&prev.group.headerElement.classList.remove("mb-group-header--drop-target"),this.dropOverlay.style.display="none",zone===null){this.dragState&&(this.dragState.currentZone=null);return}switch(zone.kind){case"header":zone.group.headerElement.classList.add("mb-group-header--drop-target");break;case"content-center":{const rect=zone.group.contentElement.getBoundingClientRect();this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height),this.dropOverlay.dataset.zone="center";break}case"content-split":this.showSplitIndicator(zone.group,zone.direction);break}this.dragState&&(this.dragState.currentZone=zone)}showSplitIndicator(group,direction){const rect=group.contentElement.getBoundingClientRect();switch(direction){case"top":this.positionDropOverlay(rect.left,rect.top,rect.width,rect.height/2);break;case"bottom":this.positionDropOverlay(rect.left,rect.top+rect.height/2,rect.width,rect.height/2);break;case"left":this.positionDropOverlay(rect.left,rect.top,rect.width/2,rect.height);break;case"right":this.positionDropOverlay(rect.left+rect.width/2,rect.top,rect.width/2,rect.height);break}this.dropOverlay.dataset.zone=direction}positionDropOverlay(left,top,width,height){const el=this.dropOverlay;el.style.display="block",el.style.left=`${left}px`,el.style.top=`${top}px`,el.style.width=`${width}px`,el.style.height=`${height}px`}detachPanelToFloating(panelId,_x,_y){const panel=this.panels.get(panelId);if(!panel||!panel.group||panel.group.id===this.mainGroupId)return;const fw=Math.min(600,window.innerWidth*.8),fh=Math.min(450,window.innerHeight*.7),newGroup=this.addGroup({floating:{x:(window.innerWidth-fw)/2,y:(window.innerHeight-fh)/2,width:fw,height:fh}});this.movePanel(panelId,newGroup.id),this.onGroupCreatedByDragCb?.(newGroup)}dockTabFromDrag(panelId,direction,targetGroup){const layoutForGroup=this.getLayoutForGroup(targetGroup);if(!layoutForGroup)return;const newGroup=new PanelGroup;if(this.groups.set(newGroup.id,newGroup),this.wireGroupCallbacks(newGroup),!layoutForGroup.splitGroup(targetGroup,newGroup,direction)){this.groups.delete(newGroup.id),newGroup.dispose(),this.movePanel(panelId,targetGroup.id);return}const overlayForTarget=this.findOverlayForGroup(targetGroup);overlayForTarget?.internalLayout&&(overlayForTarget.setDragGroup(newGroup),newGroup.location="floating",this.updateFloatingSplitState(overlayForTarget)),this.movePanel(panelId,newGroup.id),overlayForTarget&&overlayForTarget.updateTotalTabCount(),this.onGroupCreatedByDragCb?.(newGroup)}getLayoutForGroup(group){if(this.layout.findGroupNode(group))return this.layout;const overlay=this.findOverlayForGroup(group);return overlay?(overlay.internalLayout||(overlay.internalLayout=new SplitLayout(overlay.element),overlay.internalLayout.setMainGroup(overlay.group)),overlay.internalLayout):null}escapeGroupFromSplit(groupId){const group=this.groups.get(groupId);if(!group||!group.isInFloatingSplit)return;const overlay=this.findOverlayForGroup(group);if(!overlay?.internalLayout)return;const rect=overlay.element.getBoundingClientRect(),wasOwner=this.floatingOverlays.get(groupId)===overlay,newOverlay=new FloatingOverlay(group,{x:Math.min(rect.left+30,window.innerWidth-320),y:Math.min(rect.top+30,window.innerHeight-220),width:Math.max(300,rect.width*.6),height:Math.max(200,rect.height*.8)},this.container,this.portalLayer);this.floatingOverlays.set(groupId,newOverlay),overlay.internalLayout.removeGroup(group);const remaining=this.cleanupOrphanedFloatingLeaf(overlay);wasOwner&&remaining.length>0?this.floatingOverlays.set(remaining[0].id,overlay):remaining.length===0&&overlay.dispose(),group.isInFloatingSplit=!1,group.location==="floating"?group.fireLocationChanged():group.location="floating"}updateFloatingSplitState(overlay){if(!overlay.internalLayout)return;const groups=overlay.internalLayout.allGroups(),isInSplit=groups.length>1;for(const g of groups)g.location="floating",g.isInFloatingSplit=isInSplit;overlay.repositionToolbar()}cleanupOrphanedFloatingLeaf(overlay){if(!overlay.internalLayout)return[];const remaining=overlay.internalLayout.allGroups();return remaining.length<=1?(remaining.length===1&&(overlay.element.appendChild(remaining[0].element),remaining[0].isInFloatingSplit=!1),overlay.internalLayout.dispose(),overlay.internalLayout=null,remaining.length===1&&(overlay.setDragGroup(remaining[0]),remaining[0].location="floating",overlay.repositionToolbar())):this.updateFloatingSplitState(overlay),overlay.updateTotalTabCount(),remaining}minimizeDocked(group){const pos=this.layout.getGroupPosition(group);return this.layout.findGroupNode(group)&&this.layout.removeGroup(group),pos?{siblingGroupId:pos.siblingGroup.id,direction:pos.direction}:null}restoreDocked(group,position,initialSize,siblingGroupId){if(siblingGroupId){const sibling=this.groups.get(siblingGroupId);if(sibling&&this.layout.findGroupNode(sibling)&&this.layout.splitGroup(sibling,group,position,initialSize))return}const mainGroup=this.mainGroupId?this.groups.get(this.mainGroupId):void 0;mainGroup&&this.layout.splitGroup(mainGroup,group,position,initialSize)}findOverlayForGroup(group){const direct=this.floatingOverlays.get(group.id);if(direct)return direct;for(const overlay of this.floatingOverlays.values())if(overlay.internalLayout?.findGroupNode(group))return overlay;return null}registerPortal(panelId,element,anchor){const entry=document.createElement("div");entry.className="mb-iframe-portal",entry.dataset.portalId=panelId,this.portalLayer.appendChild(entry),entry.appendChild(element),this.portals.set(panelId,{entry,anchor})}unregisterPortal(panelId){const portal=this.portals.get(panelId);portal&&(portal.entry.remove(),this.portals.delete(panelId))}syncPortals(){if(this.disposed)return;const updates=[];for(const[,portal]of this.portals){const{entry,anchor}=portal;if(anchor.offsetParent===null)updates.push({entry,rect:null,zIndex:"0"});else{const overlay=anchor.closest(".mb-floating-overlay"),overlayZ=overlay?.style.zIndex;updates.push({entry,rect:anchor.getBoundingClientRect(),zIndex:String(overlay?parseInt(overlayZ||String(1e5+this.zBase),10)+1:50+this.zBase)})}}for(const{entry,rect,zIndex}of updates)rect?(entry.style.display="",entry.style.left=`${rect.left}px`,entry.style.top=`${rect.top}px`,entry.style.width=`${rect.width}px`,entry.style.height=`${rect.height}px`,entry.style.zIndex=zIndex):entry.style.display="none";this.portalRaf=requestAnimationFrame(()=>this.syncPortals())}}export{FloatingOverlay,Panel,PanelGroup,PanelManager,SplitLayout};
package/dist/styles.css CHANGED
@@ -31,6 +31,7 @@
31
31
  --_status-text: var(--mb-adapt-status-text, #374151);
32
32
  --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));
33
33
  --_border-radius: var(--mb-adapt-border-radius, 8px);
34
+ --_z-base: var(--mb-adapt-z-base, 0);
34
35
  --mb-adapt-responsive-breakpoint: 768;
35
36
  --mb-adapt-responsive-hysteresis: 40;
36
37
 
@@ -165,7 +166,7 @@
165
166
  background: var(--_fork-separator);
166
167
  transition: background 0.15s;
167
168
  position: relative;
168
- z-index: 1;
169
+ z-index: calc(1 + var(--_z-base));
169
170
  touch-action: none;
170
171
  }
171
172
 
@@ -349,7 +350,7 @@
349
350
  /* ── Floating overlay ────────────────────────────────── */
350
351
  .mb-floating-overlay {
351
352
  position: fixed;
352
- z-index: 100000;
353
+ z-index: calc(100000 + var(--_z-base));
353
354
  box-shadow: var(--_floating-shadow);
354
355
  border: var(--_floating-border);
355
356
  backdrop-filter: var(--_floating-backdrop);
@@ -400,7 +401,7 @@
400
401
  /* ── Resize handles ──────────────────────────────────── */
401
402
  .mb-resize-handle {
402
403
  position: absolute;
403
- z-index: 10;
404
+ z-index: calc(10 + var(--_z-base));
404
405
  touch-action: none;
405
406
  }
406
407
 
@@ -442,7 +443,7 @@
442
443
  display: flex;
443
444
  align-items: center;
444
445
  justify-content: center;
445
- z-index: 200000;
446
+ z-index: calc(200000 + var(--_z-base));
446
447
  background: transparent;
447
448
  pointer-events: none;
448
449
  }
@@ -515,7 +516,7 @@
515
516
  flex-direction: row;
516
517
  align-items: center;
517
518
  justify-content: center;
518
- z-index: 300000;
519
+ z-index: calc(300000 + var(--_z-base));
519
520
  background: rgba(0, 0, 0, 0.4);
520
521
  height: auto;
521
522
  min-height: 0;
@@ -592,7 +593,7 @@
592
593
  align-items: center;
593
594
  justify-content: center;
594
595
  pointer-events: none;
595
- z-index: 200000;
596
+ z-index: calc(200000 + var(--_z-base));
596
597
  }
597
598
 
598
599
  .mb-adapt-cap > * {
@@ -664,7 +665,7 @@ cap-widget::part(attribution) {
664
665
  display: none;
665
666
  height: var(--_toolbar-height);
666
667
  flex-shrink: 0;
667
- z-index: 100;
668
+ z-index: calc(100 + var(--_z-base));
668
669
  align-items: stretch;
669
670
  background: var(--_fork-tab-bg);
670
671
  border-bottom: 1px solid var(--_fork-separator);
@@ -737,7 +738,7 @@ cap-widget::part(attribution) {
737
738
  .mb-drag-ghost {
738
739
  position: fixed;
739
740
  pointer-events: none;
740
- z-index: 999999;
741
+ z-index: calc(999999 + var(--_z-base));
741
742
  padding: 4px 10px;
742
743
  background: var(--_fork-tab-bg);
743
744
  color: var(--_fork-tab-color);
@@ -767,7 +768,7 @@ cap-widget::part(attribution) {
767
768
  .mb-drop-overlay {
768
769
  position: fixed;
769
770
  pointer-events: none;
770
- z-index: 999998;
771
+ z-index: calc(999998 + var(--_z-base));
771
772
  display: none;
772
773
  box-sizing: border-box;
773
774
  border-radius: 6px;
@@ -1,5 +1,5 @@
1
1
  import type { AdaptTheme } from "./theme.js";
2
- import type { AdaptWebClientOptions, CapWidgetOptions, Output, PersistOptions, SignalValue, StatusJson, StatusText } from "./types.js";
2
+ import type { AdaptError, AdaptWebClientOptions, CapWidgetOptions, Output, PersistOptions, SignalValue, StatusJson, StatusText } from "./types.js";
3
3
  /**
4
4
  * `<adapt-automation>` custom element for embedding Adapt automations.
5
5
  *
@@ -42,6 +42,7 @@ export declare class AdaptAutomationElement extends BaseElement {
42
42
  onSessionCallback: ((status: StatusJson, fork?: string) => void) | undefined;
43
43
  onOutputCallback: ((output: Output) => void) | undefined;
44
44
  onForkActiveCallback: ((active: boolean) => void) | undefined;
45
+ onErrorCallback: ((error: AdaptError) => void) | undefined;
45
46
  get automationId(): string | null;
46
47
  set automationId(v: string | null);
47
48
  get darkMode(): boolean;
@@ -10,7 +10,7 @@
10
10
  * ```
11
11
  */
12
12
  export { AdaptWebClient as WebClient } from "./index.js";
13
- export type { AdaptTheme, AdaptWebClientOptions, CapWidgetI18n, CapWidgetOptions, ChallengeInfo, ForkDisplay, Output, PersistOptions, RedeemedChallenge, SignalValue, StatusJson, StatusText, } from "./types.js";
13
+ export type { AdaptError, AdaptErrorKind, AdaptTheme, AdaptWebClientOptions, CapWidgetI18n, CapWidgetOptions, ChallengeInfo, ForkDisplay, Output, PersistOptions, RedeemedChallenge, SignalValue, StatusJson, StatusText, } from "./types.js";
14
14
  export { resolveTheme } from "./theme.js";
15
15
  export type { SignalData } from "@mochabug/adapt-core";
16
16
  export { createConnectClient } from "@mochabug/adapt-core/connect";
@@ -1 +1 @@
1
- export declare const PANEL_MANAGER_CSS = "/* ==========================================================================\n Mochabug Adapt Web \u2014 Combined Styles\n Panel Manager CSS + Cap Widget CSS\n ========================================================================== */\n\n:root { --mb-adapt-styles-loaded: 1; }\n\n/* \u2500\u2500 Root \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: inherit;\n display: flex;\n flex-direction: column;\n\n /* Two-layer CSS variables: --_X reads user-set --mb-adapt-X first, falls back to light default */\n --_bg: var(--mb-adapt-bg, transparent);\n --_font: var(--mb-adapt-font, system-ui, -apple-system, sans-serif);\n --_button-hover-bg: var(--mb-adapt-button-hover-bg, rgba(128, 128, 128, 0.2));\n --_separator-active: var(--mb-adapt-separator-active, rgba(59, 130, 246, 0.5));\n --_floating-shadow: var(--mb-adapt-floating-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 12px 24px -8px rgba(0, 0, 0, 0.15));\n --_floating-border: var(--mb-adapt-floating-border, none);\n --_floating-backdrop: var(--mb-adapt-floating-backdrop, none);\n --_floating-radius: var(--mb-adapt-floating-radius, 8px);\n --_status-card-bg: var(--mb-adapt-status-card-bg, #ffffff);\n --_status-card-border: var(--mb-adapt-status-card-border, #e5e7eb);\n --_status-card-shadow: var(--mb-adapt-status-card-shadow, 0 4px 24px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04));\n --_status-icon-bg: var(--mb-adapt-status-icon-bg, #fef2f2);\n --_status-icon-stopped-bg: var(--mb-adapt-status-icon-stopped-bg, var(--mb-adapt-status-icon-bg, #f3f4f6));\n --_status-text: var(--mb-adapt-status-text, #374151);\n --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));\n --_border-radius: var(--mb-adapt-border-radius, 8px);\n --mb-adapt-responsive-breakpoint: 768;\n --mb-adapt-responsive-hysteresis: 40;\n\n /* Cap.js widget variables */\n --_cap-background: var(--mb-adapt-cap-background, #ffffff);\n --_cap-border-color: var(--mb-adapt-cap-border-color, #e2e8f0);\n --_cap-border-radius: var(--mb-adapt-cap-border-radius, 16px);\n --_cap-height: var(--mb-adapt-cap-height, 72px);\n --_cap-width: var(--mb-adapt-cap-width, 380px);\n --_cap-padding: var(--mb-adapt-cap-padding, 20px 28px);\n --_cap-gap: var(--mb-adapt-cap-gap, 20px);\n --_cap-color: var(--mb-adapt-cap-color, #1e293b);\n --_cap-checkbox-size: var(--mb-adapt-cap-checkbox-size, 36px);\n --_cap-checkbox-border: var(--mb-adapt-cap-checkbox-border, 2px solid #cbd5e1);\n --_cap-checkbox-radius: var(--mb-adapt-cap-checkbox-radius, 10px);\n --_cap-checkbox-background: var(--mb-adapt-cap-checkbox-background, #f8fafc);\n --_cap-spinner-color: var(--mb-adapt-cap-spinner-color, #6366f1);\n --_cap-spinner-bg: var(--mb-adapt-cap-spinner-bg, #e2e8f0);\n --_cap-font: var(--mb-adapt-cap-font, inherit);\n --_cap-spinner-thickness: var(--mb-adapt-cap-spinner-thickness, 3px);\n --_cap-shadow: var(--mb-adapt-cap-shadow, 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04));\n --_cap-shadow-hover: var(--mb-adapt-cap-shadow-hover, 0 8px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06));\n\n /* Fork panel theming */\n --_fork-bg: var(--mb-adapt-fork-bg, #ffffff);\n --_fork-tab-bg: var(--mb-adapt-fork-tab-bg, #f3f3f3);\n --_fork-tab-active-bg: var(--mb-adapt-fork-tab-active-bg, #ffffff);\n --_fork-tab-color: var(--mb-adapt-fork-tab-color, rgb(51, 51, 51));\n --_fork-tab-inactive-color: var(--mb-adapt-fork-tab-inactive-color, rgba(51, 51, 51, 0.7));\n --_fork-separator: var(--mb-adapt-fork-separator, rgba(128, 128, 128, 0.35));\n\n /* Tab shape */\n --_tab-radius: var(--mb-adapt-tab-radius, 0);\n --_tab-shadow: var(--mb-adapt-tab-shadow, none);\n --_tab-active-shadow: var(--mb-adapt-tab-active-shadow, none);\n --_tab-gap: var(--mb-adapt-tab-gap, 0px);\n --_tab-padding: var(--mb-adapt-tab-padding, 0 14px);\n --_tab-font-size: var(--mb-adapt-tab-font-size, 13px);\n --_tab-min-width: var(--mb-adapt-tab-min-width, 100px);\n --_tab-spacing: var(--mb-adapt-tab-spacing, 6px);\n --_toolbar-height: var(--mb-adapt-toolbar-height, 40px);\n --_toolbar-padding: var(--mb-adapt-toolbar-padding, 0);\n\n /* Drop targets \u2014 light defaults */\n --_drop-header-bg: var(--mb-adapt-drop-header-bg, rgba(99, 102, 241, 0.18));\n --_drop-center-bg: var(--mb-adapt-drop-center-bg, rgba(99, 102, 241, 0.12));\n --_drop-split-bg: var(--mb-adapt-drop-split-bg, rgba(99, 102, 241, 0.14));\n --_drop-border: var(--mb-adapt-drop-border, rgba(99, 102, 241, 0.55));\n\n background: var(--_bg);\n}\n\n.mb-adapt--dark {\n /* Cap.js widget dark mode */\n --_cap-background: var(--mb-adapt-cap-background, #1e293b);\n --_cap-border-color: var(--mb-adapt-cap-border-color, #334155);\n --_cap-color: var(--mb-adapt-cap-color, #f1f5f9);\n --_cap-checkbox-border: var(--mb-adapt-cap-checkbox-border, 2px solid #475569);\n --_cap-checkbox-background: var(--mb-adapt-cap-checkbox-background, #0f172a);\n --_cap-spinner-color: var(--mb-adapt-cap-spinner-color, #818cf8);\n --_cap-spinner-bg: var(--mb-adapt-cap-spinner-bg, #334155);\n --_cap-shadow: var(--mb-adapt-cap-shadow, 0 4px 20px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15));\n --_cap-shadow-hover: var(--mb-adapt-cap-shadow-hover, 0 8px 30px rgba(0, 0, 0, 0.35), 0 4px 12px rgba(0, 0, 0, 0.2));\n\n /* Status card dark mode */\n --_status-card-bg: var(--mb-adapt-status-card-bg, #1e293b);\n --_status-card-border: var(--mb-adapt-status-card-border, #334155);\n --_status-icon-bg: var(--mb-adapt-status-icon-bg, #351c1c);\n --_status-icon-stopped-bg: var(--mb-adapt-status-icon-stopped-bg, var(--mb-adapt-status-icon-bg, #1e293b));\n --_status-text: var(--mb-adapt-status-text, #e2e8f0);\n\n /* Panel dark mode overrides */\n --_button-hover-bg: var(--mb-adapt-button-hover-bg, rgba(128, 128, 128, 0.3));\n --_separator-active: var(--mb-adapt-separator-active, rgba(99, 130, 246, 0.6));\n --_floating-shadow: var(--mb-adapt-floating-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 12px 24px -8px rgba(0, 0, 0, 0.3));\n --_floating-border: var(--mb-adapt-floating-border, 1px solid rgba(255, 255, 255, 0.06));\n --_status-card-shadow: var(--mb-adapt-status-card-shadow, 0 4px 24px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15));\n --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.35));\n\n /* Fork panel dark mode */\n --_fork-bg: var(--mb-adapt-fork-bg, #1e1e1e);\n --_fork-tab-bg: var(--mb-adapt-fork-tab-bg, #252526);\n --_fork-tab-active-bg: var(--mb-adapt-fork-tab-active-bg, #1e1e1e);\n --_fork-tab-color: var(--mb-adapt-fork-tab-color, #ffffff);\n --_fork-tab-inactive-color: var(--mb-adapt-fork-tab-inactive-color, #969696);\n --_fork-separator: var(--mb-adapt-fork-separator, rgb(68, 68, 68));\n\n /* Drop target dark mode */\n --_drop-header-bg: var(--mb-adapt-drop-header-bg, rgba(129, 140, 248, 0.22));\n --_drop-center-bg: var(--mb-adapt-drop-center-bg, rgba(129, 140, 248, 0.15));\n --_drop-split-bg: var(--mb-adapt-drop-split-bg, rgba(129, 140, 248, 0.18));\n --_drop-border: var(--mb-adapt-drop-border, rgba(129, 140, 248, 0.6));\n}\n\n/* \u2500\u2500 Layout (recursive split tree) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-layout {\n flex: 1;\n min-height: 0;\n position: relative;\n display: flex;\n}\n\n.mb-split-container {\n display: flex;\n min-width: 0;\n min-height: 0;\n}\n\n.mb-split-horizontal { flex-direction: row; }\n.mb-split-vertical { flex-direction: column; }\n\n.mb-split-leaf {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n/* Animated flex transition \u2014 applied temporarily during dock/undock/maximize */\n.mb-split-leaf--animating {\n transition: flex 0.25s ease;\n}\n.mb-split-container--animating {\n transition: flex 0.25s ease;\n}\n.mb-layout-separator--animating {\n transition: opacity 0.25s ease;\n}\n\n/* Draggable separator between split panels */\n.mb-layout-separator {\n flex: 0 0 5px;\n background: var(--_fork-separator);\n transition: background 0.15s;\n position: relative;\n z-index: 1;\n touch-action: none;\n}\n\n.mb-layout-separator-v { cursor: col-resize; }\n.mb-layout-separator-h { cursor: row-resize; }\n\n.mb-layout-separator:hover,\n.mb-layout-separator--active {\n background: var(--_separator-active);\n}\n\n/* \u2500\u2500 Group \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-group {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--_bg);\n}\n\n.mb-group-header {\n display: flex;\n align-items: stretch;\n height: var(--_toolbar-height);\n min-height: var(--_toolbar-height);\n padding: var(--_toolbar-padding);\n background: var(--_fork-tab-bg);\n border-bottom: 1px solid var(--_fork-separator);\n user-select: none;\n}\n\n.mb-group-header-prefix {\n display: flex;\n align-items: stretch;\n}\n\n.mb-group-tabs {\n display: flex;\n align-items: stretch;\n overflow-x: auto;\n overflow-y: hidden;\n flex: 0 1 auto;\n min-width: 0;\n}\n\n.mb-group-tabs::-webkit-scrollbar {\n height: 2px;\n}\n\n/* Drag handle \u2014 fills remaining header space so the user can grab it */\n.mb-group-header-void {\n flex: 1;\n min-width: 40px;\n touch-action: none;\n}\n\n.mb-group-header-actions {\n display: flex;\n align-items: center;\n}\n\n.mb-group-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n background: var(--_fork-bg);\n}\n\n/* Main group overrides */\n.mb-group[data-main-group=\"true\"] {\n background: var(--_bg);\n}\n\n.mb-group[data-main-group=\"true\"] .mb-group-content {\n background: var(--_fork-bg);\n}\n\n\n/* \u2500\u2500 Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-tab {\n display: flex;\n align-items: center;\n gap: var(--_tab-spacing);\n padding: var(--_tab-padding);\n min-width: var(--_tab-min-width);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n cursor: pointer;\n touch-action: none;\n color: var(--_fork-tab-inactive-color);\n background: var(--_fork-tab-bg);\n border-right: 1px solid var(--_fork-separator);\n border-radius: var(--_tab-radius);\n box-shadow: var(--_tab-shadow);\n margin: var(--_tab-gap);\n transition: background 0.15s, box-shadow 0.15s;\n}\n\n.mb-tab[data-active=\"true\"] {\n color: var(--_fork-tab-color);\n background: var(--_fork-tab-active-bg);\n box-shadow: var(--_tab-active-shadow);\n}\n\n.mb-tab:hover {\n background: var(--_fork-tab-active-bg);\n}\n\n.mb-tab-label {\n display: flex;\n align-items: center;\n}\n\n.mb-tab-label svg {\n width: 14px;\n height: 14px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mb-tab[data-active=\"true\"] .mb-tab-label svg {\n opacity: 1;\n}\n\n.mb-tab-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n width: 40px;\n flex-shrink: 0;\n justify-content: flex-end;\n margin-left: auto;\n}\n\n.mb-tab-close {\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.15s, background 0.15s;\n}\n\n.mb-tab:hover .mb-tab-close {\n opacity: 0.7;\n}\n\n.mb-tab-close:hover {\n opacity: 1 !important;\n background: var(--_button-hover-bg);\n}\n\n.mb-tab-close svg {\n width: 12px;\n height: 12px;\n}\n\n/* \u2500\u2500 Panel visibility \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-panel {\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.mb-panel[data-active=\"false\"] {\n display: none;\n}\n\n.mb-panel[data-active=\"true\"] {\n display: block;\n}\n\n/* \u2500\u2500 Floating overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-floating-overlay {\n position: fixed;\n z-index: 100000;\n box-shadow: var(--_floating-shadow);\n border: var(--_floating-border);\n backdrop-filter: var(--_floating-backdrop);\n -webkit-backdrop-filter: var(--_floating-backdrop);\n border-radius: var(--_floating-radius);\n display: flex;\n flex-direction: column;\n /* No overflow:hidden here \u2014 resize handles use negative offsets (top:-3px etc.)\n and would be clipped. The inner .mb-group already has overflow:hidden for\n its own border-radius clipping. */\n}\n\n.mb-floating-overlay > .mb-group {\n flex: 1;\n border-radius: var(--_floating-radius);\n overflow: hidden;\n}\n\n/* Internal split layout inside a floating overlay */\n.mb-floating-overlay > .mb-layout {\n position: relative;\n inset: auto;\n height: auto;\n flex: 1;\n min-width: 0;\n min-height: 0;\n border-radius: var(--_floating-radius);\n overflow: hidden;\n}\n\n.mb-floating-maximized {\n border-radius: 0;\n box-shadow: none;\n}\n\n.mb-floating-maximized .mb-group {\n border-radius: 0;\n}\n\n.mb-floating-maximized .mb-resize-handle {\n display: none !important;\n}\n\n.mb-floating-maximized .mb-group-header-void {\n pointer-events: none;\n}\n\n/* \u2500\u2500 Resize handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-resize-handle {\n position: absolute;\n z-index: 10;\n touch-action: none;\n}\n\n.mb-resize-n { top: -3px; left: 8px; right: 8px; height: 6px; cursor: n-resize; }\n.mb-resize-s { bottom: -3px; left: 8px; right: 8px; height: 6px; cursor: s-resize; }\n.mb-resize-e { right: -3px; top: 8px; bottom: 8px; width: 6px; cursor: e-resize; }\n.mb-resize-w { left: -3px; top: 8px; bottom: 8px; width: 6px; cursor: w-resize; }\n.mb-resize-ne { top: -3px; right: -3px; width: 12px; height: 12px; cursor: ne-resize; }\n.mb-resize-nw { top: -3px; left: -3px; width: 12px; height: 12px; cursor: nw-resize; }\n.mb-resize-se { bottom: -3px; right: -3px; width: 12px; height: 12px; cursor: se-resize; }\n.mb-resize-sw { bottom: -3px; left: -3px; width: 12px; height: 12px; cursor: sw-resize; }\n\n/* \u2500\u2500 Iframe styling \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt__iframe {\n width: 100%;\n height: 100%;\n min-height: 0;\n border: 0;\n display: block;\n background: transparent;\n border-radius: var(--_border-radius);\n pointer-events: auto;\n opacity: 0;\n transition: opacity 0.1s ease-out;\n}\n\n.mb-adapt__iframe--visible {\n opacity: 1;\n}\n\n.mb-adapt__iframe--hidden {\n display: none;\n}\n\n/* \u2500\u2500 Status message overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt__status-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 200000;\n background: transparent;\n pointer-events: none;\n}\n\n.mb-adapt__status-card {\n pointer-events: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n padding: 32px 40px;\n max-width: 380px;\n border-radius: 16px;\n background: var(--_status-card-bg);\n border: 1px solid var(--_status-card-border);\n box-shadow: var(--_status-card-shadow);\n font-family: var(--_font);\n text-align: center;\n}\n\n.mb-adapt__status-icon {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--_status-icon-bg);\n}\n\n.mb-adapt__status-icon svg {\n width: 24px;\n height: 24px;\n}\n\n.mb-adapt__status-icon--stopped {\n background: var(--_status-icon-stopped-bg);\n}\n\n.mb-adapt__status-text {\n color: var(--_status-text);\n font-size: 15px;\n line-height: 1.5;\n margin: 0;\n}\n\n.mb-adapt__status-restart {\n padding: 8px 20px;\n border: 1px solid var(--_status-card-border);\n border-radius: 8px;\n background: transparent;\n color: var(--_status-text);\n font-size: 14px;\n font-weight: 500;\n font-family: var(--_font);\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.mb-adapt__status-restart:hover {\n background: var(--_status-card-border);\n}\n\n/* \u2500\u2500 Confirm-on-close dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mb-adapt__confirm-overlay {\n position: fixed;\n inset: 0;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n z-index: 300000;\n background: rgba(0, 0, 0, 0.4);\n height: auto;\n min-height: 0;\n}\n\n.mb-adapt--dark.mb-adapt__confirm-overlay {\n background: rgba(0, 0, 0, 0.55);\n}\n\n.mb-adapt__confirm-card {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 16px;\n padding: 24px 28px;\n max-width: 360px;\n width: 100%;\n border-radius: var(--_floating-radius);\n background: var(--_fork-tab-active-bg);\n border: 1px solid var(--_fork-separator);\n box-shadow: var(--_floating-shadow);\n font-family: var(--_font);\n text-align: center;\n}\n\n.mb-adapt__confirm-text {\n font-size: 14px;\n line-height: 1.5;\n color: var(--_fork-tab-color);\n margin: 0;\n}\n\n.mb-adapt__confirm-buttons {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.mb-adapt__confirm-btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 13px;\n font-family: var(--_font);\n cursor: pointer;\n font-weight: 500;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.mb-adapt__confirm-btn--cancel {\n background: transparent;\n border: 1px solid var(--_fork-separator);\n color: var(--_fork-tab-color);\n}\n\n.mb-adapt__confirm-btn--cancel:hover {\n background: var(--_button-hover-bg);\n}\n\n.mb-adapt__confirm-btn--confirm {\n background: var(--_fork-tab-color);\n color: var(--_fork-tab-active-bg);\n border: 1px solid transparent;\n}\n\n.mb-adapt__confirm-btn--confirm:hover {\n opacity: 0.85;\n}\n\n/* \u2500\u2500 Cap.js widget positioning \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt-cap {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n z-index: 200000;\n}\n\n.mb-adapt-cap > * {\n pointer-events: auto;\n}\n\n/* Cap.js widget styling */\n.mb-adapt cap-widget {\n --cap-background: var(--_cap-background);\n --cap-border-color: var(--_cap-border-color);\n --cap-border-radius: var(--_cap-border-radius);\n --cap-widget-height: var(--_cap-height);\n --cap-widget-width: var(--_cap-width);\n --cap-widget-padding: var(--_cap-padding);\n --cap-gap: var(--_cap-gap);\n --cap-color: var(--_cap-color);\n --cap-checkbox-size: var(--_cap-checkbox-size);\n --cap-checkbox-border: var(--_cap-checkbox-border);\n --cap-checkbox-border-radius: var(--_cap-checkbox-radius);\n --cap-checkbox-background: var(--_cap-checkbox-background);\n --cap-checkbox-margin: 0;\n --cap-font: var(--_cap-font);\n --cap-spinner-color: var(--_cap-spinner-color);\n --cap-spinner-background-color: var(--_cap-spinner-bg);\n --cap-spinner-thickness: var(--_cap-spinner-thickness);\n}\n\n/* Hide Cap.js credits */\ncap-widget::part(attribution) {\n display: none;\n}\n\n/* \u2500\u2500 Fork group action buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt-fork-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n padding-right: 4px;\n}\n.mb-adapt-fork-actions button {\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--_fork-tab-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0.7;\n transition: opacity 0.15s, background 0.15s;\n}\n.mb-adapt-fork-actions button:hover {\n opacity: 1;\n background: var(--_button-hover-bg);\n}\n.mb-adapt-fork-actions button svg {\n width: 14px;\n height: 14px;\n}\n\n/* \u2500\u2500 Minimized-group tabs bar (at the top, NOT an overlay) \u2500\u2500\u2500 */\n/* Sits at the top of .mb-adapt as a normal flow element so the layout\n underneath shrinks to accommodate it. This prevents scrollbars when\n docked panels are minimized \u2014 the iframe gets the remaining height. */\n.mb-adapt-minimized-tabs {\n display: none;\n height: var(--_toolbar-height);\n flex-shrink: 0;\n z-index: 100;\n align-items: stretch;\n background: var(--_fork-tab-bg);\n border-bottom: 1px solid var(--_fork-separator);\n user-select: none;\n}\n.mb-adapt-minimized-tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0 12px;\n flex: 1;\n background: var(--_fork-tab-bg);\n color: var(--_fork-tab-color);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n border-right: 1px solid var(--_fork-separator);\n cursor: default;\n}\n.mb-adapt-minimized-tab-label {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.mb-adapt-minimized-tab-label svg {\n width: 14px;\n height: 14px;\n opacity: 0.8;\n flex-shrink: 0;\n}\n.mb-adapt-minimized-tab-action {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0.6;\n transition: opacity 0.15s, background 0.15s;\n}\n.mb-adapt-minimized-tab-action:hover {\n opacity: 1;\n background: var(--_button-hover-bg);\n}\n.mb-adapt-minimized-tab-action svg {\n width: 14px;\n height: 14px;\n}\n\n/* Minimized tab drag handle cursor */\n.mb-adapt-minimized-tab {\n cursor: grab;\n touch-action: none;\n}\n\n/* Drop target highlight for minimized tab merge */\n.mb-adapt-minimized-tab--drop-target {\n background: var(--_drop-header-bg) !important;\n box-shadow: inset 0 0 0 2px var(--_drop-border);\n}\n\n/* \u2500\u2500 Pointer-drag ghost element \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-drag-ghost {\n position: fixed;\n pointer-events: none;\n z-index: 999999;\n padding: 4px 10px;\n background: var(--_fork-tab-bg);\n color: var(--_fork-tab-color);\n border: 1px solid var(--_fork-separator);\n border-radius: var(--_tab-radius, 4px);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n box-shadow: var(--_drag-ghost-shadow);\n opacity: 0.92;\n display: flex;\n align-items: center;\n}\n\n.mb-drag-ghost svg {\n width: 16px;\n height: 16px;\n}\n\n/* \u2500\u2500 Drop target highlight on group header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-group-header--drop-target {\n background: var(--_drop-header-bg) !important;\n box-shadow: inset 0 0 0 2px var(--_drop-border);\n}\n\n/* \u2500\u2500 Drop overlay (content-area and dock-strip indicators) */\n.mb-drop-overlay {\n position: fixed;\n pointer-events: none;\n z-index: 999998;\n display: none;\n box-sizing: border-box;\n border-radius: 6px;\n transition: opacity 0.1s ease-out;\n}\n\n.mb-drop-overlay[data-zone=\"center\"] {\n background: var(--_drop-center-bg);\n border: 2px solid var(--_drop-border);\n}\n\n.mb-drop-overlay[data-zone=\"top\"],\n.mb-drop-overlay[data-zone=\"bottom\"],\n.mb-drop-overlay[data-zone=\"left\"],\n.mb-drop-overlay[data-zone=\"right\"] {\n background: var(--_drop-split-bg);\n border: 2px solid var(--_drop-border);\n}\n\n/* \u2500\u2500 Iframe pointer-event guard during drag \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nhtml.mb-dragging iframe,\nhtml.mb-dragging webview {\n pointer-events: none !important;\n}\n\n/* \u2500\u2500 Tab pop-out button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-tab-popout {\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.15s, background 0.15s;\n}\n\n.mb-tab:hover .mb-tab-popout {\n opacity: 0.7;\n}\n\n.mb-tab-popout:hover {\n opacity: 1 !important;\n background: var(--_button-hover-bg);\n}\n\n.mb-tab-popout svg {\n width: 12px;\n height: 12px;\n}\n\n/* Hide pop-out button on main group (never floats), when overlay\n has 0 or 1 total tabs (nothing to pop out), and when floating is disallowed. */\n.mb-group[data-main-group=\"true\"] .mb-tab-popout,\n.mb-floating-overlay[data-total-tab-count=\"0\"] .mb-tab-popout,\n.mb-floating-overlay[data-total-tab-count=\"1\"] .mb-tab-popout,\n.mb-group[data-allow-floating=\"false\"] .mb-tab-popout {\n display: none !important;\n}\n\n\n/* \u2500\u2500 Iframe portal layer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* MUST NOT create a stacking context \u2014 portal entries' z-indexes\n must compete with floating overlays in the parent stacking context.\n position: absolute + no z-index achieves this. */\n.mb-iframe-portal-layer {\n position: absolute;\n width: 0;\n height: 0;\n overflow: visible;\n pointer-events: none;\n}\n.mb-iframe-portal {\n position: fixed;\n pointer-events: auto;\n overflow: hidden;\n}\n\n/* \u2500\u2500 Touch device adjustments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n@media (hover: none) {\n .mb-tab-close {\n opacity: 0.5;\n }\n\n .mb-tab-popout {\n opacity: 0.5;\n }\n\n .mb-tab:hover .mb-tab-close,\n .mb-tab:hover .mb-tab-popout {\n opacity: 0.7;\n }\n}\n\n@media (pointer: coarse) {\n .mb-tab-close,\n .mb-tab-popout {\n width: 24px;\n height: 24px;\n }\n\n .mb-adapt-fork-actions button {\n width: 26px;\n height: 26px;\n }\n\n .mb-adapt-minimized-tab-action {\n width: 28px;\n height: 28px;\n }\n}";
1
+ export declare const PANEL_MANAGER_CSS = "/* ==========================================================================\n Mochabug Adapt Web \u2014 Combined Styles\n Panel Manager CSS + Cap Widget CSS\n ========================================================================== */\n\n:root { --mb-adapt-styles-loaded: 1; }\n\n/* \u2500\u2500 Root \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt {\n position: relative;\n width: 100%;\n height: 100%;\n min-height: inherit;\n display: flex;\n flex-direction: column;\n\n /* Two-layer CSS variables: --_X reads user-set --mb-adapt-X first, falls back to light default */\n --_bg: var(--mb-adapt-bg, transparent);\n --_font: var(--mb-adapt-font, system-ui, -apple-system, sans-serif);\n --_button-hover-bg: var(--mb-adapt-button-hover-bg, rgba(128, 128, 128, 0.2));\n --_separator-active: var(--mb-adapt-separator-active, rgba(59, 130, 246, 0.5));\n --_floating-shadow: var(--mb-adapt-floating-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.25), 0 12px 24px -8px rgba(0, 0, 0, 0.15));\n --_floating-border: var(--mb-adapt-floating-border, none);\n --_floating-backdrop: var(--mb-adapt-floating-backdrop, none);\n --_floating-radius: var(--mb-adapt-floating-radius, 8px);\n --_status-card-bg: var(--mb-adapt-status-card-bg, #ffffff);\n --_status-card-border: var(--mb-adapt-status-card-border, #e5e7eb);\n --_status-card-shadow: var(--mb-adapt-status-card-shadow, 0 4px 24px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04));\n --_status-icon-bg: var(--mb-adapt-status-icon-bg, #fef2f2);\n --_status-icon-stopped-bg: var(--mb-adapt-status-icon-stopped-bg, var(--mb-adapt-status-icon-bg, #f3f4f6));\n --_status-text: var(--mb-adapt-status-text, #374151);\n --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.15));\n --_border-radius: var(--mb-adapt-border-radius, 8px);\n --_z-base: var(--mb-adapt-z-base, 0);\n --mb-adapt-responsive-breakpoint: 768;\n --mb-adapt-responsive-hysteresis: 40;\n\n /* Cap.js widget variables */\n --_cap-background: var(--mb-adapt-cap-background, #ffffff);\n --_cap-border-color: var(--mb-adapt-cap-border-color, #e2e8f0);\n --_cap-border-radius: var(--mb-adapt-cap-border-radius, 16px);\n --_cap-height: var(--mb-adapt-cap-height, 72px);\n --_cap-width: var(--mb-adapt-cap-width, 380px);\n --_cap-padding: var(--mb-adapt-cap-padding, 20px 28px);\n --_cap-gap: var(--mb-adapt-cap-gap, 20px);\n --_cap-color: var(--mb-adapt-cap-color, #1e293b);\n --_cap-checkbox-size: var(--mb-adapt-cap-checkbox-size, 36px);\n --_cap-checkbox-border: var(--mb-adapt-cap-checkbox-border, 2px solid #cbd5e1);\n --_cap-checkbox-radius: var(--mb-adapt-cap-checkbox-radius, 10px);\n --_cap-checkbox-background: var(--mb-adapt-cap-checkbox-background, #f8fafc);\n --_cap-spinner-color: var(--mb-adapt-cap-spinner-color, #6366f1);\n --_cap-spinner-bg: var(--mb-adapt-cap-spinner-bg, #e2e8f0);\n --_cap-font: var(--mb-adapt-cap-font, inherit);\n --_cap-spinner-thickness: var(--mb-adapt-cap-spinner-thickness, 3px);\n --_cap-shadow: var(--mb-adapt-cap-shadow, 0 4px 20px rgba(0, 0, 0, 0.08), 0 2px 8px rgba(0, 0, 0, 0.04));\n --_cap-shadow-hover: var(--mb-adapt-cap-shadow-hover, 0 8px 30px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.06));\n\n /* Fork panel theming */\n --_fork-bg: var(--mb-adapt-fork-bg, #ffffff);\n --_fork-tab-bg: var(--mb-adapt-fork-tab-bg, #f3f3f3);\n --_fork-tab-active-bg: var(--mb-adapt-fork-tab-active-bg, #ffffff);\n --_fork-tab-color: var(--mb-adapt-fork-tab-color, rgb(51, 51, 51));\n --_fork-tab-inactive-color: var(--mb-adapt-fork-tab-inactive-color, rgba(51, 51, 51, 0.7));\n --_fork-separator: var(--mb-adapt-fork-separator, rgba(128, 128, 128, 0.35));\n\n /* Tab shape */\n --_tab-radius: var(--mb-adapt-tab-radius, 0);\n --_tab-shadow: var(--mb-adapt-tab-shadow, none);\n --_tab-active-shadow: var(--mb-adapt-tab-active-shadow, none);\n --_tab-gap: var(--mb-adapt-tab-gap, 0px);\n --_tab-padding: var(--mb-adapt-tab-padding, 0 14px);\n --_tab-font-size: var(--mb-adapt-tab-font-size, 13px);\n --_tab-min-width: var(--mb-adapt-tab-min-width, 100px);\n --_tab-spacing: var(--mb-adapt-tab-spacing, 6px);\n --_toolbar-height: var(--mb-adapt-toolbar-height, 40px);\n --_toolbar-padding: var(--mb-adapt-toolbar-padding, 0);\n\n /* Drop targets \u2014 light defaults */\n --_drop-header-bg: var(--mb-adapt-drop-header-bg, rgba(99, 102, 241, 0.18));\n --_drop-center-bg: var(--mb-adapt-drop-center-bg, rgba(99, 102, 241, 0.12));\n --_drop-split-bg: var(--mb-adapt-drop-split-bg, rgba(99, 102, 241, 0.14));\n --_drop-border: var(--mb-adapt-drop-border, rgba(99, 102, 241, 0.55));\n\n background: var(--_bg);\n}\n\n.mb-adapt--dark {\n /* Cap.js widget dark mode */\n --_cap-background: var(--mb-adapt-cap-background, #1e293b);\n --_cap-border-color: var(--mb-adapt-cap-border-color, #334155);\n --_cap-color: var(--mb-adapt-cap-color, #f1f5f9);\n --_cap-checkbox-border: var(--mb-adapt-cap-checkbox-border, 2px solid #475569);\n --_cap-checkbox-background: var(--mb-adapt-cap-checkbox-background, #0f172a);\n --_cap-spinner-color: var(--mb-adapt-cap-spinner-color, #818cf8);\n --_cap-spinner-bg: var(--mb-adapt-cap-spinner-bg, #334155);\n --_cap-shadow: var(--mb-adapt-cap-shadow, 0 4px 20px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15));\n --_cap-shadow-hover: var(--mb-adapt-cap-shadow-hover, 0 8px 30px rgba(0, 0, 0, 0.35), 0 4px 12px rgba(0, 0, 0, 0.2));\n\n /* Status card dark mode */\n --_status-card-bg: var(--mb-adapt-status-card-bg, #1e293b);\n --_status-card-border: var(--mb-adapt-status-card-border, #334155);\n --_status-icon-bg: var(--mb-adapt-status-icon-bg, #351c1c);\n --_status-icon-stopped-bg: var(--mb-adapt-status-icon-stopped-bg, var(--mb-adapt-status-icon-bg, #1e293b));\n --_status-text: var(--mb-adapt-status-text, #e2e8f0);\n\n /* Panel dark mode overrides */\n --_button-hover-bg: var(--mb-adapt-button-hover-bg, rgba(128, 128, 128, 0.3));\n --_separator-active: var(--mb-adapt-separator-active, rgba(99, 130, 246, 0.6));\n --_floating-shadow: var(--mb-adapt-floating-shadow, 0 25px 50px -12px rgba(0, 0, 0, 0.5), 0 12px 24px -8px rgba(0, 0, 0, 0.3));\n --_floating-border: var(--mb-adapt-floating-border, 1px solid rgba(255, 255, 255, 0.06));\n --_status-card-shadow: var(--mb-adapt-status-card-shadow, 0 4px 24px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.15));\n --_drag-ghost-shadow: var(--mb-adapt-drag-ghost-shadow, 0 4px 12px rgba(0, 0, 0, 0.35));\n\n /* Fork panel dark mode */\n --_fork-bg: var(--mb-adapt-fork-bg, #1e1e1e);\n --_fork-tab-bg: var(--mb-adapt-fork-tab-bg, #252526);\n --_fork-tab-active-bg: var(--mb-adapt-fork-tab-active-bg, #1e1e1e);\n --_fork-tab-color: var(--mb-adapt-fork-tab-color, #ffffff);\n --_fork-tab-inactive-color: var(--mb-adapt-fork-tab-inactive-color, #969696);\n --_fork-separator: var(--mb-adapt-fork-separator, rgb(68, 68, 68));\n\n /* Drop target dark mode */\n --_drop-header-bg: var(--mb-adapt-drop-header-bg, rgba(129, 140, 248, 0.22));\n --_drop-center-bg: var(--mb-adapt-drop-center-bg, rgba(129, 140, 248, 0.15));\n --_drop-split-bg: var(--mb-adapt-drop-split-bg, rgba(129, 140, 248, 0.18));\n --_drop-border: var(--mb-adapt-drop-border, rgba(129, 140, 248, 0.6));\n}\n\n/* \u2500\u2500 Layout (recursive split tree) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-layout {\n flex: 1;\n min-height: 0;\n position: relative;\n display: flex;\n}\n\n.mb-split-container {\n display: flex;\n min-width: 0;\n min-height: 0;\n}\n\n.mb-split-horizontal { flex-direction: row; }\n.mb-split-vertical { flex-direction: column; }\n\n.mb-split-leaf {\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n/* Animated flex transition \u2014 applied temporarily during dock/undock/maximize */\n.mb-split-leaf--animating {\n transition: flex 0.25s ease;\n}\n.mb-split-container--animating {\n transition: flex 0.25s ease;\n}\n.mb-layout-separator--animating {\n transition: opacity 0.25s ease;\n}\n\n/* Draggable separator between split panels */\n.mb-layout-separator {\n flex: 0 0 5px;\n background: var(--_fork-separator);\n transition: background 0.15s;\n position: relative;\n z-index: calc(1 + var(--_z-base));\n touch-action: none;\n}\n\n.mb-layout-separator-v { cursor: col-resize; }\n.mb-layout-separator-h { cursor: row-resize; }\n\n.mb-layout-separator:hover,\n.mb-layout-separator--active {\n background: var(--_separator-active);\n}\n\n/* \u2500\u2500 Group \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-group {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--_bg);\n}\n\n.mb-group-header {\n display: flex;\n align-items: stretch;\n height: var(--_toolbar-height);\n min-height: var(--_toolbar-height);\n padding: var(--_toolbar-padding);\n background: var(--_fork-tab-bg);\n border-bottom: 1px solid var(--_fork-separator);\n user-select: none;\n}\n\n.mb-group-header-prefix {\n display: flex;\n align-items: stretch;\n}\n\n.mb-group-tabs {\n display: flex;\n align-items: stretch;\n overflow-x: auto;\n overflow-y: hidden;\n flex: 0 1 auto;\n min-width: 0;\n}\n\n.mb-group-tabs::-webkit-scrollbar {\n height: 2px;\n}\n\n/* Drag handle \u2014 fills remaining header space so the user can grab it */\n.mb-group-header-void {\n flex: 1;\n min-width: 40px;\n touch-action: none;\n}\n\n.mb-group-header-actions {\n display: flex;\n align-items: center;\n}\n\n.mb-group-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n background: var(--_fork-bg);\n}\n\n/* Main group overrides */\n.mb-group[data-main-group=\"true\"] {\n background: var(--_bg);\n}\n\n.mb-group[data-main-group=\"true\"] .mb-group-content {\n background: var(--_fork-bg);\n}\n\n\n/* \u2500\u2500 Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-tab {\n display: flex;\n align-items: center;\n gap: var(--_tab-spacing);\n padding: var(--_tab-padding);\n min-width: var(--_tab-min-width);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n cursor: pointer;\n touch-action: none;\n color: var(--_fork-tab-inactive-color);\n background: var(--_fork-tab-bg);\n border-right: 1px solid var(--_fork-separator);\n border-radius: var(--_tab-radius);\n box-shadow: var(--_tab-shadow);\n margin: var(--_tab-gap);\n transition: background 0.15s, box-shadow 0.15s;\n}\n\n.mb-tab[data-active=\"true\"] {\n color: var(--_fork-tab-color);\n background: var(--_fork-tab-active-bg);\n box-shadow: var(--_tab-active-shadow);\n}\n\n.mb-tab:hover {\n background: var(--_fork-tab-active-bg);\n}\n\n.mb-tab-label {\n display: flex;\n align-items: center;\n}\n\n.mb-tab-label svg {\n width: 14px;\n height: 14px;\n opacity: 0.7;\n flex-shrink: 0;\n}\n\n.mb-tab[data-active=\"true\"] .mb-tab-label svg {\n opacity: 1;\n}\n\n.mb-tab-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n width: 40px;\n flex-shrink: 0;\n justify-content: flex-end;\n margin-left: auto;\n}\n\n.mb-tab-close {\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.15s, background 0.15s;\n}\n\n.mb-tab:hover .mb-tab-close {\n opacity: 0.7;\n}\n\n.mb-tab-close:hover {\n opacity: 1 !important;\n background: var(--_button-hover-bg);\n}\n\n.mb-tab-close svg {\n width: 12px;\n height: 12px;\n}\n\n/* \u2500\u2500 Panel visibility \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-panel {\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.mb-panel[data-active=\"false\"] {\n display: none;\n}\n\n.mb-panel[data-active=\"true\"] {\n display: block;\n}\n\n/* \u2500\u2500 Floating overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-floating-overlay {\n position: fixed;\n z-index: calc(100000 + var(--_z-base));\n box-shadow: var(--_floating-shadow);\n border: var(--_floating-border);\n backdrop-filter: var(--_floating-backdrop);\n -webkit-backdrop-filter: var(--_floating-backdrop);\n border-radius: var(--_floating-radius);\n display: flex;\n flex-direction: column;\n /* No overflow:hidden here \u2014 resize handles use negative offsets (top:-3px etc.)\n and would be clipped. The inner .mb-group already has overflow:hidden for\n its own border-radius clipping. */\n}\n\n.mb-floating-overlay > .mb-group {\n flex: 1;\n border-radius: var(--_floating-radius);\n overflow: hidden;\n}\n\n/* Internal split layout inside a floating overlay */\n.mb-floating-overlay > .mb-layout {\n position: relative;\n inset: auto;\n height: auto;\n flex: 1;\n min-width: 0;\n min-height: 0;\n border-radius: var(--_floating-radius);\n overflow: hidden;\n}\n\n.mb-floating-maximized {\n border-radius: 0;\n box-shadow: none;\n}\n\n.mb-floating-maximized .mb-group {\n border-radius: 0;\n}\n\n.mb-floating-maximized .mb-resize-handle {\n display: none !important;\n}\n\n.mb-floating-maximized .mb-group-header-void {\n pointer-events: none;\n}\n\n/* \u2500\u2500 Resize handles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-resize-handle {\n position: absolute;\n z-index: calc(10 + var(--_z-base));\n touch-action: none;\n}\n\n.mb-resize-n { top: -3px; left: 8px; right: 8px; height: 6px; cursor: n-resize; }\n.mb-resize-s { bottom: -3px; left: 8px; right: 8px; height: 6px; cursor: s-resize; }\n.mb-resize-e { right: -3px; top: 8px; bottom: 8px; width: 6px; cursor: e-resize; }\n.mb-resize-w { left: -3px; top: 8px; bottom: 8px; width: 6px; cursor: w-resize; }\n.mb-resize-ne { top: -3px; right: -3px; width: 12px; height: 12px; cursor: ne-resize; }\n.mb-resize-nw { top: -3px; left: -3px; width: 12px; height: 12px; cursor: nw-resize; }\n.mb-resize-se { bottom: -3px; right: -3px; width: 12px; height: 12px; cursor: se-resize; }\n.mb-resize-sw { bottom: -3px; left: -3px; width: 12px; height: 12px; cursor: sw-resize; }\n\n/* \u2500\u2500 Iframe styling \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt__iframe {\n width: 100%;\n height: 100%;\n min-height: 0;\n border: 0;\n display: block;\n background: transparent;\n border-radius: var(--_border-radius);\n pointer-events: auto;\n opacity: 0;\n transition: opacity 0.1s ease-out;\n}\n\n.mb-adapt__iframe--visible {\n opacity: 1;\n}\n\n.mb-adapt__iframe--hidden {\n display: none;\n}\n\n/* \u2500\u2500 Status message overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt__status-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: calc(200000 + var(--_z-base));\n background: transparent;\n pointer-events: none;\n}\n\n.mb-adapt__status-card {\n pointer-events: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n padding: 32px 40px;\n max-width: 380px;\n border-radius: 16px;\n background: var(--_status-card-bg);\n border: 1px solid var(--_status-card-border);\n box-shadow: var(--_status-card-shadow);\n font-family: var(--_font);\n text-align: center;\n}\n\n.mb-adapt__status-icon {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--_status-icon-bg);\n}\n\n.mb-adapt__status-icon svg {\n width: 24px;\n height: 24px;\n}\n\n.mb-adapt__status-icon--stopped {\n background: var(--_status-icon-stopped-bg);\n}\n\n.mb-adapt__status-text {\n color: var(--_status-text);\n font-size: 15px;\n line-height: 1.5;\n margin: 0;\n}\n\n.mb-adapt__status-restart {\n padding: 8px 20px;\n border: 1px solid var(--_status-card-border);\n border-radius: 8px;\n background: transparent;\n color: var(--_status-text);\n font-size: 14px;\n font-weight: 500;\n font-family: var(--_font);\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.mb-adapt__status-restart:hover {\n background: var(--_status-card-border);\n}\n\n/* \u2500\u2500 Confirm-on-close dialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.mb-adapt__confirm-overlay {\n position: fixed;\n inset: 0;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n z-index: calc(300000 + var(--_z-base));\n background: rgba(0, 0, 0, 0.4);\n height: auto;\n min-height: 0;\n}\n\n.mb-adapt--dark.mb-adapt__confirm-overlay {\n background: rgba(0, 0, 0, 0.55);\n}\n\n.mb-adapt__confirm-card {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 16px;\n padding: 24px 28px;\n max-width: 360px;\n width: 100%;\n border-radius: var(--_floating-radius);\n background: var(--_fork-tab-active-bg);\n border: 1px solid var(--_fork-separator);\n box-shadow: var(--_floating-shadow);\n font-family: var(--_font);\n text-align: center;\n}\n\n.mb-adapt__confirm-text {\n font-size: 14px;\n line-height: 1.5;\n color: var(--_fork-tab-color);\n margin: 0;\n}\n\n.mb-adapt__confirm-buttons {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.mb-adapt__confirm-btn {\n padding: 8px 16px;\n border-radius: 6px;\n font-size: 13px;\n font-family: var(--_font);\n cursor: pointer;\n font-weight: 500;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.mb-adapt__confirm-btn--cancel {\n background: transparent;\n border: 1px solid var(--_fork-separator);\n color: var(--_fork-tab-color);\n}\n\n.mb-adapt__confirm-btn--cancel:hover {\n background: var(--_button-hover-bg);\n}\n\n.mb-adapt__confirm-btn--confirm {\n background: var(--_fork-tab-color);\n color: var(--_fork-tab-active-bg);\n border: 1px solid transparent;\n}\n\n.mb-adapt__confirm-btn--confirm:hover {\n opacity: 0.85;\n}\n\n/* \u2500\u2500 Cap.js widget positioning \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt-cap {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n z-index: calc(200000 + var(--_z-base));\n}\n\n.mb-adapt-cap > * {\n pointer-events: auto;\n}\n\n/* Cap.js widget styling */\n.mb-adapt cap-widget {\n --cap-background: var(--_cap-background);\n --cap-border-color: var(--_cap-border-color);\n --cap-border-radius: var(--_cap-border-radius);\n --cap-widget-height: var(--_cap-height);\n --cap-widget-width: var(--_cap-width);\n --cap-widget-padding: var(--_cap-padding);\n --cap-gap: var(--_cap-gap);\n --cap-color: var(--_cap-color);\n --cap-checkbox-size: var(--_cap-checkbox-size);\n --cap-checkbox-border: var(--_cap-checkbox-border);\n --cap-checkbox-border-radius: var(--_cap-checkbox-radius);\n --cap-checkbox-background: var(--_cap-checkbox-background);\n --cap-checkbox-margin: 0;\n --cap-font: var(--_cap-font);\n --cap-spinner-color: var(--_cap-spinner-color);\n --cap-spinner-background-color: var(--_cap-spinner-bg);\n --cap-spinner-thickness: var(--_cap-spinner-thickness);\n}\n\n/* Hide Cap.js credits */\ncap-widget::part(attribution) {\n display: none;\n}\n\n/* \u2500\u2500 Fork group action buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-adapt-fork-actions {\n display: flex;\n align-items: center;\n gap: 2px;\n padding-right: 4px;\n}\n.mb-adapt-fork-actions button {\n width: 20px;\n height: 20px;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--_fork-tab-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0.7;\n transition: opacity 0.15s, background 0.15s;\n}\n.mb-adapt-fork-actions button:hover {\n opacity: 1;\n background: var(--_button-hover-bg);\n}\n.mb-adapt-fork-actions button svg {\n width: 14px;\n height: 14px;\n}\n\n/* \u2500\u2500 Minimized-group tabs bar (at the top, NOT an overlay) \u2500\u2500\u2500 */\n/* Sits at the top of .mb-adapt as a normal flow element so the layout\n underneath shrinks to accommodate it. This prevents scrollbars when\n docked panels are minimized \u2014 the iframe gets the remaining height. */\n.mb-adapt-minimized-tabs {\n display: none;\n height: var(--_toolbar-height);\n flex-shrink: 0;\n z-index: calc(100 + var(--_z-base));\n align-items: stretch;\n background: var(--_fork-tab-bg);\n border-bottom: 1px solid var(--_fork-separator);\n user-select: none;\n}\n.mb-adapt-minimized-tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0 12px;\n flex: 1;\n background: var(--_fork-tab-bg);\n color: var(--_fork-tab-color);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n border-right: 1px solid var(--_fork-separator);\n cursor: default;\n}\n.mb-adapt-minimized-tab-label {\n flex: 1;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.mb-adapt-minimized-tab-label svg {\n width: 14px;\n height: 14px;\n opacity: 0.8;\n flex-shrink: 0;\n}\n.mb-adapt-minimized-tab-action {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n opacity: 0.6;\n transition: opacity 0.15s, background 0.15s;\n}\n.mb-adapt-minimized-tab-action:hover {\n opacity: 1;\n background: var(--_button-hover-bg);\n}\n.mb-adapt-minimized-tab-action svg {\n width: 14px;\n height: 14px;\n}\n\n/* Minimized tab drag handle cursor */\n.mb-adapt-minimized-tab {\n cursor: grab;\n touch-action: none;\n}\n\n/* Drop target highlight for minimized tab merge */\n.mb-adapt-minimized-tab--drop-target {\n background: var(--_drop-header-bg) !important;\n box-shadow: inset 0 0 0 2px var(--_drop-border);\n}\n\n/* \u2500\u2500 Pointer-drag ghost element \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-drag-ghost {\n position: fixed;\n pointer-events: none;\n z-index: calc(999999 + var(--_z-base));\n padding: 4px 10px;\n background: var(--_fork-tab-bg);\n color: var(--_fork-tab-color);\n border: 1px solid var(--_fork-separator);\n border-radius: var(--_tab-radius, 4px);\n font-size: var(--_tab-font-size);\n font-family: var(--_font);\n white-space: nowrap;\n box-shadow: var(--_drag-ghost-shadow);\n opacity: 0.92;\n display: flex;\n align-items: center;\n}\n\n.mb-drag-ghost svg {\n width: 16px;\n height: 16px;\n}\n\n/* \u2500\u2500 Drop target highlight on group header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-group-header--drop-target {\n background: var(--_drop-header-bg) !important;\n box-shadow: inset 0 0 0 2px var(--_drop-border);\n}\n\n/* \u2500\u2500 Drop overlay (content-area and dock-strip indicators) */\n.mb-drop-overlay {\n position: fixed;\n pointer-events: none;\n z-index: calc(999998 + var(--_z-base));\n display: none;\n box-sizing: border-box;\n border-radius: 6px;\n transition: opacity 0.1s ease-out;\n}\n\n.mb-drop-overlay[data-zone=\"center\"] {\n background: var(--_drop-center-bg);\n border: 2px solid var(--_drop-border);\n}\n\n.mb-drop-overlay[data-zone=\"top\"],\n.mb-drop-overlay[data-zone=\"bottom\"],\n.mb-drop-overlay[data-zone=\"left\"],\n.mb-drop-overlay[data-zone=\"right\"] {\n background: var(--_drop-split-bg);\n border: 2px solid var(--_drop-border);\n}\n\n/* \u2500\u2500 Iframe pointer-event guard during drag \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\nhtml.mb-dragging iframe,\nhtml.mb-dragging webview {\n pointer-events: none !important;\n}\n\n/* \u2500\u2500 Tab pop-out button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.mb-tab-popout {\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 3px;\n opacity: 0;\n transition: opacity 0.15s, background 0.15s;\n}\n\n.mb-tab:hover .mb-tab-popout {\n opacity: 0.7;\n}\n\n.mb-tab-popout:hover {\n opacity: 1 !important;\n background: var(--_button-hover-bg);\n}\n\n.mb-tab-popout svg {\n width: 12px;\n height: 12px;\n}\n\n/* Hide pop-out button on main group (never floats), when overlay\n has 0 or 1 total tabs (nothing to pop out), and when floating is disallowed. */\n.mb-group[data-main-group=\"true\"] .mb-tab-popout,\n.mb-floating-overlay[data-total-tab-count=\"0\"] .mb-tab-popout,\n.mb-floating-overlay[data-total-tab-count=\"1\"] .mb-tab-popout,\n.mb-group[data-allow-floating=\"false\"] .mb-tab-popout {\n display: none !important;\n}\n\n\n/* \u2500\u2500 Iframe portal layer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n/* MUST NOT create a stacking context \u2014 portal entries' z-indexes\n must compete with floating overlays in the parent stacking context.\n position: absolute + no z-index achieves this. */\n.mb-iframe-portal-layer {\n position: absolute;\n width: 0;\n height: 0;\n overflow: visible;\n pointer-events: none;\n}\n.mb-iframe-portal {\n position: fixed;\n pointer-events: auto;\n overflow: hidden;\n}\n\n/* \u2500\u2500 Touch device adjustments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n@media (hover: none) {\n .mb-tab-close {\n opacity: 0.5;\n }\n\n .mb-tab-popout {\n opacity: 0.5;\n }\n\n .mb-tab:hover .mb-tab-close,\n .mb-tab:hover .mb-tab-popout {\n opacity: 0.7;\n }\n}\n\n@media (pointer: coarse) {\n .mb-tab-close,\n .mb-tab-popout {\n width: 24px;\n height: 24px;\n }\n\n .mb-adapt-fork-actions button {\n width: 26px;\n height: 26px;\n }\n\n .mb-adapt-minimized-tab-action {\n width: 28px;\n height: 28px;\n }\n}";
@@ -3,7 +3,7 @@ import { createConnectClient } from "@mochabug/adapt-core/connect";
3
3
  import { IframePanelComponent, type IframePanelHost } from "./panel-setup.js";
4
4
  import { type AdaptTheme } from "./theme.js";
5
5
  import type { AdaptWebClientOptions } from "./types.js";
6
- export type { AdaptTheme, AdaptWebClientOptions, CapWidgetI18n, CapWidgetOptions, ChallengeInfo, ForkDisplay, Output, PersistOptions, RedeemedChallenge, SignalValue, StatusJson, StatusText, } from "./types.js";
6
+ export type { AdaptError, AdaptErrorKind, AdaptTheme, AdaptWebClientOptions, CapWidgetI18n, CapWidgetOptions, ChallengeInfo, ForkDisplay, Output, PersistOptions, RedeemedChallenge, SignalValue, StatusJson, StatusText, } from "./types.js";
7
7
  export { resolveTheme } from "./theme.js";
8
8
  export type { SignalData } from "@mochabug/adapt-core";
9
9
  export { createConnectClient };
@@ -243,4 +243,5 @@ export declare class AdaptWebClient implements IframePanelHost {
243
243
  private showErrorStatus;
244
244
  private isExpiredTokenError;
245
245
  private getErrorMessage;
246
+ private classifyError;
246
247
  }
@@ -381,7 +381,9 @@ export declare class PanelManager {
381
381
  private portalRaf;
382
382
  private mainGroupCollapsed;
383
383
  private _beforeTabClose;
384
+ private zBase;
384
385
  constructor(opts: PanelManagerOptions);
386
+ private getZBase;
385
387
  setBeforeTabClose(cb: ((panelId: string) => boolean | Promise<boolean>) | null): void;
386
388
  addPanel(opts: PanelOptions): Panel;
387
389
  removePanel(panelId: string): void;
@@ -402,6 +402,23 @@ export interface AdaptWebClientOptions {
402
402
  * @param active - Whether a fork is visually active
403
403
  */
404
404
  onForkActive?: (active: boolean) => void;
405
+ /**
406
+ * Callback invoked when the automation encounters an error.
407
+ * Receives a structured error with classification, message, and retriability.
408
+ * Fires for both init-phase errors (e.g. invalid inheritToken) and streaming errors.
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * onError: (error) => {
413
+ * if (error.retriable) {
414
+ * console.log('Retriable error:', error.kind, error.message);
415
+ * } else {
416
+ * console.error('Fatal error:', error.kind, error.message);
417
+ * }
418
+ * }
419
+ * ```
420
+ */
421
+ onError?: (error: AdaptError) => void;
405
422
  /**
406
423
  * Custom CSS class names to override default styling.
407
424
  * All properties are optional. Unspecified classes use defaults.
@@ -511,3 +528,10 @@ export interface StatusText {
511
528
  /** Label for the restart/try-again button on status cards. Default: `"Try again"` */
512
529
  restartButton?: string;
513
530
  }
531
+ export type AdaptErrorKind = 'auth' | 'expired' | 'not_found' | 'session_not_found' | 'capacity' | 'error';
532
+ export interface AdaptError {
533
+ kind: AdaptErrorKind;
534
+ message: string;
535
+ retriable: boolean;
536
+ cause?: unknown;
537
+ }
@@ -4324,7 +4324,7 @@ var MbAdapt = (() => {
4324
4324
  // src/cap-adapter.ts
4325
4325
  if (typeof window !== "undefined" && true && !window.CAP_CUSTOM_WASM_URL) {
4326
4326
  window.CAP_CUSTOM_WASM_URL = new URL(
4327
- "https://cdn.mochabug.com/adapt/web/1.0.1-rc.15/cap_wasm.js",
4327
+ "https://cdn.mochabug.com/adapt/web/1.0.1-rc.17/cap_wasm.js",
4328
4328
  window.location.href
4329
4329
  ).href;
4330
4330
  }
Binary file