local API = rawget(_G, "LIDCOUNCIL_API")
local INTERNAL_API = type(API) == "table" and type(API.__internal) == "table" and API.__internal or nil
if type(INTERNAL_API) ~= "table" then
  error("LidCouncil missing internal API registry.")
end

local GetEditorThemePalette = type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function"
  and INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl
  or nil

local function CreateMainTab(parent, previous, def)
  local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
  button:SetSize(def.width, 20)
  if previous then
    button:SetPoint("LEFT", previous, "RIGHT", 8, 0)
  else
    button:SetPoint("LEFT", 0, 0)
  end
  button:SetText(def.text)
  return button
end

local function CreateRootPage(scrollChild, titleText)
  local page = CreateFrame("Frame", nil, scrollChild)
  page:SetPoint("TOPLEFT", 0, 0)
  page:SetPoint("BOTTOMRIGHT", 0, 0)

  if not titleText then
    return page
  end

  local title = page:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
  title:SetPoint("TOPLEFT", 0, 0)
  title:SetText(titleText)
  -- Main navigation already identifies the active page.
  title:Hide()

  local currentLabel = page:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  currentLabel:SetPoint("TOPLEFT", 0, -22)
  -- The compact session header is the single source of profile context.
  currentLabel:Hide()

  return page, title, currentLabel
end

