-- LidCouncil_Editor_RefreshSections.lua
-- Split from Editor.lua to isolate editor section wiring and refresh logic.

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

INTERNAL_API.LIDCOUNCIL_WireEditorRefreshSections = function(editor, deps)
  local GetEditorThemePalette = type(INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl) == "function"
    and INTERNAL_API.LIDCOUNCIL_GetEditorThemePalette_Impl
    or nil
  local RootDB = deps.RootDB
  local DB = deps.DB
  local GetDebugStore = deps.GetDebugStore
  local ReportEditorRuntimeError = deps.ReportEditorRuntimeError
  local GetPanelsUnlockedState = deps.GetPanelsUnlockedState
  local EnsureGradientTables = deps.EnsureGradientTables
  local SetDropdownSelection = deps.SetDropdownSelection
  local DisplayProfileName = deps.DisplayProfileName
  local GetEnabledLootProfileName = deps.GetEnabledLootProfileName
  local ADDON_VERSION = deps.ADDON_VERSION
  local WOW_CLIENT_VERSION = deps.WOW_CLIENT_VERSION
  local LISTS_PER_PAGE = deps.LISTS_PER_PAGE
  local GetSortedPanelNames = deps.GetSortedPanelNames
  local GetListPageForValue = deps.GetListPageForValue
  local ClampListPage = deps.ClampListPage
  local MakeListButton = deps.MakeListButton
  local MakeSimpleListButton = deps.MakeSimpleListButton
  local MakeProfileButton = deps.MakeProfileButton
  local SelectPanel = deps.SelectPanel
  local UpdatePagerControls = deps.UpdatePagerControls
  local ListBackgroundCategories = deps.ListBackgroundCategories
  local FindCategoryIndex = deps.FindCategoryIndex
  local FindBackgroundCategoryGroupIndex = deps.FindBackgroundCategoryGroupIndex
  local EnsureBackgroundCategoryGroups = deps.EnsureBackgroundCategoryGroups
  local BuildVisibleBackgroundCategoryRows = deps.BuildVisibleBackgroundCategoryRows
  local GetBackgroundCategoryFocusKey = deps.GetBackgroundCategoryFocusKey
  local ToggleBackgroundCategoryGroupCollapsed = deps.ToggleBackgroundCategoryGroupCollapsed
  local ConfigureBackgroundCategoryGroupButton = deps.ConfigureBackgroundCategoryGroupButton
  local BeginBackgroundCategoryGroupDrag = deps.BeginBackgroundCategoryGroupDrag
  local BeginBackgroundCategoryDrag = deps.BeginBackgroundCategoryDrag
  local SelectBackground = deps.SelectBackground
  local GetSortedBackgroundNames = deps.GetSortedBackgroundNames
  local ListBackgrounds = deps.ListBackgrounds
  local FindProfileGroupIndex = deps.FindProfileGroupIndex
  local EnsureProfileGroups = deps.EnsureProfileGroups
  local BuildVisibleProfileRows = deps.BuildVisibleProfileRows
  local GetProfileFocusKey = deps.GetProfileFocusKey
  local ToggleProfileGroupCollapsed = deps.ToggleProfileGroupCollapsed
  local ConfigureProfileGroupButton = deps.ConfigureProfileGroupButton
  local BeginProfileGroupDrag = deps.BeginProfileGroupDrag
  local InvalidateSortedProfileNames = deps.InvalidateSortedProfileNames
  local InvalidateSortedPanelNames = deps.InvalidateSortedPanelNames
  local GetBackgroundPath = deps.GetBackgroundPath
  local CreatePurpleOutline = deps.CreatePurpleOutline

  local function GetDeveloperAccentHex()
    local palette = GetEditorThemePalette and GetEditorThemePalette() or nil
    local color = type(palette) == "table" and type(palette.aboutTitle) == "table"
      and palette.aboutTitle
      or { 0.6588, 0.4784, 0.9098, 1.0 }
    local function ToHex(component)
      local value = tonumber(component) or 1
      value = math.max(0, math.min(255, math.floor((value * 255) + 0.5)))
      return string.format("%02x", value)
    end
    return ToHex(color[1]) .. ToHex(color[2]) .. ToHex(color[3])
  end

  local function ApplyDeveloperAccentMarkup(text)
    return tostring(text or ""):gsub("|cffa87ae8", "|cff" .. GetDeveloperAccentHex())
  end

  local function GetSelectedPanelName()
    return deps.GetSelectedPanelName()
  end

  local function GetSelectedBackgroundName()
    return deps.GetSelectedBackgroundName()
  end

  local function SetSelectedBackgroundName(value)
    deps.SetSelectedBackgroundName(value)
  end

  local function GetSelectedBackgroundCategory()
    return deps.GetSelectedBackgroundCategory()
  end

  local function SetSelectedBackgroundCategory(value)
    deps.SetSelectedBackgroundCategory(value)
  end

  local function GetSelectedBackgroundCategoryGroup()
    return deps.GetSelectedBackgroundCategoryGroup()
  end

  local function SetSelectedBackgroundCategoryGroup(value)
    deps.SetSelectedBackgroundCategoryGroup(value)
  end

  function editor:UpdateBgPreviewLayout()
    if not self.bgPreviewFrame or not self.bgPreviewTex then
      return
    end
    local path = self.bgPreviewTex.__path
    if not path or path == "" then
      self.bgPreviewTex:SetAllPoints(true)
      return
    end
    local frameW = self.bgPreviewFrame:GetWidth() or 0
    local frameH = self.bgPreviewFrame:GetHeight() or 0
    if frameW <= 1 or frameH <= 1 then
      return
    end

    local texW, texH
    if C_Texture and C_Texture.GetFileIDFromPath and C_Texture.GetTextureInfo then
      local fileID = C_Texture.GetFileIDFromPath(path)
      if fileID then
        local w, h = C_Texture.GetTextureInfo(fileID)
        if type(w) == "table" then
          texW = w.width
          texH = w.height
        else
          texW = w
          texH = h
        end
      end
    end

    if not texW or not texH or texW <= 0 or texH <= 0 then
      self.bgPreviewTex:ClearAllPoints()
      self.bgPreviewTex:SetAllPoints(true)
      return
    end

    local scaleW = frameW / texW
    local scaleH = frameH / texH
    local scale = math.min(scaleW, scaleH)
    local drawW = math.floor(texW * scale)
    local drawH = math.floor(texH * scale)

    self.bgPreviewTex:ClearAllPoints()
    self.bgPreviewTex:SetPoint("CENTER", 0, 0)
    self.bgPreviewTex:SetSize(drawW, drawH)
  end

  function editor:RefreshAbout()
    if not self.aboutMeta then
      return
    end
    local root = RootDB()
    local debugStore = GetDebugStore()

    self.aboutMeta:SetText(ApplyDeveloperAccentMarkup(
      "|cffa87ae8Title:|r LidCouncil\n" ..
      "|cffa87ae8Version:|r " .. ADDON_VERSION .. "\n" ..
      "|cffa87ae8Author:|r Lidian\n" ..
      "|cffa87ae8WoW Client:|r " .. WOW_CLIENT_VERSION
    ))
    if self.aboutDesc then
      self.aboutDesc:SetText(ApplyDeveloperAccentMarkup([[|cffa87ae8About the creator:|r
My Name is Lidian and I'am playing World of Warcraft since mid-end Classic. The real hook came with Legion when M+ has been added to the game and brought a challenge next to raiding. Altough my interest in the game is focusing on M+ and Raid, I have an affection for a unique personal UI. 


We all know, each raid evening is different and the definition of happiness is written for every individual itself. 
Some find happiness in Progress. Some in Loot. Some in just spending time with their friends and just having a fun evening. In my experience, no matter which one of these are the major factor to a single raider - it is always a combination of all these factors. Only the ratio shifts.

I have found a rather respectful and exemplary guild to Raid with. Our progress is quite quick in Normal and Heroic while the mood is almost 100% of the time really enjoyful. But still – we faced the issue of dissatisfaction almost every time because of the Loot distribution. While it only affects a momentum – those situations still echoes for a while.

From what I observed is, that trying to memorize each raid and each item is impossible. This leads to unfair distribution and assignment of items. It also creates false feels regarding the question – who has already got a lot from the past raids – and who was left out. Making a list and scoresystem surely is the only way to collect and analyse proper data, but it’s a hell of an effort.

I remember back in the days that a DKP System was very popular – but many hated it. So anything close to one part of the DKP System, which includes the auctioneering part, was a major part of the bad reputation this system got.

Eventually i sat down and tried to build a personal scoresystem. I created this within an Excel which then was shared and updated manually while raiding. I’am not saying this list is perfect - but a major reduction of discussions about unfair loot distribution was noticeable. I believe a key factor is simply because the list provides full transparency to everyone and eliminates any "guessing" or "feeling". I surely recommend to use a list, in case you are struggeling with disatisfaction in your raid -  wether it’s LidCouncil or something else.

With this as a backstory, I believe the reason to create this AddOn has become obvious. It’s purpose is to automatize the loot list in order to reduce the manual work on the Excel file. While the AddOn will be publicly shared on CurseForge – i tried to make sure to create an AddOn which can be used by everyone. 


I hope you enjoy this AddOn as much as I do.]]))
    end

    local hasErrors = debugStore and debugStore.errors and #debugStore.errors > 0
    if not hasErrors then
      self.aboutStatusIcon:SetTexture("Interface/Buttons/UI-CheckBox-Check")
      self.aboutStatusIcon:SetVertexColor(0.2, 0.9, 0.2, 1)
      self.aboutStatusText:SetText("No errors found, yeayyyy :)")
      self.aboutStatusText:SetTextColor(0.2, 0.9, 0.2, 1)
    else
      self.aboutStatusIcon:SetTexture("Interface/RAIDFRAME/ReadyCheck-NotReady")
      self.aboutStatusIcon:SetVertexColor(1, 0.2, 0.2, 1)
      self.aboutStatusText:SetText("Errors detected. See details below.")
      self.aboutStatusText:SetTextColor(1, 0.2, 0.2, 1)
    end

    local infoLines = {}
    local okIcon = "|TInterface/RAIDFRAME/ReadyCheck-Ready:14:14:0:0|t"
    local failIcon = "|TInterface/RAIDFRAME/ReadyCheck-NotReady:14:14:0:0|t"
    local function iconFor(msg)
      local l = string.lower(tostring(msg or ""))
      if l:find("fail", 1, true) or l:find("error", 1, true) or l:find("missing", 1, true) then
        return failIcon
      end
      return okIcon
    end
    if debugStore and debugStore.info then
      for _, msg in ipairs(debugStore.info) do
        infoLines[#infoLines + 1] = iconFor(msg) .. " " .. tostring(msg)
      end
    end
    if #infoLines == 0 then
      infoLines[1] = okIcon .. " No status messages yet."
    end
    self.aboutDetails:SetText(table.concat(infoLines, "\n"))

    local errCount = (debugStore and debugStore.errors and #debugStore.errors) or 0
    if errCount == 0 then
      self.aboutErrors:SetText("No errors captured.")
    else
      self.aboutErrors:SetText("Errors captured: " .. tostring(errCount))
    end

    local silentCount = (debugStore and debugStore.silent and #debugStore.silent) or 0
    if self.aboutSilent then
      local devMode = (root and root.ui and root.ui.developerMode) == true
      if devMode then
        if silentCount == 0 then
          self.aboutSilent:SetText("No silent errors captured.\n\nNote: Silent-error tracing is active only while Developer Mode is enabled.")
        else
          self.aboutSilent:SetText("Silent errors captured: " .. tostring(silentCount) .. "\n\nNote: Silent-error tracing is active only while Developer Mode is enabled.")
        end
      else
        self.aboutSilent:SetText("Developer Mode is OFF.\nSilent-error tracing is currently disabled.")
      end
    end
  end

  editor.AcquirePooledButton = function(_, pool, index, creator)
    local button = pool[index]
    if not button then
      button = creator()
      pool[index] = button
    end
    return button
  end

  editor.PreparePooledListButton = function(_, button, text, y, onClick, opts)
    if not button then
      return nil
    end
    opts = opts or {}
    button:ClearAllPoints()
    button:SetPoint("TOPLEFT", opts.x or 0, y or 0)
    button:SetSize(opts.width or 200, opts.height or 20)
    button:SetText(text or "")
    button:SetScript("OnClick", onClick)
    button:Show()

    local fs = button:GetFontString()
    if fs then
      fs:SetTextColor(1, 1, 1, 1)
    end

    if button.__glow then button.__glow:Hide() end
    if button.__selectedBorder then button.__selectedBorder:Hide() end
    if button.__lockIcon then button.__lockIcon:Hide() end
    if button.__activeIcon then button.__activeIcon:Hide() end
    if button.__activeBorder then button.__activeBorder:Hide() end
    if button.__profileDragDropBorder then button.__profileDragDropBorder:Hide() end
    if button.__profileDragSourceBorder then button.__profileDragSourceBorder:Hide() end
    if button.__bgDragDropBorder then button.__bgDragDropBorder:Hide() end
    if button.__bgDragSourceBorder then button.__bgDragSourceBorder:Hide() end
    if button.__bgCategoryGroupDragDropBorder then button.__bgCategoryGroupDragDropBorder:Hide() end
    if button.__bgCategoryGroupDragSourceBorder then button.__bgCategoryGroupDragSourceBorder:Hide() end

    return button
  end

  editor.RestoreProfileCurrentLabel = function(self)
    if not self or not self.profileLabel then
      return
    end
    local root = RootDB()
    local enabledProfileName = type(GetEnabledLootProfileName) == "function" and tostring(GetEnabledLootProfileName() or "") or ""
    local profileName = enabledProfileName ~= "" and enabledProfileName or tostring(root.currentProfile or "Default")
    self.profileLabel:SetText("Current Profile: " .. DisplayProfileName(profileName))
  end

  editor.RestoreBackgroundsCurrentLabel = function(self)
    if not self or not self.backgroundsCurrentLabel then
      return
    end
    local curCat = GetSelectedBackgroundCategory() or "(none)"
    self.backgroundsCurrentLabel:SetText("Current Category: " .. curCat)
  end

  local RefreshPanelsSection
  local RefreshPanelPropertiesSection
  local RefreshBackgroundsSection
  local RefreshBackgroundListDetailsSection
  local RefreshProfilesSection
  local RefreshProfileDetailsSection

  local function RefreshPanelsListSection(self, db)
    local selectedPanelName = GetSelectedPanelName()
    local order = GetSortedPanelNames(db)
    local panelTotalPages = math.max(1, math.ceil(#order / LISTS_PER_PAGE))
    local selectedPanelPage = GetListPageForValue(order, selectedPanelName, LISTS_PER_PAGE)
    if selectedPanelName ~= self.__lastPagedSelectedPanelName and selectedPanelPage then
      self.panelListPage = selectedPanelPage
    end
    self.panelListPage = ClampListPage(self.panelListPage or 1, panelTotalPages)
    self.__lastPagedSelectedPanelName = selectedPanelName
    local panelStartIndex = ((self.panelListPage - 1) * LISTS_PER_PAGE) + 1
    local panelEndIndex = math.min(#order, panelStartIndex + LISTS_PER_PAGE - 1)

    self.listButtonPool = self.listButtonPool or {}
    self.listButtons = self.listButtons or {}
    for _, b in ipairs(self.listButtonPool) do b:Hide() end
    wipe(self.listButtons)

    local y = 0
    local usedButtons = 0
    for i = panelStartIndex, panelEndIndex do
      local name = order[i]
      usedButtons = usedButtons + 1
      local b = self:AcquirePooledButton(self.listButtonPool, usedButtons, function()
        return MakeListButton(self.listContent, name, y, function() SelectPanel(name) end)
      end)
      self:PreparePooledListButton(b, name, y, function() SelectPanel(name) end)
      local p = db.panels[name]
      if name == selectedPanelName then
        b:GetFontString():SetTextColor(0.6, 0.9, 1.0)
      end
      if b.__glow then b.__glow:SetShown(name == selectedPanelName) end
      if b.__selectedBorder then
        b.__selectedBorder:SetShown(name == selectedPanelName and GetPanelsUnlockedState() and p and not p.locked)
      end
      if b.__lockIcon then
        if p and p.locked then
          b.__lockIcon:SetTexture("Interface/Buttons/LockButton-Locked-Up")
          b.__lockIcon:SetVertexColor(1.0, 0.25, 0.25, 1)
        else
          b.__lockIcon:SetTexture("Interface/Buttons/LockButton-Unlocked-Up")
          b.__lockIcon:SetVertexColor(0.2, 1.0, 0.2, 1)
        end
        b.__lockIcon:Show()
      end
      self.listButtons[#self.listButtons + 1] = b
      y = y - 22
    end
    for i = usedButtons + 1, #self.listButtonPool do
      self.listButtonPool[i]:Hide()
    end
    self.listContent:SetHeight(math.max(1, -y))
    if self.listScroll and self.listScroll.UpdateScrollChildRect then
      self.listScroll:UpdateScrollChildRect()
    end
    if self.listScroll then self.listScroll:SetVerticalScroll(0) end
    UpdatePagerControls(self.panelPrevBtn, self.panelNextBtn, self.panelPageText, self.panelListPage, panelTotalPages)
    if self.delBtn then
      self.delBtn:SetEnabled(selectedPanelName ~= nil and selectedPanelName ~= "")
    end
  end

  local function RefreshPanelPropertiesState(self, root, db)
    local selectedPanelName = GetSelectedPanelName()
    if selectedPanelName and db.panels[selectedPanelName] then
      if self.propsScroll then self.propsScroll:Show() end
      if self.noPanelScroll then self.noPanelScroll:Hide() end
      if self.noPanelFrame then self.noPanelFrame:Hide() end
      local p = db.panels[selectedPanelName]
      p.color = p.color or { 0.05, 0.05, 0.07, 0.8 }
      self.selLabel:SetText("Selected: " .. selectedPanelName)

      self.wSlider:SetValueSilent(p.w or 300)
      self.hSlider:SetValueSilent(p.h or 120)

      local pos = db.positions[selectedPanelName]
      self.xSlider:SetValueSilent(pos and pos.x or 0)
      self.ySlider:SetValueSilent(pos and pos.y or 0)

      if self.borderDrop and self.borderOptions then
        local bval = p.border or "tooltip"
        local btext = bval
        for _, opt in ipairs(self.borderOptions) do
          if opt.value == bval then
            btext = opt.text
            break
          end
        end
        UIDropDownMenu_SetSelectedValue(self.borderDrop, bval)
        UIDropDownMenu_SetText(self.borderDrop, btext)
      end
      if self.lockCheck then
        self.lockCheck:SetChecked(p.locked and true or false)
      end
      do
        local showEditMode = not (p.locked and true or false)
        local editMode = ((root.ui and root.ui.panelEditMode) == "PREVIEW") and "PREVIEW" or "EDITOR"
        if self.editModeBox then self.editModeBox:SetShown(showEditMode) end
        if self.editModeLabel then self.editModeLabel:SetShown(showEditMode) end
        if self.editModeEditorCheck then
          self.editModeEditorCheck:SetShown(showEditMode)
          self.editModeEditorCheck:SetChecked(editMode == "EDITOR")
        end
        if self.editModePreviewCheck then
          self.editModePreviewCheck:SetShown(showEditMode)
          self.editModePreviewCheck:SetChecked(editMode == "PREVIEW")
        end
      end

      if p.gradient then
        EnsureGradientTables(p)
        self.alphaSlider:SetValue(p.gradient.c1[4] or 0.8)
      else
        self.alphaSlider:SetValue((p.color and p.color[4]) or 0.8)
      end
      if self.UpdateColorDesignUI then self:UpdateColorDesignUI() end
    else
      if self.propsScroll then self.propsScroll:Hide() end
      if self.noPanelScroll then self.noPanelScroll:Show() end
      if self.noPanelFrame then self.noPanelFrame:Show() end
      if self.LayoutNoPanel then self:LayoutNoPanel() end
      self.selLabel:SetText("Selected: (none)")
      if self.lockCheck then
        self.lockCheck:SetChecked(false)
      end
      if self.editModeBox then self.editModeBox:Hide() end
      if self.editModeLabel then self.editModeLabel:Hide() end
      if self.editModeEditorCheck then self.editModeEditorCheck:Hide() end
      if self.editModePreviewCheck then self.editModePreviewCheck:Hide() end
      if self.UpdateColorDesignUI then self:UpdateColorDesignUI() end
    end
  end

  RefreshPanelsSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      local db = DB()
      self.__refreshing = true
      RefreshPanelsListSection(self, db)
      RefreshPanelPropertiesState(self, root, db)
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Panels Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  editor.RefreshPanelsListSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local db = DB()
      self.__refreshing = true
      RefreshPanelsListSection(self, db)
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Panel List Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  RefreshPanelPropertiesSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      local db = DB()
      self.__refreshing = true
      RefreshPanelPropertiesState(self, root, db)
      self.__refreshing = false
    end, function(err)
      ReportEditorRuntimeError("Editor Panel Properties Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  local function RefreshBackgroundsSectionState(self)
    local selectedBackgroundCategory = GetSelectedBackgroundCategory()
    local selectedBackgroundName = GetSelectedBackgroundName()
    local selectedBackgroundCategoryGroup = GetSelectedBackgroundCategoryGroup()

    if self.backgroundsCurrentLabel then
      local curCat = selectedBackgroundCategory or "(none)"
      self.backgroundsCurrentLabel:SetText("Current Category: " .. curCat)
    end
    if selectedBackgroundCategory and not FindCategoryIndex(ListBackgroundCategories(), selectedBackgroundCategory) then
      selectedBackgroundCategory = nil
      selectedBackgroundName = nil
      SetSelectedBackgroundCategory(nil)
      SetSelectedBackgroundName(nil)
    end
    if selectedBackgroundCategoryGroup and not FindBackgroundCategoryGroupIndex(EnsureBackgroundCategoryGroups(), selectedBackgroundCategoryGroup) then
      selectedBackgroundCategoryGroup = nil
      SetSelectedBackgroundCategoryGroup(nil)
    end
    if (not self.__skipBackgroundCategoryListRebuild) and self.bgCatButtons then
      self.bgCatGroupButtonPool = self.bgCatGroupButtonPool or {}
      self.bgCatItemButtonPool = self.bgCatItemButtonPool or {}
      self.bgCatButtons = self.bgCatButtons or {}
      self.bgCatGroupButtons = self.bgCatGroupButtons or {}
      self.bgCatDropButtons = self.bgCatDropButtons or {}
      for _, b in ipairs(self.bgCatGroupButtonPool) do b:Hide() end
      for _, b in ipairs(self.bgCatItemButtonPool) do b:Hide() end
      wipe(self.bgCatButtons)
      wipe(self.bgCatGroupButtons)
      wipe(self.bgCatDropButtons)
      local catRows = BuildVisibleBackgroundCategoryRows(selectedBackgroundCategory)
      if not selectedBackgroundCategory and not selectedBackgroundCategoryGroup and catRows[1] then
        local firstGroupName = nil
        for _, row in ipairs(catRows) do
          if row and row.type == "category" then
            selectedBackgroundCategory = row.name
            SetSelectedBackgroundCategory(row.name)
            break
          elseif row and row.type == "group" and not firstGroupName then
            firstGroupName = row.name
          end
        end
        if not selectedBackgroundCategory and firstGroupName then
          selectedBackgroundCategoryGroup = firstGroupName
          SetSelectedBackgroundCategoryGroup(firstGroupName)
        end
      end
      local catFocusKey = GetBackgroundCategoryFocusKey(selectedBackgroundCategory, selectedBackgroundCategoryGroup)
      local bgCatTotalPages = math.max(1, math.ceil(#catRows / LISTS_PER_PAGE))
      local selectedCatPage = GetListPageForValue(catRows, catFocusKey, LISTS_PER_PAGE, function(row)
        return row and row.key
      end)
      if catFocusKey ~= self.__lastPagedBackgroundCategoryKey and selectedCatPage then
        self.bgCatPage = selectedCatPage
      end
      self.bgCatPage = ClampListPage(self.bgCatPage or 1, bgCatTotalPages)
      self.__lastPagedBackgroundCategoryKey = catFocusKey
      local bgCatStartIndex = ((self.bgCatPage - 1) * LISTS_PER_PAGE) + 1
      local bgCatEndIndex = math.min(#catRows, bgCatStartIndex + LISTS_PER_PAGE - 1)
      local yc = 0
      local usedGroupButtons = 0
      local usedItemButtons = 0
      for i = bgCatStartIndex, bgCatEndIndex do
        local row = catRows[i]
        if row and row.type == "group" then
          local label = string.format("%s (%d)", row.name or "Group", row.childCount or 0)
          usedGroupButtons = usedGroupButtons + 1
          local b = self:AcquirePooledButton(self.bgCatGroupButtonPool, usedGroupButtons, function()
            return MakeSimpleListButton(self.bgCatContent, label, yc, function()
              SetSelectedBackgroundCategoryGroup(row.name)
              SetSelectedBackgroundCategory(nil)
              SetSelectedBackgroundName(nil)
              RefreshBackgroundsSection(self)
            end)
          end)
          self:PreparePooledListButton(b, label, yc, function()
            SetSelectedBackgroundCategoryGroup(row.name)
            SetSelectedBackgroundCategory(nil)
            SetSelectedBackgroundName(nil)
            RefreshBackgroundsSection(self)
          end)
          b.__backgroundCategoryGroupName = row.name
          b.__bgCategoryGroupDragDropBorder = b.__bgCategoryGroupDragDropBorder or CreatePurpleOutline(b)
          b.__bgCategoryGroupDragDropBorder:Hide()
          b.__lid_customBg = {0.1804, 0.1216, 0.2863, 0.98}
          b.__lid_customHover = {0.72, 0.86, 1.00, 0.24}
          local isSelectedGroup = (selectedBackgroundCategoryGroup == row.name)
          local groupTextColor
          if isSelectedGroup or row.containsSelected then
            groupTextColor = {0.6, 0.9, 1.0, 1.0}
          else
            groupTextColor = {0.92, 0.82, 1.0, 1.0}
          end
          b.__lid_customText = groupTextColor
          b.__onToggleBackgroundCategoryGroup = function()
            ToggleBackgroundCategoryGroupCollapsed(row.name)
            SetSelectedBackgroundCategoryGroup(row.name)
            SetSelectedBackgroundCategory(nil)
            SetSelectedBackgroundName(nil)
            RefreshBackgroundsSection(self)
          end
          ConfigureBackgroundCategoryGroupButton(b, label, row.collapsed)
          if b.__bgCategoryGroupArrow then
            b.__bgCategoryGroupArrow:SetTextColor(groupTextColor[1], groupTextColor[2], groupTextColor[3], groupTextColor[4] or 1)
          end
          if b.__glow then b.__glow:SetShown(isSelectedGroup or (row.containsSelected and row.collapsed)) end
          self.bgCatButtons[#self.bgCatButtons + 1] = b
          self.bgCatGroupButtons[#self.bgCatGroupButtons + 1] = b
        elseif row and row.type == "category" then
          local name = row.name
          local label = row.groupName and ("  " .. name) or name
          usedItemButtons = usedItemButtons + 1
          local b = self:AcquirePooledButton(self.bgCatItemButtonPool, usedItemButtons, function()
            return MakeSimpleListButton(self.bgCatContent, label, yc, function()
              SetSelectedBackgroundCategory(name)
              SetSelectedBackgroundCategoryGroup(nil)
              SetSelectedBackgroundName(nil)
              RefreshBackgroundsSection(self)
            end)
          end)
          self:PreparePooledListButton(b, label, yc, function()
            SetSelectedBackgroundCategory(name)
            SetSelectedBackgroundCategoryGroup(nil)
            SetSelectedBackgroundName(nil)
            RefreshBackgroundsSection(self)
          end, {
            x = row.groupName and 16 or 0,
            width = row.groupName and 184 or 200,
          })
          b.__backgroundCategoryName = name
          b.__bgDragDropBorder = b.__bgDragDropBorder or CreatePurpleOutline(b)
          b.__bgDragDropBorder:Hide()
          b.__bgCategoryGroupDragSourceBorder = b.__bgCategoryGroupDragSourceBorder or CreatePurpleOutline(b)
          b.__bgCategoryGroupDragSourceBorder:Hide()
          b:RegisterForDrag("LeftButton")
          b:SetScript("OnDragStart", function(button)
            BeginBackgroundCategoryGroupDrag(name, row.groupName, button)
          end)

          if name == selectedBackgroundCategory then
            b:GetFontString():SetTextColor(0.6, 0.9, 1.0)
          end
          if b.__glow then b.__glow:SetShown(name == selectedBackgroundCategory) end
          self.bgCatButtons[#self.bgCatButtons + 1] = b
          self.bgCatDropButtons[#self.bgCatDropButtons + 1] = b
        end
        yc = yc - 22
      end
      for i = usedGroupButtons + 1, #self.bgCatGroupButtonPool do
        self.bgCatGroupButtonPool[i]:Hide()
      end
      for i = usedItemButtons + 1, #self.bgCatItemButtonPool do
        self.bgCatItemButtonPool[i]:Hide()
      end
      if self.bgCatContent then
        self.bgCatContent:SetHeight(math.max(1, -yc))
      end
      if self.bgCatScroll and self.bgCatScroll.UpdateScrollChildRect then
        self.bgCatScroll:UpdateScrollChildRect()
      end
      if self.bgCatScroll then self.bgCatScroll:SetVerticalScroll(0) end
      UpdatePagerControls(self.bgCatPrevBtn, self.bgCatNextBtn, self.bgCatPageText, self.bgCatPage, bgCatTotalPages)
      if self.bgDeleteCatBtn then
        self.bgDeleteCatBtn:SetEnabled(selectedBackgroundCategory ~= nil and selectedBackgroundCategory ~= "")
      end
      self.bgSelectedCategoryGroupName = selectedBackgroundCategoryGroup
    end

    if not self.__skipBackgroundListRebuild and self.bgListButtons then
      for _, b in ipairs(self.bgListButtons) do b:Hide() end
      wipe(self.bgListButtons)
      local list = ListBackgrounds and ListBackgrounds(selectedBackgroundCategory) or {}
      local sortedList = GetSortedBackgroundNames(list)
      local bgListTotalPages = math.max(1, math.ceil(#sortedList / LISTS_PER_PAGE))
      local selectedBgPage = GetListPageForValue(sortedList, selectedBackgroundName, LISTS_PER_PAGE)
      if selectedBackgroundName ~= self.__lastPagedBackgroundName and selectedBgPage then
        self.bgListPage = selectedBgPage
      end
      self.bgListPage = ClampListPage(self.bgListPage or 1, bgListTotalPages)
      self.__lastPagedBackgroundName = selectedBackgroundName
      local bgListStartIndex = ((self.bgListPage - 1) * LISTS_PER_PAGE) + 1
      local bgListEndIndex = math.min(#sortedList, bgListStartIndex + LISTS_PER_PAGE - 1)
      local yb = 0
      for i = bgListStartIndex, bgListEndIndex do
        local name = sortedList[i]
        local b = MakeSimpleListButton(self.bgListContent, name, yb, function() SelectBackground(name) end)
        b.__backgroundItemName = name
        b.__bgDragSourceBorder = b.__bgDragSourceBorder or CreatePurpleOutline(b)
        b.__bgDragSourceBorder:Hide()
        b:RegisterForDrag("LeftButton")
        b:SetScript("OnDragStart", function(button)
          BeginBackgroundCategoryDrag(name, selectedBackgroundCategory, button)
        end)
        if name == selectedBackgroundName then
          b:GetFontString():SetTextColor(0.6, 0.9, 1.0)
        end
        if b.__glow then b.__glow:SetShown(name == selectedBackgroundName) end
        self.bgListButtons[#self.bgListButtons + 1] = b
        yb = yb - 22
      end
      if self.bgListContent then
        self.bgListContent:SetHeight(math.max(1, -yb))
      end
      if self.bgListScroll and self.bgListScroll.UpdateScrollChildRect then
        self.bgListScroll:UpdateScrollChildRect()
      end
      if self.bgListScroll then self.bgListScroll:SetVerticalScroll(0) end
      UpdatePagerControls(self.bgPrevBtn, self.bgNextBtn, self.bgPageText, self.bgListPage, bgListTotalPages)
      if self.bgDeleteListBtn then
        self.bgDeleteListBtn:SetEnabled(selectedBackgroundName ~= nil and selectedBackgroundName ~= "")
      end
    end

    if self.__skipBackgroundDetailsRebuild then
      return
    end

    if self.bgSelLabel then
      if selectedBackgroundName then
        self.bgSelLabel:SetText("Selected: " .. selectedBackgroundName)
        if self.bgSourceText then
          self.bgSourceText:SetText("Source:\nAddOns/LidCouncil_UserMedia/Your_Backgrounds/" .. selectedBackgroundName .. ".tga")
          self.bgSourceText:Show()
        end
        if self.bgPreviewTex then
          local path = (GetBackgroundPath and GetBackgroundPath(selectedBackgroundName))
            or ("Interface\\AddOns\\LidCouncil_UserMedia\\Your_Backgrounds\\" .. selectedBackgroundName .. ".tga")
          local hasTex = true
          if C_Texture and C_Texture.GetFileIDFromPath then
            hasTex = (C_Texture.GetFileIDFromPath(path) ~= nil)
          end
          if hasTex then
            self.bgPreviewTex:SetTexture(path)
            self.bgPreviewTex.__path = path
          else
            self.bgPreviewTex:SetTexture(nil)
            self.bgPreviewTex.__path = nil
          end
        end
        if self.bgSourceText then self.bgSourceText:Show() end
        if self.bgReloadNote then self.bgReloadNote:Show() end
        if self.bgPreviewFrame then self.bgPreviewFrame:Show() end
        if self.bgEmptyText then self.bgEmptyText:Hide() end
        if self.bgRenameBtn then self.bgRenameBtn:Show(); self.bgRenameBtn:Enable() end
        if self.bgDeleteBtn then self.bgDeleteBtn:Show(); self.bgDeleteBtn:Enable() end
        if self.bgRenameCatBtn then self.bgRenameCatBtn:Hide(); self.bgRenameCatBtn:Disable() end
        if self.bgDeleteCatPropsBtn then self.bgDeleteCatPropsBtn:Hide(); self.bgDeleteCatPropsBtn:Disable() end
        if self.bgRenameCatGroupBtn then self.bgRenameCatGroupBtn:Hide(); self.bgRenameCatGroupBtn:Disable() end
        if self.bgDeleteCatGroupPropsBtn then self.bgDeleteCatGroupPropsBtn:Hide(); self.bgDeleteCatGroupPropsBtn:Disable() end
        if self.UpdateBgPreviewLayout then self:UpdateBgPreviewLayout() end
        if self.UpdateBgPropsLayout then self:UpdateBgPropsLayout() end
      elseif selectedBackgroundCategoryGroup then
        self.bgSelLabel:SetText("Selected Group: " .. selectedBackgroundCategoryGroup)
        if self.bgSourceText then self.bgSourceText:SetText("Source:\nAddOns/LidCouncil_UserMedia/Your_Backgrounds/"); self.bgSourceText:Hide() end
        if self.bgReloadNote then self.bgReloadNote:Hide() end
        if self.bgPreviewTex then self.bgPreviewTex:SetTexture(nil) end
        if self.bgPreviewTex then self.bgPreviewTex.__path = nil end
        if self.bgPreviewFrame then self.bgPreviewFrame:Hide() end
        if self.bgEmptyText then
          self.bgEmptyText:SetText("Open the group or drag categories into it.\nDeleting the group keeps all categories and makes them groupless.")
          self.bgEmptyText:Show()
        end
        if self.bgRenameBtn then self.bgRenameBtn:Hide(); self.bgRenameBtn:Disable() end
        if self.bgDeleteBtn then self.bgDeleteBtn:Hide(); self.bgDeleteBtn:Disable() end
        if self.bgRenameCatBtn then self.bgRenameCatBtn:Hide(); self.bgRenameCatBtn:Disable() end
        if self.bgDeleteCatPropsBtn then self.bgDeleteCatPropsBtn:Hide(); self.bgDeleteCatPropsBtn:Disable() end
        if self.bgRenameCatGroupBtn then self.bgRenameCatGroupBtn:Show(); self.bgRenameCatGroupBtn:Enable() end
        if self.bgDeleteCatGroupPropsBtn then self.bgDeleteCatGroupPropsBtn:Show(); self.bgDeleteCatGroupPropsBtn:Enable() end
        if self.UpdateBgPropsLayout then self:UpdateBgPropsLayout() end
      elseif selectedBackgroundCategory then
        self.bgSelLabel:SetText("Selected Category: " .. selectedBackgroundCategory)
        if self.bgSourceText then self.bgSourceText:SetText("Source:\nAddOns/LidCouncil_UserMedia/Your_Backgrounds/"); self.bgSourceText:Hide() end
        if self.bgReloadNote then self.bgReloadNote:Hide() end
        if self.bgPreviewTex then self.bgPreviewTex:SetTexture(nil) end
        if self.bgPreviewTex then self.bgPreviewTex.__path = nil end
        if self.bgPreviewFrame then self.bgPreviewFrame:Hide() end
        if self.bgEmptyText then
          self.bgEmptyText:SetText("Add or select a background.")
          self.bgEmptyText:Show()
        end
        if self.bgRenameBtn then self.bgRenameBtn:Hide(); self.bgRenameBtn:Disable() end
        if self.bgDeleteBtn then self.bgDeleteBtn:Hide(); self.bgDeleteBtn:Disable() end
        if self.bgRenameCatBtn then self.bgRenameCatBtn:Show(); self.bgRenameCatBtn:Enable() end
        if self.bgDeleteCatPropsBtn then self.bgDeleteCatPropsBtn:Show(); self.bgDeleteCatPropsBtn:Enable() end
        if self.bgRenameCatGroupBtn then self.bgRenameCatGroupBtn:Hide(); self.bgRenameCatGroupBtn:Disable() end
        if self.bgDeleteCatGroupPropsBtn then self.bgDeleteCatGroupPropsBtn:Hide(); self.bgDeleteCatGroupPropsBtn:Disable() end
        if self.UpdateBgPropsLayout then self:UpdateBgPropsLayout() end
      else
        self.bgSelLabel:SetText("Selected: (none)")
        if self.bgSourceText then self.bgSourceText:SetText("Source:\nAddOns/LidCouncil_UserMedia/Your_Backgrounds/"); self.bgSourceText:Hide() end
        if self.bgReloadNote then self.bgReloadNote:Hide() end
        if self.bgPreviewTex then self.bgPreviewTex:SetTexture(nil) end
        if self.bgPreviewTex then self.bgPreviewTex.__path = nil end
        if self.bgPreviewFrame then self.bgPreviewFrame:Hide() end
        if self.bgEmptyText then
          self.bgEmptyText:SetText("Select or create a category first.")
          self.bgEmptyText:Show()
        end
        if self.bgRenameBtn then self.bgRenameBtn:Hide(); self.bgRenameBtn:Disable() end
        if self.bgDeleteBtn then self.bgDeleteBtn:Hide(); self.bgDeleteBtn:Disable() end
        if self.bgRenameCatBtn then self.bgRenameCatBtn:Hide(); self.bgRenameCatBtn:Disable() end
        if self.bgDeleteCatPropsBtn then self.bgDeleteCatPropsBtn:Hide(); self.bgDeleteCatPropsBtn:Disable() end
        if self.bgRenameCatGroupBtn then self.bgRenameCatGroupBtn:Hide(); self.bgRenameCatGroupBtn:Disable() end
        if self.bgDeleteCatGroupPropsBtn then self.bgDeleteCatGroupPropsBtn:Hide(); self.bgDeleteCatGroupPropsBtn:Disable() end
        if self.UpdateBgPropsLayout then self:UpdateBgPropsLayout() end
      end
    end
  end

  RefreshBackgroundsSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      self.__refreshing = true
      RefreshBackgroundsSectionState(self)
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Backgrounds Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  RefreshBackgroundListDetailsSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      self.__refreshing = true
      self.__skipBackgroundCategoryListRebuild = true
      RefreshBackgroundsSectionState(self)
      self.__skipBackgroundCategoryListRebuild = nil
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Background List/Details Refresh", err)
    end)
    if not ok then
      self.__skipBackgroundCategoryListRebuild = nil
      self.__refreshing = false
    end
  end

  editor.RefreshBackgroundCategoryListSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      self.__refreshing = true
      self.__skipBackgroundListRebuild = true
      self.__skipBackgroundDetailsRebuild = true
      RefreshBackgroundsSectionState(self)
      self.__skipBackgroundListRebuild = nil
      self.__skipBackgroundDetailsRebuild = nil
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Background Category List Refresh", err)
    end)
    if not ok then
      self.__skipBackgroundListRebuild = nil
      self.__skipBackgroundDetailsRebuild = nil
      self.__refreshing = false
    end
  end

  editor.RefreshBackgroundListSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      self.__refreshing = true
      self.__skipBackgroundCategoryListRebuild = true
      self.__skipBackgroundDetailsRebuild = true
      RefreshBackgroundsSectionState(self)
      self.__skipBackgroundCategoryListRebuild = nil
      self.__skipBackgroundDetailsRebuild = nil
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Background List Refresh", err)
    end)
    if not ok then
      self.__skipBackgroundCategoryListRebuild = nil
      self.__skipBackgroundDetailsRebuild = nil
      self.__refreshing = false
    end
  end

  local function RefreshProfileLabelsState(self, root)
    local enabledProfileName = type(GetEnabledLootProfileName) == "function" and tostring(GetEnabledLootProfileName() or "") or ""
    local currentProfileName = enabledProfileName ~= "" and enabledProfileName or tostring(root.currentProfile or "Default")
    local hasActiveProfile = currentProfileName ~= "" and currentProfileName ~= "Default"
    local curProfLabel = hasActiveProfile and DisplayProfileName(currentProfileName) or "No profile activated :("
    local profileText = "Current Profile: " .. curProfLabel
    local inactiveColor = { 1.00, 0.35, 0.25, 1.00 }
    local function SetCurrentLabel(fontString, useInactiveState)
      if not fontString then
        return
      end
      fontString:SetText(profileText)
      fontString.__lid_customTextColor = useInactiveState and inactiveColor or nil
      if fontString.SetTextColor then
        if useInactiveState then
          fontString:SetTextColor(inactiveColor[1], inactiveColor[2], inactiveColor[3], inactiveColor[4])
        else
          fontString:SetTextColor(0.92, 0.96, 1.00, 1.00)
        end
      end
    end

    if self.profileBarText then
      SetCurrentLabel(self.profileBarText, not hasActiveProfile)
    end
    if self.profileLabel then
      SetCurrentLabel(self.profileLabel, not hasActiveProfile)
    end
    if self.panelsCurrentLabel then
      SetCurrentLabel(self.panelsCurrentLabel, not hasActiveProfile)
    end
    if self.uiCurrentLabel then
      SetCurrentLabel(self.uiCurrentLabel, false)
    end
    if self.liveBoardCurrentLabel then
      SetCurrentLabel(self.liveBoardCurrentLabel, not hasActiveProfile)
    end
    if self.tutorialCurrentLabel then
      SetCurrentLabel(self.tutorialCurrentLabel, false)
    end
    if self.aboutCurrentLabel then
      SetCurrentLabel(self.aboutCurrentLabel, false)
    end
  end

  local function RefreshProfilesSectionState(self, root)
    if self.selectedProfileName == "Default" then
      self.selectedProfileName = nil
    end
    if not self.selectedProfileName and not self.selectedProfileGroupName and root.currentProfile and root.currentProfile ~= "Default" then
      self.selectedProfileName = root.currentProfile
    end
    if self.selectedProfileGroupName and not FindProfileGroupIndex(EnsureProfileGroups(), self.selectedProfileGroupName) then
      self.selectedProfileGroupName = nil
    end

    if not self.profContent or not self.profScroll then
      if type(self.profGroupButtonPool) == "table" then
        for _, button in ipairs(self.profGroupButtonPool) do
          if button and button.Hide then button:Hide() end
        end
      end
      if type(self.profItemButtonPool) == "table" then
        for _, button in ipairs(self.profItemButtonPool) do
          if button and button.Hide then button:Hide() end
        end
      end
      if type(self.profButtons) == "table" then wipe(self.profButtons) end
      if type(self.profGroupButtons) == "table" then wipe(self.profGroupButtons) end
      return
    end

    if not self.__skipProfileListRebuild then
      self.profGroupButtonPool = self.profGroupButtonPool or {}
      self.profItemButtonPool = self.profItemButtonPool or {}
      self.profButtons = self.profButtons or {}
      self.profGroupButtons = self.profGroupButtons or {}
      for _, b in ipairs(self.profGroupButtonPool) do b:Hide() end
      for _, b in ipairs(self.profItemButtonPool) do b:Hide() end
      wipe(self.profButtons)
      wipe(self.profGroupButtons)

      local profilePageFocus = GetProfileFocusKey(self.selectedProfileName, self.selectedProfileGroupName)
      if not profilePageFocus and root.currentProfile and root.currentProfile ~= "Default" then
        profilePageFocus = GetProfileFocusKey(root.currentProfile)
      end
      local profileRows = BuildVisibleProfileRows(root, self.selectedProfileName)
      local selectedProfilePage = GetListPageForValue(profileRows, profilePageFocus, LISTS_PER_PAGE, function(row)
        return row and row.key
      end)
      local profTotalPages = math.max(1, math.ceil(#profileRows / LISTS_PER_PAGE))
      if profilePageFocus ~= self.__lastPagedSelectedProfileKey and selectedProfilePage then
        self.profListPage = selectedProfilePage
      end
      self.profListPage = ClampListPage(self.profListPage or 1, profTotalPages)
      self.__lastPagedSelectedProfileKey = profilePageFocus
      local profStartIndex = ((self.profListPage - 1) * LISTS_PER_PAGE) + 1
      local profEndIndex = math.min(#profileRows, profStartIndex + LISTS_PER_PAGE - 1)
      local py = 0
      local usedProfileGroupButtons = 0
      local usedProfileButtons = 0
      for i = profStartIndex, profEndIndex do
        local row = profileRows[i]
        if row and row.type == "group" then
          local label = string.format("%s (%d)", row.name or "Group", row.childCount or 0)
          usedProfileGroupButtons = usedProfileGroupButtons + 1
          local b = self:AcquirePooledButton(self.profGroupButtonPool, usedProfileGroupButtons, function()
            return MakeSimpleListButton(self.profContent, label, py, function()
              self.selectedProfileGroupName = row.name
              self.selectedProfileName = nil
              RefreshProfilesSection(self)
            end)
          end)
          self:PreparePooledListButton(b, label, py, function()
            self.selectedProfileGroupName = row.name
            self.selectedProfileName = nil
            RefreshProfilesSection(self)
          end)
          b.__profileGroupName = row.name
          b.__profileDragDropBorder = b.__profileDragDropBorder or CreatePurpleOutline(b)
          b.__profileDragDropBorder:Hide()
          b.__lid_customBg = {0.1804, 0.1216, 0.2863, 0.98}
          b.__lid_customHover = {0.72, 0.86, 1.00, 0.24}
          local isSelectedGroup = (self.selectedProfileGroupName == row.name)
          local groupTextColor
          if isSelectedGroup then
            groupTextColor = {0.6, 0.9, 1.0, 1.0}
          elseif row.containsCurrent then
            groupTextColor = {0.7, 1.0, 0.7, 1.0}
          elseif row.containsSelected then
            groupTextColor = {0.6, 0.9, 1.0, 1.0}
          else
            groupTextColor = {0.92, 0.82, 1.0, 1.0}
          end
          b.__lid_customText = groupTextColor
          b.__onToggleProfileGroup = function()
            ToggleProfileGroupCollapsed(row.name)
            self.selectedProfileGroupName = row.name
            self.selectedProfileName = nil
            RefreshProfilesSection(self)
          end
          ConfigureProfileGroupButton(b, label, row.collapsed)
          if b.__groupArrow then
            b.__groupArrow:SetTextColor(groupTextColor[1], groupTextColor[2], groupTextColor[3], groupTextColor[4] or 1)
          end
          if b.__glow then b.__glow:SetShown(isSelectedGroup or (row.containsSelected and row.collapsed)) end
          self.profButtons[#self.profButtons + 1] = b
          self.profGroupButtons[#self.profGroupButtons + 1] = b
        elseif row and row.type == "profile" then
          local pname = row.name
          local label = row.groupName and ("  " .. pname) or pname
          usedProfileButtons = usedProfileButtons + 1
          local b = self:AcquirePooledButton(self.profItemButtonPool, usedProfileButtons, function()
            return MakeProfileButton(self.profContent, label, py, function()
              self.selectedProfileName = pname
              self.selectedProfileGroupName = nil
              RefreshProfilesSection(self)
            end)
          end)
          self:PreparePooledListButton(b, label, py, function()
            self.selectedProfileName = pname
            self.selectedProfileGroupName = nil
            RefreshProfilesSection(self)
          end, {
            x = row.groupName and 16 or 0,
            width = row.groupName and 184 or 200,
          })
          b.__profileDragSourceBorder = b.__profileDragSourceBorder or CreatePurpleOutline(b)
          b.__profileDragSourceBorder:Hide()
          b:RegisterForDrag("LeftButton")
          b:SetScript("OnDragStart", function(button)
            BeginProfileGroupDrag(pname, row.groupName, button)
          end)

          if pname == root.currentProfile then
            b:GetFontString():SetTextColor(0.7, 1.0, 0.7)
          elseif pname == self.selectedProfileName then
            b:GetFontString():SetTextColor(0.6, 0.9, 1.0)
          end
          if b.__glow then b.__glow:SetShown(pname == self.selectedProfileName) end
          if b.__activeIcon then b.__activeIcon:SetShown(pname == root.currentProfile) end
          if b.__activeBorder then b.__activeBorder:SetShown(pname == root.currentProfile) end
          self.profButtons[#self.profButtons + 1] = b
        end
        py = py - 22
      end
      for i = usedProfileGroupButtons + 1, #self.profGroupButtonPool do
        self.profGroupButtonPool[i]:Hide()
      end
      for i = usedProfileButtons + 1, #self.profItemButtonPool do
        self.profItemButtonPool[i]:Hide()
      end
      self.profContent:SetHeight(math.max(1, -py))
      if self.profScroll and self.profScroll.UpdateScrollChildRect then
        self.profScroll:UpdateScrollChildRect()
      end
      if self.profScroll then self.profScroll:SetVerticalScroll(0) end
      UpdatePagerControls(self.profPrevBtn, self.profNextBtn, self.profPageText, self.profListPage, profTotalPages)
    end

    if self.__skipProfileDetailsRebuild then
      return
    end

    self.selProfLabel:SetText("Selected: " .. (self.selectedProfileName or "(none)"))
    if self.selProfGroupLabel then
      self.selProfGroupLabel:SetText("Selected Group: " .. (self.selectedProfileGroupName or "(none)"))
    end
    if self.activateBtn then
      self.activateBtn:SetEnabled(self.selectedProfileName ~= nil and self.selectedProfileName ~= "")
    end
    if self.deactivateBtn then
      self.deactivateBtn:SetEnabled(self.selectedProfileName ~= nil and self.selectedProfileName == root.currentProfile and root.currentProfile ~= "Default")
    end
    if self.renameProfGroupBtn then
      self.renameProfGroupBtn:SetEnabled(self.selectedProfileGroupName ~= nil and self.selectedProfileGroupName ~= "")
    end
    if self.delProfGroupBtn then
      self.delProfGroupBtn:SetEnabled(self.selectedProfileGroupName ~= nil and self.selectedProfileGroupName ~= "")
    end
    if self.profGroupInfoLabel then
      local groupInfoText = "Deleting a group will only ungroup its profiles."
      if self.selectedProfileGroupName then
        local groups = EnsureProfileGroups()
        local idx = FindProfileGroupIndex(groups, self.selectedProfileGroupName)
        local childCount = (idx and groups[idx] and #(groups[idx].profiles or {})) or 0
        groupInfoText = string.format("Profiles in group: %d\nDeleting this group will keep all profiles and make them groupless.", childCount)
      end
      self.profGroupInfoLabel:SetText(groupInfoText)
    end

    if self.selectedProfileGroupName then
      if self.profRightScroll then self.profRightScroll:Hide() end
      if self.profGroupScroll then self.profGroupScroll:Show() end
      if self.profWelcomeScroll then self.profWelcomeScroll:Hide() end
      if self.profWelcomeFrame then self.profWelcomeFrame:Hide() end
    elseif self.selectedProfileName and root.profiles[self.selectedProfileName] then
      if self.profRightScroll then self.profRightScroll:Show() end
      if self.profGroupScroll then self.profGroupScroll:Hide() end
      if self.profWelcomeScroll then self.profWelcomeScroll:Hide() end
      if self.profWelcomeFrame then self.profWelcomeFrame:Hide() end
    else
      if self.profRightScroll then self.profRightScroll:Hide() end
      if self.profGroupScroll then self.profGroupScroll:Hide() end
      if self.profWelcomeScroll then self.profWelcomeScroll:Show() end
      if self.profWelcomeFrame then self.profWelcomeFrame:Show() end
      if self.LayoutProfileWelcome then self:LayoutProfileWelcome() end
    end

    if self.specAutoCheck then
      local prof = self.selectedProfileName and root.profiles[self.selectedProfileName]
      local ps = prof and prof.profileSpec
      local autoMode = (ps and ps.mode == "CHARACTER") and "CHARACTER" or "SPEC"
      local autoModeText = (autoMode == "CHARACTER") and "Change by Character" or "Change by Specialization"
      if ps and ps.enabled == nil then
        ps.enabled = false
      end
      if ps and ps.mode ~= "CHARACTER" then
        ps.mode = "SPEC"
      end
      self.specAutoCheck:SetChecked(ps and ps.enabled)
      local specAutoText = _G[self.specAutoCheck:GetName() .. "Text"]
      if specAutoText then
        specAutoText:SetText("Activate automatic profile change")
      end
      if self.profileModeDrop then
        SetDropdownSelection(self.profileModeDrop, autoMode, autoModeText)
      end
      if self.specDesc then
        if autoMode == "CHARACTER" then
          self.specDesc:SetText("If this option is activated, this profile will automatically activate when you log onto the selected character. The specialization setting is ignored in this mode.")
        else
          self.specDesc:SetText("If this option is activated, this profile will automatically activate when you change to the selected specialization. You can optionally limit this behavior to a specific character.")
        end
      end
      if self.charLabel then
        if autoMode == "CHARACTER" then
          self.charLabel:SetText("Choose Character")
        else
          self.charLabel:SetText("Optional Character Filter")
        end
      end

      local specID = ps and ps.specID
      local specText = "Unbound"
      if specID then
        if type(GetSpecializationInfoByID) == "function" then
          local _, name, _, _, role, class = GetSpecializationInfoByID(specID)
          if name then
            specText = class and (class .. "_" .. name) or name
            if role then specText = specText .. " (" .. role .. ")" end
          else
            specText = tostring(specID)
          end
        else
          specText = "SpecID: " .. tostring(specID)
        end
      end
      SetDropdownSelection(self.specDrop, specID or "NONE", specText)
      if self.specLabel then
        self.specLabel:SetShown(autoMode == "SPEC")
      end
      if self.specDrop then
        if autoMode == "SPEC" then
          self.specDrop:Show()
        else
          if self.specDrop.CloseMenu then
            self.specDrop:CloseMenu()
          end
          self.specDrop:Hide()
        end
      end

      if self.charDrop then
        local charVal = ps and ps.character
        local charText = charVal or ((autoMode == "CHARACTER") and "Choose character" or "Any character")
        local charValue = charVal
        if charValue == nil and autoMode ~= "CHARACTER" then
          charValue = "ANY"
        end
        SetDropdownSelection(self.charDrop, charValue, charText)
      end
    end
  end

  RefreshProfilesSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      self.__refreshing = true
      RefreshProfileLabelsState(self, root)
      RefreshProfilesSectionState(self, root)
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Profiles Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  RefreshProfileDetailsSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      self.__refreshing = true
      self.__skipProfileListRebuild = true
      RefreshProfileLabelsState(self, root)
      RefreshProfilesSectionState(self, root)
      self.__skipProfileListRebuild = nil
      self.__refreshing = false
    end, function(err)
      ReportEditorRuntimeError("Editor Profile Details Refresh", err)
    end)
    if not ok then
      self.__skipProfileListRebuild = nil
      self.__refreshing = false
    end
  end

  editor.RefreshProfilesListSection = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      self.__refreshing = true
      self.__skipProfileDetailsRebuild = true
      RefreshProfilesSectionState(self, root)
      self.__skipProfileDetailsRebuild = nil
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
    end, function(err)
      ReportEditorRuntimeError("Editor Profile List Refresh", err)
    end)
    if not ok then
      self.__skipProfileDetailsRebuild = nil
      self.__refreshing = false
    end
  end

  editor.RefreshCurrentProfileSections = function(self)
    if not self or self.__refreshing then return end
    local ok = xpcall(function()
      local root = RootDB()
      self.__refreshing = true
      RefreshProfileLabelsState(self, root)
      if self.RefreshLootProfilePage then self:RefreshLootProfilePage() end
      if self.RefreshLootSessionPage then self:RefreshLootSessionPage() end
      if self.RefreshLootLiveBoardPage then self:RefreshLootLiveBoardPage() end
      if self.RefreshLootListPage then self:RefreshLootListPage() end
      self.__refreshing = false
      if self.ApplyTheme then self:ApplyTheme() end
      if self.RefreshAbout then self:RefreshAbout() end
    end, function(err)
      ReportEditorRuntimeError("Editor Current Profile Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  editor.RefreshLootWorkflowSections = function(self, opts)
    if not self or self.__refreshing then
      return
    end
    opts = type(opts) == "table" and opts or {}
    local ok = xpcall(function()
      local root = RootDB()
      local currentPage = tostring(self.currentPage or "Profiles")
      local refreshAllLoot = opts.refreshAllLoot == true
      local refreshPages = type(opts.refreshPages) == "table" and opts.refreshPages or nil
      local refreshAbout = opts.refreshAbout == true or currentPage == "About" or (refreshPages and refreshPages.About == true)
      local refreshedLootPage = false

      local function ShouldRefreshPage(pageName)
        if refreshAllLoot then
          return true
        end
        if refreshPages then
          return refreshPages[pageName] == true
        end
        return currentPage == pageName
      end

      self.__refreshing = true
      RefreshProfileLabelsState(self, root)

      if ShouldRefreshPage("Profiles") then
        if self.RefreshLootProfilePage then self:RefreshLootProfilePage() end
        refreshedLootPage = true
      end
      if ShouldRefreshPage("Panels") then
        if self.RefreshLootSessionPage then self:RefreshLootSessionPage() end
        refreshedLootPage = true
      end
      if ShouldRefreshPage("LiveBoard") then
        if self.RefreshLootLiveBoardPage then self:RefreshLootLiveBoardPage() end
        refreshedLootPage = true
      end
      if ShouldRefreshPage("Backgrounds") then
        if self.RefreshLootListPage then self:RefreshLootListPage() end
        refreshedLootPage = true
      end

      self.__refreshing = false
      if self.ApplyTheme and refreshedLootPage then
        self:ApplyTheme()
      end
      if refreshAbout and self.RefreshAbout then
        self:RefreshAbout()
      end
    end, function(err)
      ReportEditorRuntimeError("Editor Loot Workflow Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end

  editor.InvalidateSortedNameCaches = function()
    InvalidateSortedProfileNames()
    InvalidateSortedPanelNames()
  end

  editor.RefreshPanelsSection = RefreshPanelsSection
  editor.RefreshPanelPropertiesSection = RefreshPanelPropertiesSection
  editor.RefreshBackgroundsSection = RefreshBackgroundsSection
  editor.RefreshBackgroundListDetailsSection = RefreshBackgroundListDetailsSection
  editor.RefreshProfilesSection = RefreshProfilesSection
  editor.RefreshProfileDetailsSection = RefreshProfileDetailsSection

  function editor:Refresh()
    local ok = xpcall(function()
      local root = RootDB()

      self.__refreshing = true
      self.title:SetText("LidCouncil Version " .. ADDON_VERSION)
      if self.versionText then
        self.versionText:SetText("v" .. WOW_CLIENT_VERSION)
      end
      RefreshProfileLabelsState(self, root)

      if self.minimapSizeSlider then
        local size = (root.ui.minimap and root.ui.minimap.size) or 28
        self.minimapSizeSlider:SetValueSilent(size)
      end
      if self.minimapAlphaSlider then
        local alpha = (root.ui.minimap and root.ui.minimap.alpha) or 1
        self.minimapAlphaSlider:SetValueSilent(alpha * 100)
      end
      if self.minimapHoverCheck then
        local hov = (root.ui.minimap and root.ui.minimap.onlyOnHover) and true or false
        self.minimapHoverCheck:SetChecked(hov)
      end

      if self.RefreshLootProfilePage then self:RefreshLootProfilePage() end
      if self.RefreshLootSessionPage then self:RefreshLootSessionPage() end
      if self.RefreshLootLiveBoardPage then self:RefreshLootLiveBoardPage() end
      if self.RefreshLootListPage then self:RefreshLootListPage() end
      if self.UpdateUILayout then self:UpdateUILayout() end

      self.__refreshing = false
      self:ApplyTheme()
      if self.RefreshAbout then self:RefreshAbout() end
      self.__applyingTheme = false
    end, function(err)
      ReportEditorRuntimeError("Editor Refresh", err)
    end)
    if not ok then
      self.__refreshing = false
    end
  end
end