local function SetupEditorFrameShell(editor, deps)
  deps = deps or {}

  local RootDB = deps.RootDB
  local ApplyFrameSkin = deps.ApplyFrameSkin
  local ApplyEditorState = deps.ApplyEditorState
  local ApplyEditorScale = deps.ApplyEditorScale
  local SaveEditorState = deps.SaveEditorState
  local ApplyEditorLogo = deps.ApplyEditorLogo
  local SetAllUnlocked = deps.SetAllUnlocked
  local GetPanelsUnlockedState = deps.GetPanelsUnlockedState
  local NudgeSelectedPanel = deps.NudgeSelectedPanel
  local CreatePurpleOutline = deps.CreatePurpleOutline
  local DisplayProfileName = deps.DisplayProfileName or function(name)
    if not name or name == "" then return "(none)" end
    if name == "Default" then return "No active Profile :(" end
    return tostring(name)
  end
  local BuildTutorialPage = deps.BuildTutorialPage
  local ADDON_VERSION = tostring(deps.ADDON_VERSION or "")
  local WOW_CLIENT_VERSION = tostring(deps.WOW_CLIENT_VERSION or "")
  local LOGO_TARGET_W = tonumber(deps.LOGO_TARGET_W) or 150
  local LOGO_TARGET_H = tonumber(deps.LOGO_TARGET_H) or 120
  local HEADER_LOGO_SCALE = 0.86
  local LogSilent = deps.LogSilent

  local warnedResizeOnUpdateFailed = false
  local warnedEditorSizeChangedFailed = false

  local function LogShellFailure(message)
    if type(LogSilent) == "function" then
      LogSilent(message)
    end
  end

  local function IsEditorCombatLocked()
    return type(InCombatLockdown) == "function" and InCombatLockdown()
  end

  local function SetPropagateKeyboardInputSafe(frame, enabled)
    if not frame or type(frame.SetPropagateKeyboardInput) ~= "function" then
      return false
    end
    if IsEditorCombatLocked() then
      return false
    end
    frame:SetPropagateKeyboardInput(enabled and true or false)
    return true
  end

  local function UpdateCombatLimitedNotice()
    if not editor or not editor.combatNotice then
      return
    end
    if editor.IsShown and editor:IsShown() and IsEditorCombatLocked() then
      editor.combatNotice:Show()
    else
      editor.combatNotice:Hide()
    end
  end

  local function ClampEditorSize(width, height)
    local screenW = (UIParent and UIParent.GetWidth and UIParent:GetWidth()) or 1920
    local screenH = (UIParent and UIParent.GetHeight and UIParent:GetHeight()) or 1080
    local minW, minH = 520, 340
    local maxW = math.max(minW, math.floor(screenW - 40))
    local maxH = math.max(minH, math.floor(screenH - 40))

    local clampedW = math.min(math.max(width, minW), maxW)
    local clampedH = math.min(math.max(height, minH), maxH)
    return clampedW, clampedH
  end

  local function AnchorEditorToCurrentTopLeft()
    local left, top = editor:GetLeft(), editor:GetTop()
    if left and top and UIParent then
      editor:ClearAllPoints()
      editor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left, top)
    end
  end

  local function SetEditorBackdropVisible(visible)
    if not editor.SetBackdropColor or not editor.SetBackdropBorderColor then
      return
    end
    if visible then
      ApplyFrameSkin(editor)
    else
      editor:SetBackdropColor(0, 0, 0, 0)
      editor:SetBackdropBorderColor(0, 0, 0, 0)
    end
  end

  local function UpdateCollapsedEditorButtonStyle(button)
    if not button then
      return
    end
    local enabled = not button.IsEnabled or button:IsEnabled()
    local hovered = button.__lidEditorCollapsedHovered == true
    local paletteResolver = GetEditorThemePalette
    if type(paletteResolver) ~= "function" and type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function" then
      paletteResolver = INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl
    end
    local palette = paletteResolver and paletteResolver() or nil
    local useLootPilot = type(palette) == "table" and (palette.key == "lootpilot" or palette.key == "white_orange")
    local borderColor = enabled and { 0.72, 0.58, 0.20, 0.92 } or { 0.24, 0.24, 0.28, 0.72 }
    local fillColor = hovered and { 0.15, 0.18, 0.24, 0.98 } or { 0.10, 0.12, 0.16, 0.96 }
    local textColor = hovered and { 1.00, 0.90, 0.40, 1.00 } or { 0.94, 0.84, 0.34, 1.00 }
    if useLootPilot then
      borderColor = enabled and { 1.00, 0.88, 0.56, 0.95 } or { 0.42, 0.32, 0.24, 0.72 }
      fillColor = hovered and { 24 / 255, 38 / 255, 62 / 255, 0.98 } or { 7 / 255, 14 / 255, 25 / 255, 0.98 }
      textColor = { 1.00, 1.00, 1.00, 1.00 }
    end
    if not enabled then
      fillColor = useLootPilot and { 4 / 255, 8 / 255, 14 / 255, 0.82 } or { 0.06, 0.06, 0.08, 0.90 }
      textColor = useLootPilot and { 0.74, 0.74, 0.74, 1.00 } or { 0.48, 0.48, 0.54, 1.00 }
    end
    if button.__lidEditorCollapsedBorder then
      button.__lidEditorCollapsedBorder:SetVertexColor(borderColor[1], borderColor[2], borderColor[3], borderColor[4])
    end
    if button.__lidEditorCollapsedFill then
      button.__lidEditorCollapsedFill:SetVertexColor(fillColor[1], fillColor[2], fillColor[3], fillColor[4])
    end
    local fontString = button.GetFontString and button:GetFontString() or nil
    if fontString and fontString.SetTextColor then
      fontString:SetTextColor(textColor[1], textColor[2], textColor[3], textColor[4])
    end
  end

  local function ApplyCollapsedEditorButtonStyle(button)
    if not button or button.__lidEditorCollapsedStyled then
      UpdateCollapsedEditorButtonStyle(button)
      return button
    end
    button.__lidEditorCollapsedStyled = true
    if button.SetNormalTexture then button:SetNormalTexture("") end
    if button.SetPushedTexture then button:SetPushedTexture("") end
    if button.SetHighlightTexture then button:SetHighlightTexture("") end
    if button.SetDisabledTexture then button:SetDisabledTexture("") end
    if button.GetRegions then
      for _, region in ipairs({ button:GetRegions() }) do
        if region and region.GetObjectType and region:GetObjectType() == "Texture" then
          region:SetTexture("")
          region:Hide()
        end
      end
    end
    local border = button:CreateTexture(nil, "BACKGROUND")
    border:SetAllPoints(true)
    border:SetTexture("Interface\\Buttons\\WHITE8x8")
    button.__lidEditorCollapsedBorder = border
    local fill = button:CreateTexture(nil, "BORDER")
    fill:SetPoint("TOPLEFT", 1, -1)
    fill:SetPoint("BOTTOMRIGHT", -1, 1)
    fill:SetTexture("Interface\\Buttons\\WHITE8x8")
    button.__lidEditorCollapsedFill = fill
    if button.HookScript then
      button:HookScript("OnEnter", function(self)
        self.__lidEditorCollapsedHovered = true
        UpdateCollapsedEditorButtonStyle(self)
      end)
      button:HookScript("OnLeave", function(self)
        self.__lidEditorCollapsedHovered = false
        UpdateCollapsedEditorButtonStyle(self)
      end)
      button:HookScript("OnShow", function(self)
        UpdateCollapsedEditorButtonStyle(self)
      end)
    end
    UpdateCollapsedEditorButtonStyle(button)
    return button
  end

  local function AttachTabActiveBorder(button)
    if not button or button.__activeBorder or type(CreatePurpleOutline) ~= "function" then
      return
    end
    button.__activeBorder = CreatePurpleOutline(button)
    local underline = button:CreateTexture(nil, "OVERLAY")
    underline:SetPoint("BOTTOMLEFT", 6, 2)
    underline:SetPoint("BOTTOMRIGHT", -6, 2)
    underline:SetHeight(2)
    underline:SetTexture("Interface\\Buttons\\WHITE8x8")
    underline:SetVertexColor(1.00, 0.82, 0.28, 1.00)
    underline:Hide()
    button.__activeUnderline = underline
  end

  ApplyFrameSkin(editor)
  ApplyEditorState(editor)
  ApplyEditorScale(editor)

  editor:SetMovable(true)
  editor:EnableMouse(true)
  editor:RegisterForDrag("LeftButton")
  editor:SetScript("OnDragStart", function(self)
    if IsEditorCombatLocked() then
      UpdateCombatLimitedNotice()
      return
    end
    self:StartMoving()
  end)
  editor:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    if self.__collapsed then
      local ui = RootDB().ui
      ui.editor = ui.editor or {}
      local point, _, relPoint, x, y = self:GetPoint(1)
      ui.editor.point, ui.editor.relPoint, ui.editor.x, ui.editor.y = point, relPoint, x, y
      return
    end
    SaveEditorState(self)
  end)

  editor:SetResizable(true)
  if editor.SetMinResize then editor:SetMinResize(520, 340) end

  local resizeGrip = CreateFrame("Button", nil, editor)
  resizeGrip:SetSize(16, 16)
  resizeGrip:SetPoint("BOTTOMRIGHT", -2, 2)

  local resizeTexture = resizeGrip:CreateTexture(nil, "ARTWORK")
  resizeTexture:SetAllPoints(true)
  resizeTexture:SetTexture("Interface/ChatFrame/UI-ChatIM-SizeGrabber-Up")

  resizeGrip:RegisterForDrag("LeftButton")
  resizeGrip:SetScript("OnDragStart", function()
    if IsEditorCombatLocked() then
      UpdateCombatLimitedNotice()
      return
    end
    editor.__resizing = true
    editor.__resizeStartW = editor:GetWidth()
    editor.__resizeStartH = editor:GetHeight()
    local left, top = editor:GetLeft(), editor:GetTop()
    if left and top then
      editor:ClearAllPoints()
      editor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left, top)
    end

    local cursorX, cursorY = GetCursorPosition()
    local scale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
    editor.__resizeStartX = cursorX / scale
    editor.__resizeStartY = cursorY / scale

    resizeGrip:SetScript("OnUpdate", function()
      local ok, err = pcall(function()
        if not editor.__resizing then return end

        local currentX, currentY = GetCursorPosition()
        local uiScale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
        currentX, currentY = currentX / uiScale, currentY / uiScale

        local deltaX = currentX - editor.__resizeStartX
        local deltaY = editor.__resizeStartY - currentY
        local nextW = (editor.__resizeStartW or editor:GetWidth()) + deltaX
        local nextH = (editor.__resizeStartH or editor:GetHeight()) + deltaY

        local clampedW, clampedH = ClampEditorSize(nextW, nextH)
        editor:SetSize(clampedW, clampedH)
      end)
      if ok then return end
      resizeGrip:SetScript("OnUpdate", nil)
      editor.__resizing = false
      if not warnedResizeOnUpdateFailed then
        warnedResizeOnUpdateFailed = true
        LogShellFailure("Editor resize OnUpdate failed: " .. tostring(err))
      end
    end)
  end)

  resizeGrip:SetScript("OnDragStop", function()
    resizeGrip:SetScript("OnUpdate", nil)
    if editor.__resizeStartX and editor.__resizeStartY then
      local cursorX, cursorY = GetCursorPosition()
      local scale = (UIParent and UIParent.GetScale and UIParent:GetScale()) or 1
      local deltaX = math.abs(((cursorX or 0) / scale) - editor.__resizeStartX)
      local deltaY = math.abs(((cursorY or 0) / scale) - editor.__resizeStartY)
      if deltaX < 2 and deltaY < 2 then
        editor:SetSize(editor.__resizeStartW or editor:GetWidth(), editor.__resizeStartH or editor:GetHeight())
      end
    end

    editor.__resizing = false
    editor.__resizeStartX = nil
    editor.__resizeStartY = nil
    SaveEditorState(editor)
    if editor.UpdateScrollLayout then editor:UpdateScrollLayout() end
  end)

  editor:SetScript("OnSizeChanged", function(self, width, height)
    local ok, err = pcall(function()
      if self.__collapsed then return end
      if self.__sizingClamp or self.__resizing then return end

      local now = GetTime and GetTime() or 0
      if self.__lastSizeTick and (now - self.__lastSizeTick) < 0.05 then return end
      self.__lastSizeTick = now

      local nextW = width or self:GetWidth()
      local nextH = height or self:GetHeight()
      local clampedW, clampedH = ClampEditorSize(nextW, nextH)
      if clampedW ~= nextW or clampedH ~= nextH then
        self.__sizingClamp = true
        self:SetSize(clampedW, clampedH)
        self.__sizingClamp = false
      end

      if self.UpdateSessionInfoCardLayout then
        self:UpdateSessionInfoCardLayout()
      end
      SaveEditorState(self)
      if self.UpdateScrollLayout then
        self:UpdateScrollLayout()
      end
    end)
    if ok then return end
    self.__sizingClamp = false
    if not warnedEditorSizeChangedFailed then
      warnedEditorSizeChangedFailed = true
      LogShellFailure("Editor OnSizeChanged failed: " .. tostring(err))
    end
  end)

  local logo = editor:CreateTexture(nil, "ARTWORK")
  logo:SetSize(math.floor(LOGO_TARGET_W * HEADER_LOGO_SCALE), math.floor(LOGO_TARGET_H * HEADER_LOGO_SCALE))
  logo:SetPoint("TOPLEFT", 12, -10)
  logo:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogo.tga")
  editor.logo = logo
  ApplyEditorLogo()

  local activeSessionLogo = editor:CreateTexture(nil, "ARTWORK", nil, 2)
  activeSessionLogo:SetAllPoints(logo)
  activeSessionLogo:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_HeaderLogoGreen.tga")
  activeSessionLogo:Hide()
  editor.activeSessionLogo = activeSessionLogo

  local sessionInfoCard = CreateFrame("Frame", nil, editor)
  sessionInfoCard:SetHeight(96)
  sessionInfoCard:EnableMouse(false)
  editor.sessionInfoCard = sessionInfoCard
  editor.UpdateSessionInfoCardLayout = function()
    if editor.__collapsed then
      return
    end
    local usesHeaderLogo = logo:IsShown()
    local logoWidth = logo:GetWidth() or LOGO_TARGET_W
    local cardLeft = usesHeaderLogo and (12 + logoWidth + 8) or 12
    local availableWidth = math.max(180, math.floor(editor:GetWidth() - cardLeft - 116))
    sessionInfoCard:ClearAllPoints()
    if usesHeaderLogo then
      sessionInfoCard:SetPoint("TOPLEFT", logo, "TOPRIGHT", 8, 2)
    else
      sessionInfoCard:SetPoint("TOPLEFT", editor, "TOPLEFT", 12, -8)
    end
    sessionInfoCard:SetWidth(math.min(460, availableWidth))
  end
  editor:UpdateSessionInfoCardLayout()

  local sessionInfoCardBg = editor:CreateTexture(nil, "ARTWORK", nil, -4)
  sessionInfoCardBg:SetAllPoints(sessionInfoCard)
  editor.sessionInfoCardBg = sessionInfoCardBg
  editor.ApplySessionInfoCardBackground = function(alpha)
    local fadeAlpha = math.max(0, math.min(0.82, tonumber(alpha) or 0.70))
    sessionInfoCardBg:SetTexture("Interface\\Buttons\\WHITE8x8")
    if sessionInfoCardBg.SetGradientAlpha then
      sessionInfoCardBg:SetGradientAlpha(
        "HORIZONTAL",
        0.01, 0.015, 0.02, fadeAlpha,
        0.01, 0.015, 0.02, 0
      )
    else
      sessionInfoCardBg:SetColorTexture(0.01, 0.015, 0.02, fadeAlpha)
    end
  end
  editor:ApplySessionInfoCardBackground(0.70)
  editor.sessionInfoCardChrome = {}

  -- Keep the dice above all header artwork and text. A texture attached to
  -- the information card can be obscured by sibling editor layers.
  local headerAutoPassIconFrame = CreateFrame("Frame", nil, editor)
  headerAutoPassIconFrame:SetFrameStrata(editor:GetFrameStrata())
  headerAutoPassIconFrame:SetFrameLevel((editor:GetFrameLevel() or 1) + 80)
  headerAutoPassIconFrame:EnableMouse(false)
  headerAutoPassIconFrame:Hide()
  editor.headerAutoPassIconFrame = headerAutoPassIconFrame

  local headerAutoPassIcon = headerAutoPassIconFrame:CreateTexture(nil, "OVERLAY", nil, 7)
  headerAutoPassIcon:SetAllPoints(headerAutoPassIconFrame)
  headerAutoPassIcon:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_Autopass_Off2.tga")
  editor.headerAutoPassIcon = headerAutoPassIcon

  -- This is intentionally separate from Auto Pass. It only appears when the
  -- local player still has one or more item choices waiting in the roll queue.
  local headerRollPendingIconFrame = CreateFrame("Frame", nil, editor)
  headerRollPendingIconFrame:SetFrameStrata(editor:GetFrameStrata())
  headerRollPendingIconFrame:SetFrameLevel((editor:GetFrameLevel() or 1) + 81)
  headerRollPendingIconFrame:Hide()
  editor.headerRollPendingIconFrame = headerRollPendingIconFrame

  local headerRollPendingIcon = headerRollPendingIconFrame:CreateTexture(nil, "OVERLAY", nil, 7)
  headerRollPendingIcon:SetAllPoints(headerRollPendingIconFrame)
  headerRollPendingIcon:SetTexture("Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_Dice_Amber.tga")
  editor.headerRollPendingIcon = headerRollPendingIcon

  local headerRollPendingCount = headerRollPendingIconFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
  headerRollPendingCount:SetPoint("BOTTOMRIGHT", headerRollPendingIconFrame, "BOTTOMRIGHT", 2, -2)
  headerRollPendingCount:SetJustifyH("RIGHT")
  headerRollPendingCount:SetTextColor(1.00, 0.92, 0.54, 1.00)
  headerRollPendingCount:SetShadowColor(0, 0, 0, 1)
  headerRollPendingCount:SetShadowOffset(1, -1)
  editor.headerRollPendingCount = headerRollPendingCount

  headerRollPendingIconFrame:EnableMouse(true)
  headerRollPendingIconFrame:SetScript("OnEnter", function(self)
    if not GameTooltip then
      return
    end
    local pendingCount = math.max(0, tonumber(editor.__lidHeaderPendingRollCount) or 0)
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText("Roll choice pending", 1.00, 0.72, 0.22)
    GameTooltip:AddLine(
      string.format(
        "%d item%s waiting for your LidCouncil roll choice.",
        pendingCount,
        pendingCount == 1 and " is" or "s are"
      ),
      0.92, 0.92, 0.96, true
    )
    GameTooltip:AddLine("Use the LidCouncil roll window to submit your choice.", 0.76, 0.82, 0.90, true)
    GameTooltip:Show()
  end)
  headerRollPendingIconFrame:SetScript("OnLeave", function()
    if GameTooltip then
      GameTooltip:Hide()
    end
  end)

  editor.UpdateHeaderStatusMetaLayout = function()
    if not editor.sessionStatusMeta or not editor.sessionStatusBadge then
      return
    end
    local rightAnchor = headerRollPendingIconFrame:IsShown()
      and headerRollPendingIconFrame
      or headerAutoPassIconFrame
    local layoutKey = (editor.__collapsed == true and "collapsed" or "expanded")
      .. "|" .. (rightAnchor == headerRollPendingIconFrame and "pending" or "autopass")
    if editor.__lidHeaderStatusMetaLayoutKey == layoutKey then
      return
    end
    editor.__lidHeaderStatusMetaLayoutKey = layoutKey
    editor.sessionStatusMeta:ClearAllPoints()
    editor.sessionStatusMeta:SetPoint("LEFT", editor.sessionStatusBadge, "RIGHT", 8, 0)
    if editor.__collapsed == true then
      editor.sessionStatusMeta:SetPoint("RIGHT", rightAnchor, "LEFT", -6, 0)
    else
      editor.sessionStatusMeta:SetPoint("RIGHT", rightAnchor, "LEFT", -8, 0)
    end
  end

  editor.SetHeaderRollPendingIndicator = function(pendingCount)
    local resolvedCount = math.max(0, math.floor(tonumber(pendingCount) or 0))
    local showIndicator = resolvedCount > 0
    local monitoringEnabled = type(editor.IsHeaderMonitoringEnabled) ~= "function"
      or editor:IsHeaderMonitoringEnabled()
    local layoutKey = tostring(resolvedCount)
      .. "|" .. (editor.__collapsed == true and "collapsed" or "expanded")
      .. "|" .. (monitoringEnabled and "shown" or "hidden")
    editor.__lidHeaderPendingRollCount = resolvedCount
    editor.__lidHeaderPendingRollDetail = showIndicator
      and string.format("Roll choice pending: %d item%s waiting.", resolvedCount, resolvedCount == 1 and "" or "s")
      or "No roll choices waiting."

    if editor.__lidHeaderRollPendingLayoutKey == layoutKey then
      editor:UpdateHeaderStatusMetaLayout()
      return
    end
    editor.__lidHeaderRollPendingLayoutKey = layoutKey

    headerRollPendingIconFrame:ClearAllPoints()
    if editor.__collapsed == true then
      headerRollPendingIconFrame:SetSize(20, 20)
      headerRollPendingIconFrame:SetPoint("RIGHT", headerAutoPassIconFrame, "LEFT", -5, 0)
    else
      headerRollPendingIconFrame:SetSize(30, 30)
      headerRollPendingIconFrame:SetPoint("RIGHT", headerAutoPassIconFrame, "LEFT", -8, 0)
    end
    headerRollPendingCount:SetText(showIndicator and tostring(resolvedCount) or "")
    headerRollPendingIconFrame:SetShown(showIndicator and monitoringEnabled)
    editor:UpdateHeaderStatusMetaLayout()
  end
  editor:SetHeaderRollPendingIndicator(0)

  editor.SetHeaderAutoPassIcon = function(enabled, visible)
    -- The indicator always represents the local roll preference. It is not
    -- conditional on session state or a refresh caller's visibility hint.
    local showIcon = true
    local monitoringEnabled = type(editor.IsHeaderMonitoringEnabled) ~= "function"
      or editor:IsHeaderMonitoringEnabled()
    local displayOverride = editor.__lidAutoPassDisplayOverride
    local overrideMatchesCurrentSession = type(displayOverride) == "boolean"
      and tostring(editor.__lidAutoPassDisplaySessionId or "") ~= ""
      and tostring(editor.__lidAutoPassDisplaySessionId or "") == tostring(editor.__lidHeaderAutoPassSessionId or "")
    -- A confirmed click in Auto Pass Setting wins for its current session.
    -- This prevents a delayed banner refresh from repainting stale state.
    local resolvedEnabled = enabled == true
    if overrideMatchesCurrentSession then
      resolvedEnabled = displayOverride
    end
    local texturePath = resolvedEnabled
      and "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_Autopass_On2.tga"
      or "Interface\\AddOns\\LidCouncil\\Media\\LidCouncil\\Logos\\LidCouncil_Autopass_Off2.tga"
    local layoutKey = (resolvedEnabled and "on" or "off")
      .. "|" .. (editor.__collapsed == true and "collapsed" or "expanded")
      .. "|" .. (monitoringEnabled and "shown" or "hidden")
    editor.__lidHeaderAutoPassEnabled = resolvedEnabled
    editor.__lidHeaderAutoPassVisible = showIcon
    if editor.__lidHeaderAutoPassLayoutKey == layoutKey then
      editor:UpdateHeaderStatusMetaLayout()
      return
    end
    editor.__lidHeaderAutoPassLayoutKey = layoutKey
    headerAutoPassIconFrame:ClearAllPoints()
    if editor.__collapsed == true then
      headerAutoPassIconFrame:SetSize(resolvedEnabled and 28 or 22, resolvedEnabled and 18 or 22)
      headerAutoPassIconFrame:SetPoint("TOPRIGHT", sessionInfoCard, "TOPRIGHT", -4, -4)
    else
      headerAutoPassIconFrame:SetSize(resolvedEnabled and 44 or 40, resolvedEnabled and 28 or 26)
      headerAutoPassIconFrame:SetPoint("TOPRIGHT", sessionInfoCard, "TOPRIGHT", -4, -6)
    end
    if editor.__lidHeaderAutoPassTexturePath ~= texturePath then
      headerAutoPassIcon:SetTexture(nil)
      headerAutoPassIcon:SetTexture(texturePath)
      editor.__lidHeaderAutoPassTexturePath = texturePath
    end
    headerAutoPassIcon:SetVertexColor(1, 1, 1, 1)
    headerAutoPassIcon:Show()
    headerAutoPassIconFrame:SetShown(showIcon and monitoringEnabled)
    editor:UpdateHeaderStatusMetaLayout()
  end
  -- Initialize the persistent local Auto Pass indicator as OFF.
  editor:SetHeaderAutoPassIcon(false, true)

  local title = editor:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
  title:SetPoint("TOPLEFT", sessionInfoCard, "TOPLEFT", 10, -6)
  title:SetPoint("TOPRIGHT", sessionInfoCard, "TOPRIGHT", -56, -6)
  title:SetJustifyH("LEFT")
  title:SetText("LidCouncil Version " .. ADDON_VERSION)
  editor.title = title

  local versionText = editor:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  versionText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -1)
  versionText:SetJustifyH("LEFT")
  versionText:SetText("v" .. WOW_CLIENT_VERSION)
  editor.versionText = versionText

  local sessionStatusBadge = CreateFrame("Frame", nil, sessionInfoCard, "BackdropTemplate")
  sessionStatusBadge:SetPoint("TOPLEFT", versionText, "BOTTOMLEFT", 0, -4)
  sessionStatusBadge:SetSize(104, 18)
  sessionStatusBadge:SetBackdrop({
    bgFile = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    tile = false,
    edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 },
  })
  sessionStatusBadge:SetBackdropColor(0.16, 0.18, 0.21, 0.95)
  sessionStatusBadge:SetBackdropBorderColor(0.42, 0.48, 0.55, 0.90)
  sessionStatusBadge:EnableMouse(false)
  editor.sessionStatusBadge = sessionStatusBadge

  local sessionStatusText = sessionStatusBadge:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  sessionStatusText:SetPoint("CENTER", 0, 0)
  sessionStatusText:SetText("NO SESSION")
  editor.sessionStatusText = sessionStatusText

  local sessionStatusMeta = sessionInfoCard:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  sessionStatusMeta:SetPoint("LEFT", sessionStatusBadge, "RIGHT", 8, 0)
  sessionStatusMeta:SetPoint("RIGHT", sessionInfoCard, "RIGHT", -10, 0)
  sessionStatusMeta:SetJustifyH("LEFT")
  if sessionStatusMeta.SetMaxLines then
    sessionStatusMeta:SetMaxLines(1)
  end
  sessionStatusMeta:SetText("")
  editor.sessionStatusMeta = sessionStatusMeta

  local localDataText = sessionInfoCard:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  localDataText:SetPoint("TOPLEFT", sessionStatusBadge, "BOTTOMLEFT", 0, -3)
  localDataText:SetWidth(300)
  localDataText:SetJustifyH("LEFT")
  if localDataText.SetMaxLines then
    localDataText:SetMaxLines(1)
  end
  localDataText:SetText("Checking local changes...")
  editor.localDataText = localDataText

  local syncActivityText = sessionInfoCard:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  syncActivityText:SetPoint("TOPLEFT", localDataText, "BOTTOMLEFT", 24, -1)
  syncActivityText:SetWidth(276)
  syncActivityText:SetJustifyH("LEFT")
  if syncActivityText.SetMaxLines then
    syncActivityText:SetMaxLines(1)
  end
  syncActivityText:SetText("Sync: Idle")
  editor.syncActivityText = syncActivityText

  local syncActivityBar = CreateFrame("StatusBar", nil, sessionInfoCard)
  syncActivityBar:SetPoint("TOPLEFT", syncActivityText, "BOTTOMLEFT", 0, -2)
  syncActivityBar:SetSize(276, 4)
  syncActivityBar:SetMinMaxValues(0, 1)
  syncActivityBar:SetStatusBarTexture("Interface\\Buttons\\WHITE8x8")
  syncActivityBar:SetStatusBarColor(0.30, 0.90, 0.36, 0.90)
  syncActivityBar:SetValue(0)
  syncActivityBar:Hide()
  syncActivityBar:SetScript("OnUpdate", function(bar, elapsed)
    if type(InCombatLockdown) == "function" and InCombatLockdown() then
      return
    end
    if bar.__lidSyncDeterminate == true then
      local current = tonumber(bar.__lidSyncDisplayedValue) or 0
      local target = tonumber(bar.__lidSyncTargetValue) or current
      local nextValue = current + ((target - current) * math.min(1, (tonumber(elapsed) or 0) * 8))
      if math.abs(target - nextValue) < 0.002 then
        nextValue = target
      end
      bar.__lidSyncDisplayedValue = nextValue
      bar:SetValue(nextValue)
      return
    end
    if bar.__lidSyncActive ~= true then
      return
    end
    bar.__lidSyncPulseElapsed = (tonumber(bar.__lidSyncPulseElapsed) or 0) + (tonumber(elapsed) or 0)
    if bar.__lidSyncPulseElapsed < 0.15 then
      return
    end
    bar.__lidSyncPulseElapsed = 0
    local now = type(GetTime) == "function" and GetTime() or 0
    bar:SetValue(0.42 + ((math.sin(now * 4) + 1) * 0.08))
  end)
  editor.syncActivityBar = syncActivityBar

  local sessionInfoButton = CreateFrame("Button", nil, sessionInfoCard, "BackdropTemplate")
  sessionInfoButton:SetSize(18, 18)
  sessionInfoButton:SetPoint("TOPLEFT", localDataText, "BOTTOMLEFT", 0, -3)
  sessionInfoButton:SetBackdrop({
    bgFile = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    tile = false,
    edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 },
  })
  sessionInfoButton:SetBackdropColor(0.08, 0.10, 0.13, 0.95)
  sessionInfoButton:SetBackdropBorderColor(0.48, 0.58, 0.68, 0.85)
  local sessionInfoButtonText = sessionInfoButton:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  sessionInfoButtonText:SetPoint("CENTER", 0, 0)
  sessionInfoButtonText:SetText("i")
  sessionInfoButton:SetScript("OnEnter", function(self)
    if not GameTooltip then
      return
    end
    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
    GameTooltip:SetText("Session and synchronization", 1.00, 0.82, 0.28)
    GameTooltip:AddLine(tostring(editor.__lidSessionTooltipDetail or "No session is open."), 0.90, 0.92, 0.96, true)
    GameTooltip:AddLine(tostring(editor.__lidHeaderAutoPassDetail or "Personal Auto Pass: OFF."), 0.88, 0.90, 0.94, true)
    GameTooltip:AddLine(tostring(editor.__lidHeaderPendingRollDetail or "No roll choices waiting."), 1.00, 0.80, 0.34, true)
    GameTooltip:AddLine(tostring(editor.__lidLocalDataDetail or "No data to push."), 0.78, 0.84, 0.90, true)
    GameTooltip:AddLine(tostring(editor.__lidSyncDetail or "Sync is idle."), 0.78, 0.84, 0.90, true)
    GameTooltip:Show()
  end)
  sessionInfoButton:SetScript("OnLeave", function()
    if GameTooltip then
      GameTooltip:Hide()
    end
  end)
  editor.sessionInfoButton = sessionInfoButton

  editor.IsHeaderMonitoringEnabled = function()
    if type(editor.__lidHeaderMonitoringEnabled) == "boolean" then
      return editor.__lidHeaderMonitoringEnabled
    end
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    if not ui then
      return true
    end
    if type(ui.headerMonitoringEnabled) ~= "boolean" then
      ui.headerMonitoringEnabled = true
    end
    editor.__lidHeaderMonitoringEnabled = ui.headerMonitoringEnabled ~= false
    return editor.__lidHeaderMonitoringEnabled
  end

  editor.ApplyHeaderMonitoringVisibility = function()
    local monitoringEnabled = editor:IsHeaderMonitoringEnabled()
    local collapsed = editor.__collapsed == true

    if sessionInfoCard then
      if collapsed then
        sessionInfoCard:ClearAllPoints()
        sessionInfoCard:SetPoint("TOPLEFT", editor, "TOPLEFT", 16, -12)
        sessionInfoCard:SetSize(monitoringEnabled and 188 or 246, monitoringEnabled and 58 or 46)
      else
        sessionInfoCard:SetHeight(monitoringEnabled and 96 or 46)
        if editor.UpdateSessionInfoCardLayout then
          editor:UpdateSessionInfoCardLayout()
        end
      end
      -- The card is also the parent of title/version. Keep it shown when
      -- monitoring is disabled, but remove all monitor-only visuals below.
      sessionInfoCard:Show()
    end

    if sessionInfoCardBg then
      sessionInfoCardBg:SetShown(monitoringEnabled)
    end
    for _, region in ipairs(type(editor.sessionInfoCardChrome) == "table" and editor.sessionInfoCardChrome or {}) do
      region:SetShown(monitoringEnabled and not collapsed)
    end
    if title then
      title:ClearAllPoints()
      title:SetPoint("TOPLEFT", sessionInfoCard, "TOPLEFT", collapsed and 0 or 10, collapsed and -2 or -6)
      title:SetPoint("TOPRIGHT", sessionInfoCard, "TOPRIGHT", monitoringEnabled and -56 or -10, collapsed and -2 or -6)
      title:SetShown(monitoringEnabled and not collapsed or not monitoringEnabled)
    end
    if versionText then
      versionText:ClearAllPoints()
      versionText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -1)
      versionText:SetWidth(monitoringEnabled and 360 or 230)
      versionText:SetShown(monitoringEnabled and not collapsed or not monitoringEnabled)
    end

    if sessionStatusBadge then sessionStatusBadge:SetShown(monitoringEnabled) end
    if sessionStatusMeta then sessionStatusMeta:SetShown(monitoringEnabled) end
    if localDataText then
      localDataText:SetShown(monitoringEnabled and editor.__lidLocalDataVisible == true and not collapsed)
    end
    if syncActivityText then syncActivityText:SetShown(monitoringEnabled) end
    if syncActivityBar then
      syncActivityBar:SetShown(monitoringEnabled and syncActivityBar.__lidSyncVisible == true)
    end
    if sessionInfoButton then sessionInfoButton:SetShown(monitoringEnabled) end
    if headerAutoPassIconFrame then headerAutoPassIconFrame:SetShown(monitoringEnabled) end
    if headerRollPendingIconFrame then
      headerRollPendingIconFrame:SetShown(monitoringEnabled and (tonumber(editor.__lidHeaderPendingRollCount) or 0) > 0)
    end
    if editor.SetHeaderAutoPassIcon then
      editor:SetHeaderAutoPassIcon(editor.__lidHeaderAutoPassEnabled, editor.__lidHeaderAutoPassVisible)
    end
    if editor.SetHeaderRollPendingIndicator then
      editor:SetHeaderRollPendingIndicator(editor.__lidHeaderPendingRollCount)
    end
  end

  editor.SetHeaderMonitoringEnabled = function(self, enabled)
    local requestedEnabled = type(self) == "table" and enabled or self
    editor.__lidHeaderMonitoringEnabled = requestedEnabled ~= false
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    if ui then
      ui.headerMonitoringEnabled = editor.__lidHeaderMonitoringEnabled
    end
    if IsEditorCombatLocked() then
      editor.__lidHeaderMonitoringDeferred = true
      return false
    end
    editor.__lidHeaderMonitoringDeferred = nil
    editor:ApplyHeaderMonitoringVisibility()
    return true
  end
  editor:ApplyHeaderMonitoringVisibility()

  local sessionFrameAccent = CreateFrame("Frame", nil, editor, "BackdropTemplate")
  sessionFrameAccent:SetPoint("TOPLEFT", editor, "TOPLEFT", 3, -3)
  sessionFrameAccent:SetPoint("BOTTOMRIGHT", editor, "BOTTOMRIGHT", -3, 3)
  sessionFrameAccent:SetFrameLevel((editor.GetFrameLevel and editor:GetFrameLevel() or 0) + 30)
  sessionFrameAccent:SetBackdrop({
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    edgeSize = 2,
  })
  sessionFrameAccent:SetBackdropBorderColor(0.28, 0.92, 0.42, 0.62)
  sessionFrameAccent:EnableMouse(false)
  sessionFrameAccent:Hide()
  editor.sessionFrameAccent = sessionFrameAccent
  ApplyEditorLogo()

  editor:HookScript("OnUpdate", function(frame, elapsed)
    if not frame:IsShown() then
      return
    end
    if frame.__lidHeaderMonitoringDeferred == true and not IsEditorCombatLocked() then
      frame.__lidHeaderMonitoringDeferred = nil
      if type(frame.ApplyHeaderMonitoringVisibility) == "function" then
        frame:ApplyHeaderMonitoringVisibility()
      end
    end
    frame.__lidSyncBannerRefreshElapsed = (tonumber(frame.__lidSyncBannerRefreshElapsed) or 0)
      + math.max(0, tonumber(elapsed) or 0)
    -- With no session open there is no automatic profile traffic to watch.
    -- Poll slowly in that stable state; explicit session/profile events still
    -- refresh the banner immediately, while active sessions retain 0.5s data.
    local refreshInterval = frame.__lidSessionPresentationState == "inactive" and 10.0 or 0.50
    if frame.__lidSyncBannerRefreshElapsed < refreshInterval then
      return
    end
    frame.__lidSyncBannerRefreshElapsed = 0
    if IsEditorCombatLocked() then
      return
    end
    local refreshSyncActivity = frame.RefreshSyncActivityBanner
    if type(refreshSyncActivity) ~= "function" then
      return
    end
    local ok, err = pcall(refreshSyncActivity, frame)
    if not ok and frame.__lidSyncBannerRefreshFailureLogged ~= true then
      frame.__lidSyncBannerRefreshFailureLogged = true
      LogShellFailure("Editor sync activity refresh failed: " .. tostring(err))
    elseif ok then
      frame.__lidSyncBannerRefreshFailureLogged = nil
    end
    if frame.currentPage == "Panels" and frame.lootSessionSection == "CURRENT"
      and type(frame.RefreshCurrentSessionPriorityTelemetry) == "function"
    then
      local telemetryOk, telemetryErr = pcall(frame.RefreshCurrentSessionPriorityTelemetry, frame)
      if not telemetryOk and frame.__lidPriorityTelemetryRefreshFailureLogged ~= true then
        frame.__lidPriorityTelemetryRefreshFailureLogged = true
        LogShellFailure("Current-session priority telemetry refresh failed: " .. tostring(telemetryErr))
      elseif telemetryOk then
        frame.__lidPriorityTelemetryRefreshFailureLogged = nil
      end
    end
    if frame.currentPage == "Panels" and frame.lootSessionSection == "CURRENT"
      and type(frame.RefreshCurrentSessionRosterIfChanged) == "function"
    then
      local rosterOk, rosterErr = pcall(frame.RefreshCurrentSessionRosterIfChanged, frame)
      if not rosterOk and frame.__lidCurrentSessionRosterRefreshFailureLogged ~= true then
        frame.__lidCurrentSessionRosterRefreshFailureLogged = true
        LogShellFailure("Current-session roster refresh failed: " .. tostring(rosterErr))
      elseif rosterOk then
        frame.__lidCurrentSessionRosterRefreshFailureLogged = nil
      end
    end
  end)

  local close = CreateFrame("Button", nil, editor, "UIPanelCloseButton")
  close:SetSize(20, 20)
  close:SetPoint("TOPRIGHT", -2, -2)
  close:SetScript("OnClick", function() editor:Hide() end)

  local collapseBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapseBtn:SetSize(70, 20)
  collapseBtn:SetPoint("RIGHT", close, "LEFT", -4, 0)
  collapseBtn:SetText("Collapse ^")
  editor.collapseBtn = collapseBtn

  local collapsedExpandBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapsedExpandBtn:SetSize(74, 22)
  collapsedExpandBtn:SetText("Expand")
  collapsedExpandBtn:Hide()
  ApplyCollapsedEditorButtonStyle(collapsedExpandBtn)
  editor.collapsedExpandBtn = collapsedExpandBtn

  local collapsedCloseBtn = CreateFrame("Button", nil, editor, "UIPanelButtonTemplate")
  collapsedCloseBtn:SetSize(70, 22)
  collapsedCloseBtn:SetText("Close")
  collapsedCloseBtn:SetScript("OnClick", function() editor:Hide() end)
  collapsedCloseBtn:Hide()
  ApplyCollapsedEditorButtonStyle(collapsedCloseBtn)
  editor.collapsedCloseBtn = collapsedCloseBtn

  editor:SetScript("OnShow", function()
    if SetAllUnlocked and not IsEditorCombatLocked() then
      SetAllUnlocked(GetPanelsUnlockedState())
    end
    ApplyEditorScale(editor)
    UpdateCombatLimitedNotice()
  end)

  editor:SetScript("OnHide", function()
    if SetAllUnlocked and not IsEditorCombatLocked() then
      SetAllUnlocked(GetPanelsUnlockedState())
    end
    UpdateCombatLimitedNotice()
  end)

  editor:EnableKeyboard(true)
  SetPropagateKeyboardInputSafe(editor, true)
  editor:SetScript("OnKeyDown", function(self, key)
    if not self:IsShown() then return end
    if IsEditorCombatLocked() then
      UpdateCombatLimitedNotice()
      return
    end
    if self.currentPage ~= "Panels" or not self.allowKeyboardNudging then
      SetPropagateKeyboardInputSafe(self, true)
      return
    end

    local focus = GetCurrentKeyBoardFocus and GetCurrentKeyBoardFocus()
    if focus and focus.IsDescendantOf and focus:IsDescendantOf(self) then
      SetPropagateKeyboardInputSafe(self, true)
      return
    end

    local step = 1
    if IsShiftKeyDown and IsShiftKeyDown() then step = 10 end

    local deltaX, deltaY = 0, 0
    if key == "LEFT" then
      deltaX = -step
    elseif key == "RIGHT" then
      deltaX = step
    elseif key == "UP" then
      deltaY = step
    elseif key == "DOWN" then
      deltaY = -step
    else
      SetPropagateKeyboardInputSafe(self, true)
      return
    end

    local moved = false
    if NudgeSelectedPanel then
      moved = NudgeSelectedPanel(deltaX, deltaY)
    end
    SetPropagateKeyboardInputSafe(self, not moved)
  end)

  local headerHeight = math.max(math.floor(LOGO_TARGET_H * HEADER_LOGO_SCALE) + 18, 80)
  editor.headerHeight = headerHeight

  -- Retain the legacy frame for dependent refresh code, but keep profile
  -- context in the session banner instead of rendering a duplicate strip.
  local profileBarHeight = 0
  editor.profileBarHeight = profileBarHeight

  local headerBg = editor:CreateTexture(nil, "BACKGROUND")
  headerBg:SetPoint("TOPLEFT", editor, "TOPLEFT", 2, -2)
  headerBg:SetPoint("TOPRIGHT", editor, "TOPRIGHT", -2, -2)
  headerBg:SetHeight(headerHeight + profileBarHeight + 6)
  if headerBg.SetDrawLayer then headerBg:SetDrawLayer("ARTWORK", -5) end
  headerBg:Hide()
  editor.headerBg = headerBg

  local profileBar = CreateFrame("Frame", nil, editor, "BackdropTemplate")
  profileBar:SetPoint("TOPLEFT", 12, -headerHeight)
  profileBar:SetPoint("TOPRIGHT", -12, -headerHeight)
  profileBar:SetHeight(1)
  profileBar:SetBackdrop({
    bgFile = "Interface/Buttons/WHITE8x8",
    edgeFile = "Interface/Buttons/WHITE8x8",
    tile = false, edgeSize = 1,
    insets = { left = 1, right = 1, top = 1, bottom = 1 }
  })
  profileBar:SetBackdropColor(0.06, 0.06, 0.08, 0.80)
  profileBar:SetBackdropBorderColor(0, 0, 0, 0.7)
  editor.profileBar = profileBar
  profileBar:Hide()

  local combatNotice = editor:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  combatNotice:SetPoint("BOTTOMLEFT", profileBar, "TOPLEFT", 0, 4)
  combatNotice:SetPoint("BOTTOMRIGHT", profileBar, "TOPRIGHT", 0, 4)
  combatNotice:SetJustifyH("LEFT")
  combatNotice:SetTextColor(1.00, 0.78, 0.28, 1.00)
  combatNotice:SetText("Combat active: editor layout controls are temporarily limited.")
  combatNotice:Hide()
  editor.combatNotice = combatNotice
  UpdateCombatLimitedNotice()

  editor:RegisterEvent("PLAYER_REGEN_DISABLED")
  editor:RegisterEvent("PLAYER_REGEN_ENABLED")
  editor:SetScript("OnEvent", function()
    UpdateCombatLimitedNotice()
    if not IsEditorCombatLocked() and editor.__lidBannerDiagnosticsDeferred and type(editor.RefreshLootWorkflowSections) == "function" then
      editor.__lidBannerDiagnosticsDeferred = nil
      editor:RefreshLootWorkflowSections()
    end
  end)

  local profileBarText = profileBar:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
  profileBarText:SetPoint("LEFT", 8, 0)
  profileBarText:SetText("Current Profile: " .. DisplayProfileName("Default"))
  editor.profileBarText = profileBarText

  local tabsOffset = headerHeight + profileBarHeight + 4
  local tabs = CreateFrame("Frame", nil, editor)
  tabs:SetPoint("TOPLEFT", 12, -tabsOffset)
  tabs:SetPoint("TOPRIGHT", -12, -tabsOffset)
  tabs:SetHeight(24)

  local tabDefs = {
    { key = "Profiles", field = "profilesTab", text = "Profile", width = 100 },
    { key = "Panels", field = "panelsTab", text = "Session", width = 100 },
    { key = "LiveBoard", field = "liveBoardTab", text = "Live Board", width = 110 },
    { key = "Backgrounds", field = "backgroundsTab", text = "Loot List", width = 120 },
    { key = "LootPresets", field = "lootPresetsTab", text = "Loot Presets", width = 120 },
    { key = "UI", field = "uiTab", text = "UI Settings", width = 120 },
    { key = "Tutorial", field = "tutorialTab", text = "Tutorial", width = 100 },
    { key = "About", field = "aboutTab", text = "About", width = 100 },
  }

  editor.mainTabs = {}
  local previousTab
  for _, def in ipairs(tabDefs) do
    local button = CreateMainTab(tabs, previousTab, def)
    editor[def.field] = button
    editor.mainTabs[def.key] = button
    AttachTabActiveBorder(button)
    previousTab = button
  end

  function editor:UpdateMainTabHighlight()
    local activePage = self.currentPage or "Profiles"
    local palette = GetEditorThemePalette and GetEditorThemePalette() or nil
    local useLootPilot = type(palette) == "table" and (palette.key == "lootpilot" or palette.key == "white_orange")
    local activeColor = useLootPilot and (palette.text or { 1, 1, 1, 1 }) or { 1.00, 0.82, 0.28, 1.00 }
    local borderColor = { 0.40, 0.66, 0.98, 0.96 }
    local activeR = activeColor[1] or 0.6588
    local activeG = activeColor[2] or 0.4784
    local activeB = activeColor[3] or 0.9098
    for page, button in pairs(self.mainTabs or {}) do
      local isActive = (page == activePage)
      if button.__activeBorder then
        button.__activeBorder:SetShown(isActive)
        if button.__activeBorder.SetBackdropBorderColor then
          button.__activeBorder:SetBackdropBorderColor(
            borderColor[1] or activeR,
            borderColor[2] or activeG,
            borderColor[3] or activeB,
            borderColor[4] or 0.95
          )
        end
      end
      if button.__activeUnderline then
        button.__activeUnderline:SetShown(isActive)
      end

      local fontString = button.GetFontString and button:GetFontString()
      if fontString then
        if useLootPilot then
          fontString:SetTextColor(1, 1, 1, 1)
        elseif isActive then
          fontString:SetTextColor(activeR, activeG, activeB, 1)
        else
          fontString:SetTextColor(1, 1, 1, 1)
        end
      end
    end
  end

  local scrollFrame = CreateFrame("ScrollFrame", nil, editor, "UIPanelScrollFrameTemplate")
  scrollFrame:SetPoint("TOPLEFT", 12, -(tabsOffset + 30))
  scrollFrame:SetPoint("BOTTOMRIGHT", -12, 12)
  scrollFrame:EnableMouseWheel(false)
  scrollFrame:SetScript("OnMouseWheel", function(self, delta)
    local scrollBar = self.ScrollBar
    if not scrollBar then return end
    local current = scrollBar:GetValue()
    local minValue, maxValue = scrollBar:GetMinMaxValues()
    local nextValue = current - (delta * 20)
    if nextValue < minValue then nextValue = minValue end
    if nextValue > maxValue then nextValue = maxValue end
    scrollBar:SetValue(nextValue)
  end)

  local scrollChild = CreateFrame("Frame", nil, scrollFrame)
  scrollChild:SetSize(1, 1)
  scrollFrame:SetScrollChild(scrollChild)

  editor.scrollFrame = scrollFrame
  editor.scrollChild = scrollChild

  local panelsPage, panelsTitle, panelsCurrentLabel = CreateRootPage(scrollChild, "Session")
  local liveBoardPage, liveBoardTitle, liveBoardCurrentLabel = CreateRootPage(scrollChild, "Live Board")
  local backgroundsPage, backgroundsTitle, backgroundsCurrentLabel = CreateRootPage(scrollChild, "Loot List")
  local lootPresetsPage, lootPresetsTitle, lootPresetsCurrentLabel = CreateRootPage(scrollChild, "Loot Presets")
  local profilesPage, profilesTitle, profilesCurrentLabel = CreateRootPage(scrollChild, "Profile")
  local uiPage, uiPageTitle, uiCurrentLabel = CreateRootPage(scrollChild, "UI Settings")
  local tutorialPage, tutorialPageTitle, tutorialCurrentLabel = CreateRootPage(scrollChild, "Tutorial")
  local aboutPage, aboutPageTitle, aboutCurrentLabel = CreateRootPage(scrollChild, "About")

  liveBoardPage:Hide()
  backgroundsPage:Hide()
  lootPresetsPage:Hide()
  profilesPage:Hide()
  uiPage:Hide()
  tutorialPage:Hide()
  aboutPage:Hide()

  editor.panelsPage = panelsPage
  editor.liveBoardPage = liveBoardPage
  editor.profilesPage = profilesPage
  editor.backgroundsPage = backgroundsPage
  editor.lootPresetsPage = lootPresetsPage
  editor.uiPage = uiPage
  editor.tutorialPage = tutorialPage
  editor.aboutPage = aboutPage

  editor.profilesTitle = profilesTitle
  editor.profilesCurrentLabel = profilesCurrentLabel
  editor.panelsTitle = panelsTitle
  editor.panelsCurrentLabel = panelsCurrentLabel
  editor.liveBoardTitle = liveBoardTitle
  editor.liveBoardCurrentLabel = liveBoardCurrentLabel
  editor.backgroundsTitle = backgroundsTitle
  editor.backgroundsCurrentLabel = backgroundsCurrentLabel
  editor.lootPresetsTitle = lootPresetsTitle
  editor.lootPresetsCurrentLabel = lootPresetsCurrentLabel
  editor.uiPageTitle = uiPageTitle
  editor.uiCurrentLabel = uiCurrentLabel
  editor.tutorialPageTitle = tutorialPageTitle
  editor.tutorialCurrentLabel = tutorialCurrentLabel
  editor.aboutPageTitle = aboutPageTitle
  editor.aboutCurrentLabel = aboutCurrentLabel

  local pages = {
    Panels = panelsPage,
    LiveBoard = liveBoardPage,
    Profiles = profilesPage,
    Backgrounds = backgroundsPage,
    LootPresets = lootPresetsPage,
    UI = uiPage,
    Tutorial = tutorialPage,
    About = aboutPage,
  }
  editor.pages = pages

  local function UpdateScrollChildSize(height)
    if type(height) ~= "number" then height = 800 end
    local width = (scrollFrame.GetWidth and scrollFrame:GetWidth()) or 1
    width = math.max(1, math.floor(width))
    local finalHeight = math.max(1, height)
    scrollChild:SetSize(width, finalHeight)
    if scrollFrame.UpdateScrollChildRect then scrollFrame:UpdateScrollChildRect() end
  end
  editor.UpdateScrollChildSize = UpdateScrollChildSize

  local function UpdateScrollLayout(selfOrSkipPageLayout, skipPageLayoutArg)
    if editor.__collapsed then return end
    if editor.__updatingScrollLayout then return end
    editor.__updatingScrollLayout = true

    -- Page refreshers already lay out their own content. They pass true as
    -- the second colon-call argument to avoid immediately rebuilding it.
    local skipPageLayout = selfOrSkipPageLayout == true or skipPageLayoutArg == true

    local currentPage = editor.currentPage or "Panels"
    local viewHeight = (scrollFrame.GetHeight and scrollFrame:GetHeight()) or 800
    local useViewportHeight = (
      currentPage == "Panels"
      or currentPage == "UI"
      or currentPage == "Tutorial"
      or currentPage == "About"
    )
    UpdateScrollChildSize(viewHeight)

    if not skipPageLayout then
      if currentPage == "Profiles" and editor.LayoutLootProfilePage then
        editor:LayoutLootProfilePage()
      elseif currentPage == "Panels" and editor.LayoutLootSessionPage then
        editor:LayoutLootSessionPage()
      elseif currentPage == "LiveBoard" and editor.LayoutLootLiveBoardPage then
        editor:LayoutLootLiveBoardPage()
      elseif currentPage == "Backgrounds" and editor.RefreshLootListPage then
        editor:RefreshLootListPage()
      end
    end

    if currentPage == "Tutorial" and editor.ShowTutorialSection then
      editor:ShowTutorialSection(editor.tutorialSection or "Beginner")
    end

    local currentFrame = pages[currentPage]
    local contentHeight = (currentFrame and currentFrame.__contentHeight) or viewHeight

    local targetHeight = useViewportHeight and viewHeight or math.max(contentHeight, viewHeight)
    editor.currentPageHeight = targetHeight
    if targetHeight ~= viewHeight then
      UpdateScrollChildSize(targetHeight)
    end
    local useOuterScroll = currentPage == "LiveBoard"
    local showOuterScroll = useOuterScroll and targetHeight > (viewHeight + 1)
    scrollFrame:EnableMouseWheel(useOuterScroll)
    if scrollFrame.ScrollBar then
      scrollFrame.ScrollBar:SetShown(showOuterScroll)
      if not showOuterScroll and scrollFrame.ScrollBar.SetValue then
        scrollFrame.ScrollBar:SetValue(0)
      end
    end

    editor.__updatingScrollLayout = false
  end
  editor.UpdateScrollLayout = UpdateScrollLayout

  local function SetEditorCollapsed(collapsed)
    local nextCollapsed = collapsed == true
    if editor.__collapsed == nextCollapsed then
      return
    end

    AnchorEditorToCurrentTopLeft()

    editor.__collapsed = nextCollapsed
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    if ui then
      ui.editor = type(ui.editor) == "table" and ui.editor or {}
      ui.editor.collapsed = nextCollapsed
    end

    if nextCollapsed then
      editor.__expandedW = editor:GetWidth()
      editor.__expandedH = editor:GetHeight()
      SetEditorBackdropVisible(true)
      if headerBg then headerBg:Hide() end
      if logo then logo:Hide() end
      if activeSessionLogo then activeSessionLogo:Hide() end
      if sessionInfoCard then
        sessionInfoCard:ClearAllPoints()
        sessionInfoCard:SetPoint("TOPLEFT", editor, "TOPLEFT", 16, -12)
        sessionInfoCard:SetSize(188, 58)
        sessionInfoCard:Show()
      end
      if sessionInfoCardBg then
        if editor.ApplySessionInfoCardBackground then
          editor:ApplySessionInfoCardBackground(0.68)
        end
        sessionInfoCardBg:Show()
      end
      for _, region in ipairs(type(editor.sessionInfoCardChrome) == "table" and editor.sessionInfoCardChrome or {}) do
        region:Hide()
      end
      if sessionFrameAccent then sessionFrameAccent:Hide() end
      if title then
        title:Hide()
      end
      if versionText then
        versionText:Hide()
      end
      if sessionStatusBadge then
        sessionStatusBadge:ClearAllPoints()
        sessionStatusBadge:SetPoint("TOPLEFT", sessionInfoCard, "TOPLEFT", 0, -2)
      end
      if sessionStatusMeta then
        sessionStatusMeta:ClearAllPoints()
        sessionStatusMeta:SetPoint("LEFT", sessionStatusBadge, "RIGHT", 8, 0)
        sessionStatusMeta:SetPoint("RIGHT", sessionInfoCard, "RIGHT", -2, 0)
      end
      if localDataText then
        localDataText:Hide()
      end
      if syncActivityText then
        syncActivityText:ClearAllPoints()
        syncActivityText:SetPoint("TOPLEFT", sessionStatusBadge, "BOTTOMLEFT", 24, -3)
        syncActivityText:SetWidth(164)
      end
      if syncActivityBar then
        syncActivityBar:ClearAllPoints()
        syncActivityBar:SetPoint("TOPLEFT", syncActivityText, "BOTTOMLEFT", 0, -2)
        syncActivityBar:SetWidth(164)
      end
      if sessionInfoButton then
        sessionInfoButton:ClearAllPoints()
        sessionInfoButton:SetPoint("TOPLEFT", sessionStatusBadge, "BOTTOMLEFT", 0, -3)
      end
      if editor.SetHeaderAutoPassIcon then
        editor:SetHeaderAutoPassIcon(editor.__lidHeaderAutoPassEnabled, editor.__lidHeaderAutoPassVisible)
      end
      profileBar:Hide()
      tabs:Hide()
      scrollFrame:Hide()
      if resizeGrip then resizeGrip:Hide() end
      if editor.SetResizable then editor:SetResizable(false) end
      if editor.SetMinResize then editor:SetMinResize(380, 84) end
      editor:SetSize(380, 84)
      if close then close:Hide() end
      if collapseBtn then collapseBtn:Hide() end
      if collapsedCloseBtn then
        collapsedCloseBtn:ClearAllPoints()
        collapsedCloseBtn:SetPoint("TOPRIGHT", -16, -12)
        collapsedCloseBtn:Show()
        UpdateCollapsedEditorButtonStyle(collapsedCloseBtn)
      end
      if collapsedExpandBtn then
        collapsedExpandBtn:ClearAllPoints()
        collapsedExpandBtn:SetPoint("RIGHT", collapsedCloseBtn, "LEFT", -8, 0)
        collapsedExpandBtn:Show()
        UpdateCollapsedEditorButtonStyle(collapsedExpandBtn)
      end
      AnchorEditorToCurrentTopLeft()
      if type(editor.RefreshSyncActivityBanner) == "function" then
        editor:RefreshSyncActivityBanner()
      end
      if type(editor.ApplyHeaderMonitoringVisibility) == "function" then
        editor:ApplyHeaderMonitoringVisibility()
      end
      return
    end

    SetEditorBackdropVisible(true)
    ApplyEditorLogo()
    if sessionInfoCard then
      sessionInfoCard:SetHeight(96)
      if editor.UpdateSessionInfoCardLayout then
        editor:UpdateSessionInfoCardLayout()
      end
      sessionInfoCard:Show()
    end
    if sessionInfoCardBg then
      if editor.ApplySessionInfoCardBackground then
        editor:ApplySessionInfoCardBackground(0.70)
      end
      sessionInfoCardBg:Show()
    end
    for _, region in ipairs(type(editor.sessionInfoCardChrome) == "table" and editor.sessionInfoCardChrome or {}) do
      region:Show()
    end
    if title then
      title:Show()
      title:ClearAllPoints()
      title:SetPoint("TOPLEFT", sessionInfoCard, "TOPLEFT", 10, -6)
      title:SetPoint("TOPRIGHT", sessionInfoCard, "TOPRIGHT", -56, -6)
      title:SetText("LidCouncil Version " .. ADDON_VERSION)
    end
    if versionText then
      versionText:Show()
      versionText:ClearAllPoints()
      versionText:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -1)
      versionText:SetWidth(360)
      versionText:SetJustifyH("LEFT")
      versionText:SetText("v" .. WOW_CLIENT_VERSION)
    end
    if sessionStatusBadge then
      sessionStatusBadge:ClearAllPoints()
      sessionStatusBadge:SetPoint("TOPLEFT", versionText, "BOTTOMLEFT", 0, -4)
    end
    if sessionStatusMeta then
      sessionStatusMeta:ClearAllPoints()
      sessionStatusMeta:SetPoint("LEFT", sessionStatusBadge, "RIGHT", 8, 0)
      sessionStatusMeta:SetPoint("RIGHT", sessionInfoCard, "RIGHT", -10, 0)
    end
    if localDataText then
      localDataText:ClearAllPoints()
      localDataText:SetPoint("TOPLEFT", sessionStatusBadge, "BOTTOMLEFT", 0, -3)
    end
    if syncActivityText then
      syncActivityText:ClearAllPoints()
      syncActivityText:SetPoint("TOPLEFT", localDataText, "BOTTOMLEFT", 24, -1)
    end
    if syncActivityBar then
      syncActivityBar:ClearAllPoints()
      syncActivityBar:SetPoint("TOPLEFT", syncActivityText, "BOTTOMLEFT", 0, -2)
    end
    if sessionInfoButton then
      sessionInfoButton:ClearAllPoints()
      sessionInfoButton:SetPoint("TOPLEFT", localDataText, "BOTTOMLEFT", 0, -3)
    end
    if editor.SetHeaderAutoPassIcon then
      editor:SetHeaderAutoPassIcon(editor.__lidHeaderAutoPassEnabled, editor.__lidHeaderAutoPassVisible)
    end
    if collapsedExpandBtn then collapsedExpandBtn:Hide() end
    if collapsedCloseBtn then collapsedCloseBtn:Hide() end
    profileBar:Hide()
    tabs:Show()
    scrollFrame:Show()
    if resizeGrip then resizeGrip:Show() end
    if editor.SetResizable then editor:SetResizable(true) end
    if editor.SetMinResize then editor:SetMinResize(520, 340) end
    if close then
      close:SetSize(20, 20)
      close:ClearAllPoints()
      close:SetPoint("TOPRIGHT", -2, -2)
      close:Show()
    end
    if collapseBtn then
      collapseBtn:SetSize(70, 20)
      collapseBtn:ClearAllPoints()
      collapseBtn:SetPoint("RIGHT", close, "LEFT", -4, 0)
      collapseBtn:Show()
    end
    local restoreW = tonumber(editor.__expandedW)
    local restoreH = tonumber(editor.__expandedH)
    if restoreW and restoreH then
      local clampedW, clampedH = ClampEditorSize(restoreW, restoreH)
      editor:SetSize(clampedW, clampedH)
    end
    if collapseBtn then collapseBtn:SetText("Collapse ^") end
    AnchorEditorToCurrentTopLeft()
    SaveEditorState(editor)
    UpdateScrollLayout()
    if type(editor.RefreshSyncActivityBanner) == "function" then
      editor:RefreshSyncActivityBanner()
    end
    if type(editor.ApplyHeaderMonitoringVisibility) == "function" then
      editor:ApplyHeaderMonitoringVisibility()
    end
  end
  editor.SetEditorCollapsed = SetEditorCollapsed

  if collapseBtn then
    collapseBtn:SetScript("OnClick", function()
      SetEditorCollapsed(not editor.__collapsed)
    end)
  end
  if collapsedExpandBtn then
    collapsedExpandBtn:SetScript("OnClick", function()
      SetEditorCollapsed(false)
    end)
  end

  do
    local root = type(RootDB) == "function" and RootDB() or nil
    local ui = type(root) == "table" and type(root.ui) == "table" and root.ui or nil
    local st = type(ui) == "table" and type(ui.editor) == "table" and ui.editor or nil
    if type(st) == "table" and st.collapsed == true then
      editor.__collapsed = false
      SetEditorCollapsed(true)
    end
  end

  if type(BuildTutorialPage) == "function" then
    BuildTutorialPage(editor, tutorialPage)
  end

  local workflowPages = {
    Profiles = true,
    Panels = true,
    LiveBoard = true,
    Backgrounds = true,
    LootPresets = true,
  }

  local function RefreshVisiblePage(self)
    local owner = type(self) == "table" and self or editor
    local which = tostring(owner.currentPage or "Profiles")
    local workflowRefreshed = false

    if workflowPages[which] and type(owner.RefreshLootWorkflowSections) == "function" then
      owner:RefreshLootWorkflowSections({
        refreshPages = {
          [which] = true,
        },
      })
      workflowRefreshed = true
    elseif which == "UI" and type(owner.UpdateUILayout) == "function" then
      owner:UpdateUILayout()
    elseif which == "Tutorial" and type(owner.ShowTutorialSection) == "function" then
      owner:ShowTutorialSection(owner.tutorialSection or "Beginner")
    elseif which == "About" then
      if type(owner.RefreshAbout) == "function" then
        owner:RefreshAbout()
      end
      if type(owner.ShowAboutSection) == "function" then
        owner:ShowAboutSection(owner.aboutSection or "Overview")
      end
    end

    if not workflowRefreshed and owner.UpdateScrollLayout then
      owner:UpdateScrollLayout()
    end
    if owner.ApplyTheme and not workflowRefreshed then
      owner:ApplyTheme()
    end
    if owner.ApplyHeaderMonitoringVisibility then
      owner:ApplyHeaderMonitoringVisibility()
    end
    if owner.UpdateMainTabHighlight then
      owner:UpdateMainTabHighlight()
    end
  end

  local function ShowPage(which)
    for pageName, page in pairs(pages) do
      page:SetShown(pageName == which)
    end

    editor.currentPage = which
    if which == "LiveBoard" and type(RootDB) == "function" then
      local root = RootDB()
      root.ui = root.ui or {}
      root.ui.lootLiveBoardMode = "EMBEDDED"
      root.ui.lootLiveBoardView = "BOARD"
    end
    if which == "About" then
      editor.aboutSection = "Overview"
    end
    RefreshVisiblePage(editor)
    scrollFrame:SetVerticalScroll(0)
  end

  editor.ShowPage = ShowPage
  editor.RefreshVisiblePage = RefreshVisiblePage
  editor.profilesTab:SetScript("OnClick", function() ShowPage("Profiles") end)
  editor.panelsTab:SetScript("OnClick", function() ShowPage("Panels") end)
  editor.liveBoardTab:SetScript("OnClick", function() ShowPage("LiveBoard") end)
  editor.backgroundsTab:SetScript("OnClick", function() ShowPage("Backgrounds") end)
  editor.lootPresetsTab:SetScript("OnClick", function() ShowPage("LootPresets") end)
  editor.uiTab:SetScript("OnClick", function() ShowPage("UI") end)
  editor.tutorialTab:SetScript("OnClick", function() ShowPage("Tutorial") end)
  editor.aboutTab:SetScript("OnClick", function() ShowPage("About") end)

  return {
    panelsPage = panelsPage,
    liveBoardPage = liveBoardPage,
    profilesPage = profilesPage,
    backgroundsPage = backgroundsPage,
    lootPresetsPage = lootPresetsPage,
    uiPage = uiPage,
    tutorialPage = tutorialPage,
    aboutPage = aboutPage,
  }
end

INTERNAL_API.LIDCOUNCIL_SetupEditorFrameShell = SetupEditorFrameShell
